7.1 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Build & Development Commands
npm run dev # Start Next.js dev server at http://localhost:3000
npm run build # Build for production
npm run start # Start production server
npm run lint # Run Next.js linting
npm run test # Run all tests with Vitest (watch mode)
npm run test:run # Run all tests once (CI mode)
Environment Setup
Create .env.local in the root directory:
GEMINI_API_KEY=your_gemini_api_key
OPENAI_API_KEY=your_openai_api_key # Optional, for OpenAI LLM provider
KIE_API_KEY=your_kie_api_key # Optional, for Kie.ai models (Sora, Veo, Kling, etc.)
Architecture Overview
Node Banana is a node-based visual workflow editor for AI image generation. Users drag nodes onto a React Flow canvas, connect them via typed handles, and execute pipelines that call AI APIs.
Core Stack
- Next.js 16 (App Router) with TypeScript
- @xyflow/react (React Flow) for the node editor canvas
- Konva.js / react-konva for canvas annotation drawing
- Zustand for state management (single store pattern)
Key Files
| Purpose | Location |
|---|---|
| Central workflow state & execution logic | src/store/workflowStore.ts |
| All TypeScript type definitions | src/types/index.ts |
| Main canvas component & connection validation | src/components/WorkflowCanvas.tsx |
| Base node component (shared by all nodes) | src/components/nodes/BaseNode.tsx |
| Image generation API route | src/app/api/generate/route.ts |
| LLM text generation API route | src/app/api/llm/route.ts |
| Cost calculations | src/utils/costCalculator.ts |
| Grid splitting utility | src/utils/gridSplitter.ts |
State Management
All application state lives in workflowStore.ts using Zustand. Key patterns:
useWorkflowStore()hook provides access to nodes, edges, and all actionsexecuteWorkflow(startFromNodeId?)runs the pipeline via topological sortgetConnectedInputs(nodeId)retrieves upstream data for a nodeupdateNodeData(nodeId, partialData)updates node state- Auto-save runs every 90 seconds when enabled
Execution Flow
- User clicks Run or presses
Cmd/Ctrl+Enter executeWorkflow()performs topological sort on node graph- Nodes execute in dependency order, calling APIs as needed
getConnectedInputs()provides upstream images/text to each node- Locked groups are skipped; pause edges halt execution
AI Models
Image generation models (these exist and are recently released):
gemini-2.5-flash-preview-image-generation→ internal name:nano-bananagemini-3-pro-image-preview→ internal name:nano-banana-pro
LLM models:
- Google:
gemini-2.5-flash,gemini-3-flash-preview,gemini-3-pro-preview - OpenAI:
gpt-4.1-mini,gpt-4.1-nano
Node Types
| Type | Purpose | Inputs | Outputs |
|---|---|---|---|
imageInput |
Load/upload images | reference | image |
annotation |
Draw on images (Konva) | image | image |
prompt |
Text prompt input | none | text |
nanoBanana |
AI image generation | image, text | image |
llmGenerate |
AI text generation | text, image | text |
splitGrid |
Split image into grid cells | image | reference |
output |
Display final result | image | none |
Node Connection System
Handle Types
| Handle Type | Data Format | Description |
|---|---|---|
image |
Base64 data URL | Visual content |
text |
String | Text content |
Connection Rules
- Type Matching: Handles only connect to matching types (
image→image,text→text) - Direction: Connections flow from source (output) to target (input)
- Multiplicity: Image inputs accept multiple connections; text inputs accept one
Data Flow in getConnectedInputs
Returns { images: string[], text: string | null }.
Image data extracted from:
imageInput→data.imageannotation→data.outputImagenanoBanana→data.outputImage
Text data extracted from:
prompt→data.promptllmGenerate→data.outputText
Keyboard Shortcuts
Cmd/Ctrl + Enter- Run workflowCmd/Ctrl + C/V- Copy/paste nodesShift + P- Add prompt node at centerShift + I- Add image input nodeShift + G- Add generate (nanoBanana) nodeShift + V- Add video (generateVideo) nodeShift + L- Add LLM nodeShift + A- Add annotation nodeH- Stack selected nodes horizontallyV- Stack selected nodes verticallyG- Arrange selected nodes in grid
Adding New Node Types
- Define the data interface in
src/types/index.ts - Add to
NodeTypeunion insrc/types/index.ts - Create default data in
createDefaultNodeData()inworkflowStore.ts - Add dimensions to
defaultDimensionsinworkflowStore.ts - Create the component in
src/components/nodes/ - Export from
src/components/nodes/index.ts - Register in
nodeTypesinWorkflowCanvas.tsx - Add minimap color in
WorkflowCanvas.tsx - Update
getConnectedInputs()if the node produces consumable output - Add execution logic in
executeWorkflow()if the node requires processing - Update
ConnectionDropMenu.tsxto include the node in source/target lists
Handle Naming Convention
Use descriptive handle IDs matching the data type:
id="image"for image dataid="text"for text data
Validation
- Connection validation:
isValidConnection()inWorkflowCanvas.tsx - Workflow validation:
validateWorkflow()inworkflowStore.ts
API Routes
All routes in src/app/api/:
| Route | Timeout | Purpose |
|---|---|---|
/api/generate |
5 min | Image generation via Gemini |
/api/llm |
1 min | Text generation (Google/OpenAI) |
/api/workflow |
default | Save/load workflow files |
/api/save-generation |
default | Auto-save generated images |
/api/logs |
default | Session logging |
localStorage Keys
node-banana-workflow-configs- Project metadata (paths)node-banana-workflow-costs- Cost tracking per workflownode-banana-nanoBanana-defaults- Sticky generation settings
Commits
- The .planning directory is untracked, do not attempt to commit any changes to the files in this directory.
Deployment & Git Workflow
Vercel Deployment
Production URL: https://node-banana-nilas-projects-2f16eb79.vercel.app
The app is deployed on Vercel from the etailup/node-banana fork. Pushes to master trigger automatic deployments.
Environment variables required in Vercel dashboard:
GEMINI_API_KEYOPENAI_API_KEY(optional)KIE_API_KEY(optional, for Kie.ai models)
Fork + Upstream Sync
This repo is a fork that tracks the original upstream:
| Remote | Repository | Purpose |
|---|---|---|
| origin | etailup/node-banana |
Your fork (push here, deploys to Vercel) |
| upstream | shrimbly/node-banana |
Original source (pull updates from here) |
Pull updates from original while keeping your modifications:
git fetch upstream
git merge upstream/master
# Resolve conflicts if any
git push origin master
Check remotes:
git remote -v