diff --git a/.planning/phases/03-generate-node-refactor/03-01-PLAN.md b/.planning/phases/03-generate-node-refactor/03-01-PLAN.md
index 4a923ae8..742b7971 100644
--- a/.planning/phases/03-generate-node-refactor/03-01-PLAN.md
+++ b/.planning/phases/03-generate-node-refactor/03-01-PLAN.md
@@ -5,10 +5,12 @@ type: execute
---
-Rename NanoBanana node to Generate and add multi-provider model selector.
+Rename NanoBanana node to GenerateImage and add multi-provider model selector.
-Purpose: Transform the hardcoded Gemini-only node into a generic generation node that can use any provider's models.
-Output: Generate node component with provider/model dropdown, updated types, store functions renamed.
+Purpose: Transform the hardcoded Gemini-only node into a multi-provider image generation node that filters to image-capable models only.
+Output: GenerateImage node component with provider/model dropdown (image models only), updated types, store functions renamed.
+
+Note: GenerateVideo node will be added in Phase 6 (Video & Polish) as a separate node type.
@@ -61,18 +63,19 @@ Output: Generate node component with provider/model dropdown, updated types, sto
- Task 2: Rename component to GenerateNode with model selector UI
+ Task 2: Rename component to GenerateImageNode with model selector UI
src/components/nodes/NanoBananaNode.tsx, src/components/nodes/index.ts
- 1. Rename file from NanoBananaNode.tsx to GenerateNode.tsx
+ 1. Rename file from NanoBananaNode.tsx to GenerateImageNode.tsx
- 2. Rename component from NanoBananaNode to GenerateNode (keep function export name)
+ 2. Rename component from NanoBananaNode to GenerateImageNode
3. Add model selector UI that shows:
- Provider dropdown (gemini, replicate, fal) - only show enabled providers
- Model dropdown (fetched from /api/models for selected provider)
+ - **Filter to image capabilities only**: text-to-image, image-to-image
- For Gemini, show existing hardcoded models (Nano Banana, Nano Banana Pro)
- - For other providers, fetch models dynamically
+ - For other providers, fetch models dynamically with capability filter
4. When provider/model changes:
- Update node data with selectedModel: { provider, modelId, displayName }
@@ -81,16 +84,16 @@ Output: Generate node component with provider/model dropdown, updated types, sto
5. Keep existing aspect ratio/resolution controls for Gemini models
- Hide them for non-Gemini models (parameters will come from provider schema later)
- 6. Update index.ts to export GenerateNode and alias it as NanoBananaNode for backward compatibility:
+ 6. Update index.ts to export GenerateImageNode and alias as NanoBananaNode:
```typescript
- export { GenerateNode } from "./GenerateNode";
- export { GenerateNode as NanoBananaNode } from "./GenerateNode";
+ export { GenerateImageNode } from "./GenerateImageNode";
+ export { GenerateImageNode as NanoBananaNode } from "./GenerateImageNode";
```
- WHY: The component rename reflects its new multi-provider purpose. The alias maintains backward compatibility with existing imports.
+ WHY: The component rename reflects its image-specific purpose. Video generation will be a separate GenerateVideoNode in Phase 6. The alias maintains backward compatibility.
npm run build succeeds, component renders in browser
- GenerateNode.tsx exists, shows provider selector, model dropdown fetches from API for non-Gemini providers
+ GenerateImageNode.tsx exists, shows provider selector, model dropdown shows only image-capable models
@@ -98,18 +101,18 @@ Output: Generate node component with provider/model dropdown, updated types, sto
src/store/workflowStore.ts, src/components/WorkflowCanvas.tsx
1. In workflowStore.ts:
- - Rename saveNanoBananaDefaults to saveGenerateDefaults (keep old name as alias)
- - Rename loadNanoBananaDefaults to loadGenerateDefaults (keep old name as alias)
+ - Rename saveNanoBananaDefaults to saveGenerateImageDefaults (keep old name as alias)
+ - Rename loadNanoBananaDefaults to loadGenerateImageDefaults (keep old name as alias)
- Update localStorage key comment but keep actual key for migration
- Update createDefaultNodeData for "nanoBanana" case to include default selectedModel for Gemini
2. In WorkflowCanvas.tsx:
- - Update nodeTypes registration to use GenerateNode
- - Keep "nanoBanana" as the type key (internal type name unchanged)
+ - Update nodeTypes registration to use GenerateImageNode
+ - Keep "nanoBanana" as the type key (internal type name unchanged for now)
- Update minimap color mapping if it references "nanoBanana"
3. In any file using NanoBananaNode import:
- - Update import to use GenerateNode
+ - Update import to use GenerateImageNode
- Files: ConnectionDropMenu.tsx, FloatingActionBar.tsx, etc.
WHY: Internal references update to new names while keeping the node type string "nanoBanana" for workflow file compatibility.
@@ -124,7 +127,8 @@ Output: Generate node component with provider/model dropdown, updated types, sto
Before declaring plan complete:
- [ ] `npm run build` succeeds without errors
- [ ] `npx tsc --noEmit` passes type checking
-- [ ] GenerateNode renders with provider dropdown
+- [ ] GenerateImageNode renders with provider dropdown
+- [ ] Model selector shows only image-capable models (text-to-image, image-to-image)
- [ ] Gemini models show in model selector
- [ ] Existing workflows with nanoBanana nodes still load
@@ -133,7 +137,8 @@ Before declaring plan complete:
- All tasks completed
- All verification checks pass
-- GenerateNode component exists with multi-provider UI
+- GenerateImageNode component exists with multi-provider UI
+- Model selector filters to image capabilities only
- Types support both legacy Gemini and new multi-provider selection
- Backward compatibility maintained for existing workflows
diff --git a/.planning/phases/03-generate-node-refactor/03-02-PLAN.md b/.planning/phases/03-generate-node-refactor/03-02-PLAN.md
index 4954f2c1..78957209 100644
--- a/.planning/phases/03-generate-node-refactor/03-02-PLAN.md
+++ b/.planning/phases/03-generate-node-refactor/03-02-PLAN.md
@@ -5,10 +5,12 @@ type: execute
---
-Add provider-specific execution logic to the generate API route.
+Add provider-specific execution logic to the generate API route for image generation.
-Purpose: Enable the generate endpoint to route requests to the correct provider (Gemini, Replicate, fal.ai) based on the selected model.
-Output: Updated /api/generate route that dispatches to provider-specific generation logic.
+Purpose: Enable the generate endpoint to route requests to the correct provider (Gemini, Replicate, fal.ai) based on the selected model, filtering to image outputs only.
+Output: Updated /api/generate route that dispatches to provider-specific image generation logic.
+
+Note: Video generation will use a separate endpoint in Phase 6.
@@ -59,12 +61,16 @@ Output: Updated /api/generate route that dispatches to provider-specific generat
3. Fetch output:
- Poll GET /predictions/{id} until status is "succeeded" or "failed"
- Convert output URL to base64 data URL
- - Return in GenerationOutput format
+ - Return in GenerationOutput format with type: "image"
+
+ 4. Filter to image models only:
+ - Only accept models with text-to-image or image-to-image capabilities
+ - Return error if video model passed (video generation is Phase 6)
- WHY: Replicate requires polling for async predictions. The generate() method encapsulates this complexity.
+ WHY: Replicate requires polling for async predictions. The generate() method encapsulates this complexity. Image-only filter keeps this endpoint focused.
TypeScript compiles, generate() method exists and doesn't throw immediately
- Replicate provider has working generate() method that calls prediction API
+ Replicate provider has working generate() method that calls prediction API for image models
@@ -82,14 +88,18 @@ Output: Updated /api/generate route that dispatches to provider-specific generat
- API key optional but rate limited without it
3. Parse response:
- - Extract image/video URL from response
+ - Extract image URL from response
- Convert to base64 data URL for consistency
- - Handle different output formats (images array, video URL, etc.)
+ - Handle images array output format
+
+ 4. Filter to image models only:
+ - Only accept models with text-to-image or image-to-image capabilities
+ - Return error if video model passed (video generation is Phase 6)
- WHY: fal.ai's synchronous API is simpler than Replicate. The generate() method normalizes the response format.
+ WHY: fal.ai's synchronous API is simpler than Replicate. The generate() method normalizes the response format. Image-only filter keeps this endpoint focused.
TypeScript compiles, generate() method exists
- fal.ai provider has working generate() method that calls fal.run endpoint
+ fal.ai provider has working generate() method that calls fal.run endpoint for image models
diff --git a/.planning/phases/03-generate-node-refactor/03-03-PLAN.md b/.planning/phases/03-generate-node-refactor/03-03-PLAN.md
index da0d89ad..c19b682a 100644
--- a/.planning/phases/03-generate-node-refactor/03-03-PLAN.md
+++ b/.planning/phases/03-generate-node-refactor/03-03-PLAN.md
@@ -28,7 +28,7 @@ Output: Migration logic, verified backward compatibility, updated workflow execu
# Key source files:
@src/store/workflowStore.ts
@src/types/index.ts
-@src/components/nodes/GenerateNode.tsx
+@src/components/nodes/GenerateImageNode.tsx
**Tech stack available:** Zustand, workflow JSON persistence
**Established patterns:** Workflow load/save in workflowStore
@@ -97,8 +97,8 @@ Output: Migration logic, verified backward compatibility, updated workflow execu
3. Handle response format:
- Provider generate() returns GenerationOutput with outputs array
- - Extract first image/video output as outputImage
- - For video outputs, store separately (Phase 6 handles video display)
+ - Extract first image output as outputImage
+ - Validate output type is "image" (video handled by separate node in Phase 6)
WHY: The store's execution logic needs to pass provider API keys (stored client-side) to the server route.
@@ -107,8 +107,8 @@ Output: Migration logic, verified backward compatibility, updated workflow execu
- Task 3: Update GenerateNode to handle legacy data
- src/components/nodes/GenerateNode.tsx
+ Task 3: Update GenerateImageNode to handle legacy data
+ src/components/nodes/GenerateImageNode.tsx
1. When component mounts or data changes:
- If model exists but not selectedModel, derive selectedModel from model
@@ -119,13 +119,13 @@ Output: Migration logic, verified backward compatibility, updated workflow execu
- Model dropdown shows correct Gemini model name
3. When saving defaults, save in both formats:
- - saveGenerateDefaults should save both model and selectedModel
+ - saveGenerateImageDefaults should save both model and selectedModel
- Ensures new nodes get correct defaults
WHY: The UI must correctly display legacy nodes that were migrated on load.
Open workflow with old nanoBanana node, verify dropdowns show correct selection
- GenerateNode displays correct provider/model for both legacy and new nodes
+ GenerateImageNode displays correct provider/model for both legacy and new nodes