In the world of social deduction games, the most intriguing element is the human interaction—the deceit, the suspicion, and the collective decision-making. But what if we could simulate this with AI?
Today, I'm excited to share Social Deduction Island, a 2D web-based simulation game where autonomous agents, powered by the Gemini API, engage in a high-stakes environment of survival and deceit.
The Technical Stack
To bring this simulation to life, we combined several powerful technologies:
- Frontend: React for the UI and Phaser.js for the 2D game engine.
- Backend: Node.js with Express and Socket.io for real-time state management.
- AI Engine: Google's Gemini 3.1 Flash model for agent decision-making.
- Styling: Tailwind CSS and Motion for a sleek, modern interface.
Architecture: Client-Side AI vs. Server-Side State
One of the most critical design decisions was where to run the AI logic. While the server manages the game state (timer, resource positions, agent coordinates), the AI decision-making happens entirely on the client side.
Why Client-Side AI?
-
Security: By running the Gemini API calls on the frontend, we can leverage the platform's secure environment variable injection (
process.env.GEMINI_API_KEY) without exposing sensitive keys on the backend. - Scalability: Offloading the intensive LLM processing to the client reduces server load, allowing for a more responsive simulation.
- Real-time Interaction: The client-side AI can directly interact with the Phaser engine to visualize "thought bubbles" and movement plans.
The AI Decision Loop
Each agent's behavior is governed by a periodic AI update loop. To avoid rate limits and optimize performance, we implemented batched requests.
// AI Update Loop on Client - Batched to avoid rate limits
const aiInterval = setInterval(async () => {
const currentGameState = gameStateRef.current;
if (currentGameState?.phase === "DAY") {
const activeAgents = currentGameState.agents.filter((a: any) => !a.isThinking && !a.isBanished);
if (activeAgents.length === 0) return;
// Gather data for all active agents
const agentsData = activeAgents.map((agent: any) => ({
id: agent.id,
name: agent.name,
role: agent.role,
memory: agent.memory.slice(-5),
surroundings: getVisibleSurroundings(agent, currentGameState)
}));
// Send a single prompt to Gemini for all agents
const prompt = `You are the controller for multiple AI agents...`;
const result = await ai.models.generateContent({
model: "gemini-3-flash-preview",
contents: prompt,
config: { responseMimeType: "application/json" },
});
// Process responses and update each agent
const responses = JSON.parse(result.text);
responses.forEach(response => {
socket.emit("agent_ai_update", response);
});
}
}, 15000);
Vision Cones & Field of View
To make the simulation more realistic, we implemented Vision Cones. Agents don't have "god-like" awareness; they only "see" and remember what's within their 150px range and ~85-degree field of view.
This was achieved by calculating the distance and angle between an agent and its potential targets (other agents or resources) and filtering the "surroundings" data sent to the AI.
The Bonfire Meeting: AI-Driven Debate
During the NIGHT phase, agents gather at the bonfire to discuss their suspicions. This is where the social deduction happens. We use a single batched prompt to generate speeches and votes for all agents, ensuring the conversation flows logically based on their individual roles and memories.
Sabotage Confirmation UI
As the observer, you're not just a spectator. We implemented a Sabotage Confirmation UI that intercepts an Impostor's decision to sabotage. This allows you to see their "inner monologue" and decide whether to let the action proceed.
Social Deduction Island is more than just a game; it's a playground for exploring multi-agent systems and LLM-driven simulations. By combining Phaser.js for visuals, Socket.io for real-time sync, and Gemini for intelligence, we've created a living, breathing world of deceit and survival.
Check out the project on GitHub and start your own simulation today!

Top comments (0)