Skip to main content

Overview

Every node in Intelligence Space can be expanded using Google Gemini AI to discover related interests. Click any sphere, and within seconds, 3-5 new concepts appear, connected to the parent node. This creates an ever-growing web of knowledge tailored to your exploration.
Intelligence Space uses Gemini 2.5 Flash for fast, high-quality content generation.

How It Works

1

User Clicks a Node

When you click a sphere in the 3D graph, the handleExpand function is triggered with the node’s label:
<mesh
  onClick={(e) => {
    e.stopPropagation();
    onExpand(node.id, node.label);
  }}
/>
A loading indicator appears above the node (three bouncing dots).
2

Server Action Called

The generateSubInterests server action is invoked from src/app/actions.ts:7:
const sub = await generateSubInterests(label);
This is a Next.js server action that runs securely on the backend with API key access.
3

AI Generates Related Concepts

Gemini AI receives a carefully crafted prompt and returns 3-5 related sub-interests as a JSON array.
4

New Nodes Added

The returned concepts are added to the graph as child nodes, connected to the parent with spring forces that naturally position them in 3D space.

The AI Prompt

Prompt Engineering

The prompt is designed to produce structured, consistent output while encouraging creative exploration:
`You are an AI that helps brainstorm and expand on interests. Given an interest, provide 3 to 5 highly relevant sub-interests or related topics.
Only provide a JSON array of strings as the response. Do not include any markdown formatting like \`\`\`json. Just the raw array.
Example: ["Sub Topic 1", "Sub Topic 2", "Sub Topic 3"]

Interest: ${interest}
`
Key Design Decisions:
  1. Role Setting - “You are an AI that helps brainstorm…” establishes the AI’s purpose
  2. Clear Constraints - “3 to 5 highly relevant” prevents overwhelming or sparse results
  3. Format Specification - “Only provide a JSON array” ensures parseable output
  4. Markdown Prevention - Explicitly forbids ```json wrappers that would break parsing
  5. Example Provided - Shows exact format expected
This reduces hallucination and ensures reliable JSON parsing.

Example Results

[
  "Quantum Entanglement",
  "Wave-Particle Duality",
  "Quantum Computing Applications",
  "Heisenberg Uncertainty Principle",
  "Quantum Field Theory"
]

API Integration

Google GenAI Setup

The integration uses the official @google/genai SDK:
import { GoogleGenAI } from '@google/genai';

const ai = new GoogleGenAI({});
The API key is automatically loaded from the GEMINI_API_KEY environment variable.

Making the Request

const response = await ai.models.generateContent({
  model: 'gemini-2.5-flash',
  contents: `[prompt text]`,
});

const text = response.text;

Response Parsing

The response undergoes careful cleaning before JSON parsing:
const cleanText = text
  .replace(/```json/gi, '')
  .replace(/```/g, '')
  .trim();
  
const array = JSON.parse(cleanText);
return array.slice(0, 5); // Limit to 5 items
The .slice(0, 5) ensures that even if the AI returns more than 5 items, only the first 5 are used to prevent visual clutter.

Fallback Handling

Graceful Degradation

Intelligence Space never fails - if the API is unavailable or returns invalid data, it falls back to mock data:
If GEMINI_API_KEY is missing:
if (!process.env.GEMINI_API_KEY) {
  console.warn("GEMINI_API_KEY is not defined. Using mock data.");
  return [
    `${interest} Essentials`,
    `Advanced ${interest}`,
    `${interest} Tools`,
  ];
}
Users can still explore the interface with generic but relevant sub-topics.
Always set GEMINI_API_KEY in your environment variables for production deployments to enable AI-powered expansion.

Loading UX

Preventing Double-Clicks

The system prevents multiple simultaneous expansions:
const [loadingNodeId, setLoadingNodeId] = useState<string | null>(null);

const handleExpand = async (id: string, label: string) => {
  if (loadingNodeId) return; // Block if already loading
  setLoadingNodeId(id);
  try {
    const sub = await generateSubInterests(label);
    addNodes(sub, id);
  } finally {
    setLoadingNodeId(null);
  }
};

Visual Feedback

While AI generates content, a bouncing dots indicator appears above the node:
{loadingNodeId && (
  <Html position={[node.x, node.y + node.radius + 0.5, node.z]} center>
    <div className="flex space-x-1 items-center bg-black/50 px-2 py-1 rounded-full backdrop-blur-md">
      <div className="w-1.5 h-1.5 bg-white rounded-full animate-bounce" 
           style={{ animationDelay: "0ms" }}></div>
      <div className="w-1.5 h-1.5 bg-white rounded-full animate-bounce" 
           style={{ animationDelay: "150ms" }}></div>
      <div className="w-1.5 h-1.5 bg-white rounded-full animate-bounce" 
           style={{ animationDelay: "300ms" }}></div>
    </div>
  </Html>
)}

Automatic Initial Expansion

First Node Behavior

When you enter your first interest, Intelligence Space automatically expands it to kickstart exploration:
const handleSubmit = async (e: React.FormEvent) => {
  e.preventDefault();
  const label = input.trim();
  const newNode = addNode(label);
  
  // Automatically trigger expansion
  setIsGenerating(true);
  const { generateSubInterests } = await import('@/app/actions');
  const sub = await generateSubInterests(label);
  useInterestStore.getState().addNodes(sub, newNode.id);
  setIsGenerating(false);
};
This immediately creates a small cluster of 4-6 nodes, giving you multiple directions to explore.
The submit button shows a spinning loader during initial generation, then switches back to the sparkles icon.

Performance Considerations

Response Time

Gemini 2.5 Flash typically responds in 1-3 seconds, providing near-instant expansion.

Cost Efficiency

Using the Flash model keeps API costs minimal while maintaining quality.

Error Recovery

Fallback mock data ensures the app never crashes from API failures.

Concurrent Safety

The loadingNodeId state prevents race conditions from multiple clicks.

3D Visualization

Learn how the 3D graph is rendered

Interactive Navigation

Discover navigation and interaction patterns

Build docs developers (and LLMs) love