Tree:
e2465b9326
TEST-s
TEST-x
codex/popi-tv-header-logo
feature-img
feature/071
feature/0710
feature/260608
feature/627
feature/add_agent_md
feature/add_provider_popi
feature/canvas-chatbot-copilot
feature/composer
feature/gateway
feature/group
feature/handle
feature/handleReconstruction
feature/interaction
feature/new_node
feature/remove
feature/video-erase
feature/workflow
feature_apikey
feature_gateway-migration
feature_login
handoff-20260429-1057
master
songxh-popiart-node-canvas
test-0523
video_node
xuzhijie-popiart-node-canvas
${ noResults }
82 Commits (e2465b9326abebffbbb284e4a3652279f7918af5)
| Author | SHA1 | Message | Date |
|---|---|---|---|
|
|
8008801402
|
feat: Tutorial improvements with mock execution and organized demonstration (#112)
* feat(49-01): add FTUX types and localStorage helpers
- Create src/types/ftux.ts with FTUXStep, FTUXModalProps, FTUXStepProps
- Add FTUX_COMPLETED_KEY to localStorage keys
- Add getFTUXCompleted() and setFTUXCompleted() helpers
- Follow existing localStorage pattern with server-safe checks
* feat(49-02): create tutorial state management with Zustand
- TutorialStep interface with id, message, highlightSelector, requiredAction
- FTUXState with tutorialActive, currentTutorialStep, tutorialSteps, lockedFeatures
- Actions: startTutorial, skipTutorial, completeCurrentStep, nextTutorialStep, resetTutorial
- setFTUXCompleted/getFTUXCompleted localStorage helpers
- Initial tutorial steps (5 steps, placeholders for Plan 03)
* feat(49-01): build FTUXModal container and step components
- Create FTUXModal.tsx: 4-step modal with navigation, skip confirmation
- Create FTUXWelcomeStep.tsx: Welcome screen with project intro
- Create FTUXApiKeysStep.tsx: Provider list with .env status checking
- Create FTUXModelDefaultsStep.tsx: Model selection via ModelSearchDialog
- Create FTUXReadyStep.tsx: Completion screen with tutorial option
- Follow WelcomeModal and ProjectSetupModal patterns
- Use Tailwind neutral-800 theme throughout
- Step indicators show progress (1-4)
- Back button hidden on step 1
- Skip confirmation shows nested dialog overlay
* feat(49-02): build typewriter hook and tutorial UI components
- useTypewriter hook with 50ms/char animation and isComplete flag
- TutorialMessage component with typewriter animation and dark backdrop
- ElementHighlight component with pulsing blue ring (2px border, 8px blur)
- Three-layer highlight: dimmed overlay (bg-black/60), blue ring (z-91), clickable window (z-92)
- TutorialOverlay coordinator with action detection (add-image-node, connect-nodes, run-workflow)
- Skip tutorial button in top-right corner
- pulse-ring keyframes added to globals.css
- Uses React portals for correct z-index stacking
* feat(49-03): replace WelcomeModal with FTUXModal in app entry point
- Import FTUXModal, getFTUXCompleted, setFTUXCompleted, useFTUXStore
- Add SSR-safe showFTUX state (initialized via useEffect)
- Render FTUXModal when showFTUX=true
- onComplete callback sets showFTUX=false and marks FTUX complete
- onStartTutorial callback hides modal and starts tutorial via ftuxStore
- WelcomeModal still available via logo click (not removed, just not on first visit)
* feat(49-03): integrate tutorial overlay and add data-tutorial attributes
WorkflowCanvas.tsx:
- Import TutorialOverlay and useFTUXStore
- Get tutorialActive and lockedFeatures from ftuxStore
- Apply dimming (opacity-30 + pointer-events-none) to Background, Controls, MiniMap when tutorial active
- Render TutorialOverlay component after AnnotationModal
FloatingActionBar.tsx:
- Add optional dataTutorial prop to NodeButton interface
- Add data-tutorial="image-button" to Image input button
- Add data-tutorial="output-button" to Output button
- These attributes allow ElementHighlight to target buttons during tutorial
* fix(49-03): resolve Zustand SSR hydration issue in WorkflowCanvas
- Replace direct useFTUXStore hook call with useState + useEffect pattern
- Subscribe to ftuxStore on client-side only via useEffect
- Initialize state with getState() after subscription
- Prevents 'getServerSnapshot should be cached' error during SSR
- Prevents 'Maximum update depth exceeded' infinite loop
* chore(49-03): add FTUX testing override to always show modal
- Force setShowFTUX(true) to bypass localStorage check
- Allows repeated testing without clearing localStorage each time
- Added clear TODO comment to revert before production
- Original production code commented out for easy restoration
* ux(49-03): improve FTUX modal copy and layout based on user testing
FTUXModal.tsx:
- Increase modal width from max-w-[520px] to max-w-[640px] for better readability
FTUXWelcomeStep.tsx:
- Remove large banana icon (w-20 h-20) for cleaner look
- Change headline from "Welcome to Node Banana" to "Let's get set up."
- Keep workflow description, update subtext to "This will only take a few quick steps."
FTUXApiKeysStep.tsx:
- Simplify description to emphasize .env.local security benefit
- New: "Add your API keys here, or save them to .env.local to keep them secure across sessions."
- Remove mention of settings (cleaner messaging)
FTUXModelDefaultsStep.tsx:
- Remove redundant "You can always change these later" from main description
- Remove "These defaults are applied when creating nodes" from footer (redundant)
- Keep single mention: "You can skip this step and configure them later in settings."
FTUXReadyStep.tsx:
- Remove large green checkmark icon (w-16 h-16 circular bg)
- Keep "All Set Up!" headline and description
- Keep both tutorial buttons unchanged
* ux(49-03): remove redundant .env.local text below API keys list
- Remove duplicate messaging at bottom of FTUXApiKeysStep
- Top description already mentions .env.local security benefit
- Cleaner, less repetitive UI
* copy(49-03): rewrite FTUX copy for clarity and conciseness
Applied principles: Clear, Concise, Consistent, Useful, Human
FTUXWelcomeStep:
- Headline: "Let's get set up." → "Let's get started."
- Body: Simplified from wordy workflow/pipeline jargon to clear action
Old: "Build AI workflows visually with nodes and connections. Create complex image and video generation pipelines by connecting simple building blocks."
New: "Connect AI models like building blocks to generate images, videos, and more."
- Removed defensive subtext ("This will only take a few quick steps")
FTUXApiKeysStep:
- Description: Clearer security benefit, less technical
Old: "Add your API keys here, or save them to .env.local to keep them secure across sessions."
New: "Add keys to use AI providers. For security, save them to your .env.local file instead of the browser."
FTUXModelDefaultsStep:
- Headline: "Default Models (Optional)" → "Choose Your Models (Optional)"
- Description: Removed redundant "by default when creating new nodes"
Old: "Choose which AI models to use by default when creating new nodes."
New: "Pick which AI models to use for images and videos."
- Removed defensive footer text ("You can skip...")
FTUXReadyStep:
- Headline: "All Set Up!" → "You're ready!"
- Body: Removed jargon and redundancy
Old: "You're ready to start building workflows. Would you like a quick tutorial to get started?"
New: "Want a quick tutorial?"
- Buttons: "Skip Tutorial" → "Skip", "Start Tutorial" → "Show me how"
* fix(49-03): remove double scrollbar in API Keys step
- Remove max-h-[380px] overflow-y-auto from provider list container
- FTUXModal already has overflow-y-auto on content area (line 112)
- Provider list now scrolls with rest of modal content, not separately
- Fixes nested scroll container causing double scrollbar
* copy(49-03): clarify browser storage in API Keys step
- Make it explicit that adding keys in UI = stored in browser
- Parenthetical "(stored in browser)" right after action
- "for better security" instead of "For security" flows better
- Clearer tradeoff between convenience (browser) and security (.env.local)
Old: "Add keys to use AI providers. For security, save them to your .env.local file instead of the browser."
New: "Add keys here to use AI providers (stored in browser), or save them to your .env.local file for better security."
* copy(49-03): add "across sessions" to API Keys security benefit
- Change "better security" to "better security across sessions"
- Makes the persistence benefit of .env.local more explicit
- Clarifies why file storage is better than browser storage
New: "Add keys here to use AI providers (stored in browser), or save them to your .env.local file for better security across sessions."
* fix(49-03): save API keys entered during FTUX onboarding
Problem: API keys entered in FTUX modal were stored in local state only
and disappeared when modal closed, requiring users to re-enter them.
Original plan decision (49-01): "API key inputs not persisted during FTUX flow"
Rationale: "Setup is informational only, actual persistence happens in ProjectSetupModal"
This created broken UX - users entered keys expecting them to work.
Solution:
- Import useWorkflowStore and updateProviderApiKey function
- Create handleKeyChange that saves to localStorage immediately via updateProviderApiKey
- Replace direct setLocalKeys with handleKeyChange in input onChange
- Keys now persist automatically as user types (saved as null if empty)
Impact: Users can now enter API keys during onboarding and they'll be
available immediately in the app without re-entry.
Deviation: Auto-fix bug (Rule 1) - keys not persisting broke user expectations
* fix(49-03): close FTUX modal and center tutorial message
Issue 1 - FTUX modal still visible after starting tutorial:
- Add setFTUXCompleted(true) to handleStartTutorial
- Ensures modal won't re-render even with testing override
- Modal now properly closes before tutorial starts
Issue 2 - Tutorial message overlapping floating action bar:
- Change TutorialMessage position from bottom-4 to center of screen
- Use top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 for true center
- Message now displays prominently in center, not at bottom
- Update comment: "contextual placement" → "center of screen for maximum visibility"
Before: bottom-4 left-1/2 -translate-x-1/2 (bottom center)
After: top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 (true center)
* fix(49-03): close WelcomeModal when starting tutorial
Problem: WelcomeModal (original quickstart modal with "New Project", "Load Workflow",
etc.) remained visible when user clicked "Show me how" to start tutorial, blocking the
tutorial UI.
Root cause: WelcomeModal is controlled by workflowStore.showQuickstart state and was not
being closed when tutorial started.
Solution:
- Import setShowQuickstart from useWorkflowStore
- Add setShowQuickstart(false) to handleStartTutorial
- WelcomeModal now closes before tutorial overlay appears
Now when tutorial starts, both FTUXModal and WelcomeModal are closed, allowing tutorial
overlay to display without obstruction.
* fix(49-03): implement complete tutorial progression flow
Problem: Tutorial stuck on "Let's cook." message without progressing.
Root causes:
1. Step 1 (welcome) had no requiredAction, so action detection never triggered
2. Steps 3-5 were placeholder steps with no content or actions
3. No auto-advance logic for informational steps
Solution:
ftuxStore.ts - Replace placeholder steps with real tutorial:
- Step 1: "Let's cook." (welcome, auto-advances after 3s)
- Step 2: "Click the Image button to add an image node." (highlights image button, requires add-image-node)
- Step 3: "Now add an Output node to see your results." (highlights output button, requires add-output-node)
- Step 4: "You're all set! Connect nodes to build workflows, or press Cmd+Enter to run." (completion, auto-advances)
- Add "add-output-node" to TutorialStep requiredAction type
TutorialOverlay.tsx - Add auto-advance and output detection:
- Steps without requiredAction now auto-advance after 3 seconds (typewriter completes ~2s)
- Add detection for "add-output-node" action (checks for node.type === "output")
- Early return cleanup timer to prevent memory leaks
Tutorial now flows: Welcome → Add Image → Add Output → Complete
Each step progresses based on user action or auto-advances for info steps.
* fix(49-03): make tutorial highlighted elements clickable and visible
Problem 1: Floating action bar was darkened during tutorial even though it
contains the highlighted image button that user needs to see and click.
Problem 2: Image button was not clickable - Layer 3 "clickable window" was
blocking clicks instead of allowing them through.
Root cause: ElementHighlight had full-screen dimmed overlay (Layer 1) blocking
clicks, and Layer 3 created an empty div that blocked the actual element.
Solution - Use box-shadow cutout technique:
- Remove solid dimmed overlay (bg-black/60)
- Remove Layer 3 entirely (not needed)
- Use box-shadow: "0 0 0 9999px rgba(0, 0, 0, 0.6)" on positioned div
- Creates dimmed overlay with cutout hole where highlighted element is
- Highlighted element remains fully visible (not dimmed)
- Highlighted element is fully clickable (no overlay blocking it)
- Everything else gets dimmed
FloatingActionBar.tsx:
- Import useFTUXStore (prepared for future use)
- Add tutorial state awareness (not currently used but ready for expansion)
ElementHighlight.tsx:
- Replace full-screen overlay + clickable window with box-shadow cutout
- Simpler 2-layer approach: dimmed background with hole + blue ring
- All pointer-events-none, so nothing blocks the actual DOM element
* fix(49-03): resolve Zustand SSR hydration issue in FloatingActionBar
Error: "The result of getServerSnapshot should be cached to avoid an infinite loop"
at FloatingActionBar (src/components/FloatingActionBar.tsx:345:58)
Same issue as WorkflowCanvas - direct useFTUXStore hook call during SSR.
Solution (identical pattern to WorkflowCanvas fix):
- Replace direct useFTUXStore hook with useState + useEffect pattern
- Initialize with false defaults (SSR-safe, no hydration mismatch)
- Subscribe to ftuxStore on client-side only via useEffect
- Initialize state with getState() after subscription
- Return cleanup function to unsubscribe on unmount
Before: const { tutorialActive, lockedFeatures } = useFTUXStore(...)
After: useState + useEffect subscription (client-side only)
This prevents the SSR hydration error while maintaining reactive updates.
* chore(49-03): restore production FTUX localStorage check
- Remove testing override that forced FTUX to show every time
- Restore production code: if (!getFTUXCompleted()) { setShowFTUX(true); }
- Remove TODO comment about reverting
- FTUX now only shows on first visit as intended
* feat(tutorial): add connection drop menu workflow steps
Extend the FTUX tutorial with 4 new steps that teach users how to use the
connection drop menu workflow pattern:
Step 6: Drag from output handle
- Prompts user to drag from the image node's output handle
- Tracks drag start via onConnectStart handler
Step 7: Release in empty space
- Prompts user to release to show the connection drop menu
- Tracks menu appearance via handleConnectEnd
Step 8: Explain connection menu
- Highlights the drop menu with blue ring
- Explains it shows compatible nodes
- Requires click to continue
Step 9: Select Generate Image
- Highlights "Generate Image" button in menu
- Tracks nanoBanana selection via handleMenuSelect
- Only advances when selected from menu (not FloatingActionBar)
Step 10: Tutorial complete
- Shows completion message with workflow tips
- Auto-advances after 3s and marks FTUX done
Implementation details:
- Add 3 new requiredAction types to TutorialStep interface
- Add 3 state tracking flags to FTUXState (connectionDragStarted, etc.)
- Add tutorial tracking in WorkflowCanvas connection lifecycle
- Add data-tutorial attributes for highlighting menu elements
- Import OnConnectStart type and create handleConnectStart handler
- Track menu appearance and nanoBanana selection with tutorialActive guards
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* refactor(tutorial): simplify drag-and-drop flow
Combine drag and drop instructions into a single step and immediately
highlight the Generate Image button when the context menu appears:
Changes:
- Combine step 6 (drag) and step 7 (drop) into one: "Drag from the output
handle and drop into empty space"
- Remove step 8 (explain menu) - go straight to highlighting Generate Image
- Step 6 now waits for menu to appear (show-connection-menu)
- Step 7 highlights Generate Image button immediately (add-nanoBanana-from-menu)
Removed unused tracking:
- Remove start-connection-drag requiredAction type
- Remove connectionDragStarted state flag and setter
- Remove handleConnectStart callback from WorkflowCanvas
- Remove onConnectStart prop from ReactFlow
- Remove OnConnectStart import
New flow is cleaner and more direct:
Step 5: Explain outputs (click to continue)
Step 6: Drag and drop to show menu (auto-advance)
Step 7: Select Generate Image (auto-advance)
Step 8: Complete
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* fix(tutorial): highlight Generate Image button immediately
Combine drag-and-drop and selection steps into one to ensure the Generate
Image button is highlighted as soon as the connection menu appears.
Problem:
- Previous flow had two separate steps (drag-drop, then select)
- 1 second delay between menu appearing and Generate Image highlighting
- Output handle was highlighted while menu was already visible (confusing)
Solution:
- Single step: "Drag from the output handle and drop into empty space. Then
select 'Generate Image'."
- highlightSelector targets the Generate Image button from the start
- ElementHighlight polls every 500ms, so highlights button immediately when
menu appears (no delay)
- Cleaner UX: instruction → action → immediate visual feedback
Removed:
- show-connection-menu requiredAction (no longer needed)
- connectionMenuShown state flag and setter
- Tutorial tracking in handleConnectEnd
New flow:
- Step 5: Explain outputs (click to continue)
- Step 6: Drag, drop, select Generate Image (highlight on button, auto-advance)
- Step 7: Complete
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* fix(tutorial): increase highlight z-index above connection menu
The ElementHighlight component was rendering at z-index 91, but the
ConnectionDropMenu is at z-index 100, causing the highlight ring to
appear behind the menu.
Change: Increase ElementHighlight z-index from 91 to 101
This ensures the pulsing blue ring appears on top of the menu while
still allowing clicks through (pointer-events-none).
Z-index stack:
- ElementHighlight: 101 (above menu)
- ConnectionDropMenu: 100
- Skip tutorial button: 94
- TutorialMessage: 93
- Click overlay: 92
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* fix(tutorial): highlight output handle when prompting drag action
Split the combined step back into two sequential steps with proper highlights
and instant transition between them.
Problem:
- Single step told user to "Drag from the output handle" but highlighted
the Generate Image button (which doesn't exist yet)
- Confusing visual feedback - wrong element highlighted for the instruction
Solution:
- Step 6: "Drag from the output handle and drop into empty space."
- Highlights: node-output-handle
- Action: show-connection-menu
- advanceDelay: 0ms (instant transition)
- Step 7: "Select 'Generate Image' to add an AI image generation node."
- Highlights: generate-image-option
- Action: add-nanoBanana-from-menu
- advanceDelay: 1000ms (default)
New feature: advanceDelay property
- Added to TutorialStep interface
- Configurable delay before advancing to next step after action completes
- Default: 1000ms (preserves existing behavior)
- Step 6 uses 0ms for instant transition when menu appears
Flow:
1. User sees output handle highlighted → drags and drops
2. Menu appears → step advances instantly (0ms delay)
3. Generate Image button immediately highlighted
4. User clicks → tutorial advances after 1s
Restored:
- show-connection-menu requiredAction
- connectionMenuShown state and setter
- Tutorial tracking in handleConnectEnd
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* fix(tutorial): subscribe to ftux state for action detection
The action detection useEffect wasn't re-running when connectionMenuShown
or nanoBananaAddedFromMenu changed because these states weren't in the
dependency array.
Problem:
- User drags and drops → menu appears
- setConnectionMenuShown(true) updates ftuxStore
- But action detection useEffect doesn't re-run (missing dependency)
- Step doesn't advance to highlight Generate Image button
Solution:
- Subscribe to connectionMenuShown and nanoBananaAddedFromMenu at component level
- Use these subscribed values instead of getState() calls
- Add them to useEffect dependency array
Now when these states change:
1. Component re-renders with new values
2. useEffect re-runs due to dependency change
3. Action is detected as completed
4. Step advances with configured delay (0ms for instant transition)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* feat(tutorial): add prompt node and connection steps
Extend tutorial with steps 8-9 to teach users:
- Adding nodes via FloatingActionBar (different from connection menu)
- Connecting nodes by dragging between existing handles
Changes:
- Add data-tutorial="prompt-button" to Prompt button
- Add data-tutorial="prompt-output-handle" to Prompt output handle
- Add "add-prompt-node" to requiredAction types
- Add step 8: Add Prompt node via FloatingActionBar
- Add step 9: Connect Prompt to Generate Image node
- Update step 10 (complete) message for clarity
- Add action detection for add-prompt-node in TutorialOverlay
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* fix(tutorial): wait for prompt node connection in step 9
Step 9 was advancing immediately because it checked for ANY edges,
but an edge already existed from step 7 (Image → Generate Image).
Changes:
- Add "connect-prompt-node" requiredAction type
- Update step 9 to use "connect-prompt-node" instead of "connect-nodes"
- Add detection logic that specifically checks for edges FROM prompt nodes
- Track edges in TutorialOverlay component state for reactive detection
- Add edges to useEffect dependency array
Now step 9 correctly waits for user to connect the prompt node
before advancing to the completion step.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* feat: prevent node overlap on creation with automatic collision detection
Implements AABB collision detection to automatically place new nodes in collision-free positions. When users add nodes via FloatingActionBar or keyboard shortcuts, the system now finds the nearest free position using a spiral search pattern (right, down, left, up, diagonals).
Changes:
- Add spatialLayout.ts with rectanglesIntersect() and findNearestFreePosition()
- Update addNode() to use collision detection before placing nodes
- Remove random offset from FloatingActionBar for more deterministic placement
- Use consistent 20px gap (COLLISION_GAP) matching existing STACK_GAP pattern
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* feat(tutorial): extend FTUX with content setup and resource guidance
Add four new tutorial steps to guide users through completing their first workflow:
- Prompt users to add text to the Prompt node
- Prompt users to add an image to the Image node
- Instruct users to run the workflow with Cmd/Ctrl+Enter
- Inform users about saving projects, templates, and Discord community
This ensures users complete a full workflow cycle during onboarding and know where to find help and resources.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* fix(tutorial): remove emojis from tutorial messages
Remove decorative emojis from the save-and-resources and completion steps for a cleaner, more professional appearance.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* fix(tutorial): improve viewport zoom timing with auto-populated nodes
Increase timeout from 400ms to 600ms and improve viewport setting logic
to ensure proper 0.7 zoom level when tutorial image node is added with
pre-loaded base64 data. Fetch fresh nodes from store and extend animation
duration for smoother transition.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* feat(tutorial): delay auto-population until after prompt connection
Change tutorial flow to create empty nodes initially and auto-populate
with sample content only after the prompt node is connected to generate.
This maintains hands-on learning while still removing friction.
Changes:
- Nodes created empty during tutorial
- Auto-populate after "connect-prompt-node" step completes
- Switch sample image: model.png → owl.jpg
- Update prompt: "wearing aviator sunglasses and a leather jacket"
- Add nodesPopulated ref to prevent duplicate population
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* feat(tutorial): improve messaging, dual highlights, and pulsing animation
- Change welcome message: "Let's cook" → "Let's go over the basics"
- Add dual highlight for connect-prompt step: both prompt output and
generate text input handles are now highlighted simultaneously
- Position connect-prompt message on left side of screen
- Update ElementHighlight to support array of selectors
- Add data-tutorial attribute to generate node's text input handle
- Pulsing animation already present via pulse-ring animation
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* feat(tutorial): implement mock execution and organized node demonstration
- Add mock workflow execution to save API costs during tutorial
- Mock execution simulates 5-second generation time with edge animations
- Loads pre-made owl aviator image instead of calling Gemini API
- Provides realistic experience without incurring charges
- Implement visible workflow tree demonstration
- Automatically builds branching workflow after mock execution
- Video branch: Prompt → Generate Video → Output
- LLM branch: Prompt → LLM → Generate Image #2 → Output
- Clean horizontal layout with 350px spacing between nodes
- Vertical separation of ±350px for clear branch distinction
- Improve user experience
- Auto-close run menu when advancing past tutorial steps
- Unlock canvas navigation after demonstration completes
- Zoom to 0.35 with centered viewport for complete tree overview
- Updated LLM prompt for nightclub scene generation
- Add tutorial assets
- Add owl aviator image (public/tutorial/owl-aviator.png)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* fix: restore .env.example file
Restore .env.example that was accidentally deleted in commit 9be881c.
This file is needed as a reference for users to set up their environment.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
|
3 months ago |
|
|
99197fc416 |
fix: preserve embedded audio when stitching videos
The video stitch node was only copying video tracks from source clips, silently discarding any embedded audio. Now extracts and concatenates audio from source videos when no external audio node is connected. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> |
3 months ago |
|
|
3c12e4f02e |
test(48-01): add failing tests for loop edge utilities
- Extend WorkflowEdgeData with isLoop and loopCount fields - Add wouldCreateCycle tests (linear, diamond, self-loop, disconnected) - Add findLoopSubgraph tests (simple loop, partial loop, branch within loop) - Add copyLoopOutput tests (image, video, text, audio data types) - Tests fail as expected (RED phase) |
3 months ago |
|
|
cd6dada4d6 |
feat: add array batch mode for sequential generation from all items
When batch mode is enabled on an array node, all parsed items are sent through a single connection to a downstream generate node, which loops through them sequentially. This eliminates the need to create separate downstream nodes for each array item. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> |
4 months ago |
|
|
67c1affa22 |
feat: add audio-to-video capability type and model discovery
Add "audio-to-video" to ModelCapability union, extend ModelInput.type and ModelInputDef.type with "audio", and include "audio-to-video" in fal.ai RELEVANT_CATEGORIES for model discovery. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> |
4 months ago |
|
|
a064ddc106 |
feat: add VideoInput node for uploading/loading video files
Adds a new videoInput node type that allows users to drag-and-drop or browse for video files (MP4, WebM, QuickTime), preview them inline with native video controls, and feed them into downstream video processing nodes. Includes full media externalization/hydration support, Shift+Y keyboard shortcut, and ConnectionDropMenu integration. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> |
4 months ago |
|
|
c5fe370a1d |
feat: wire browse view into WelcomeModal
Load workflow button now navigates to the WorkflowBrowserView instead of immediately opening the OS directory picker. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> |
4 months ago |
|
|
65e01cb64a |
feat: add missing ref fields for media externalization
Add audioFileRef, imageARef, imageBRef, and capturedImageRef fields to AudioInputNodeData, ImageCompareNodeData, and GLBViewerNodeData to support external media storage optimization. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> |
4 months ago |
|
|
d8dbe5b328 |
feat: add isOptional flag to input node types and skipped status
Add `isOptional?: boolean` to ImageInputNodeData, AudioInputNodeData, and PromptNodeData. Add "skipped" to NodeStatus union type to support skip propagation in the execution engine. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> |
4 months ago |
|
|
a876dfe262 |
feat: add "NBP Input" toggle to group context menu
Allow marking groups as NBP inputs for workflow export. Adds isNbpInput flag to NodeGroup, a toggle row in the group context menu with checkmark indicator, and a dashed border on marked group backgrounds. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> |
4 months ago |
|
|
0fd65682ce |
fix: prevent node height accumulation with inline parameters on reload
Store measured settings panel height in node data (_settingsPanelHeight). On workflow load, subtract it from persisted height so BaseNode's expand effect re-adds the real panel height from a clean baseline instead of double-counting. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> |
4 months ago |
|
|
e405e46bf9 |
feat(47-01): add inline parameters infrastructure - types, hook, and panel component
- Add parametersExpanded field to 5 generation node data types (NanoBanana, GenerateVideo, Generate3D, GenerateAudio, LLMGenerate) - Create useInlineParameters hook for localStorage-backed global setting (default: false) - Create InlineParameterPanel component with collapsible UI and chevron toggle - All TypeScript compiles without new errors |
4 months ago |
|
|
fe6a2e5480 |
feat: add Clear button to ConditionalSwitch node
Adds an evaluationPaused flag that lets users reset evaluation state and un-dim all downstream paths. The flag auto-resets on workflow execution or manual rule edits. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> |
5 months ago |
|
|
688e3b21c5 |
feat: add Anthropic Claude LLM provider and Gemini 3.1 Pro model
Add Anthropic as a third LLM provider with Claude Opus 4.6, Sonnet 4.5, and Haiku 4.5 models. Extend Google provider with Gemini 3.1 Pro. Includes full API route support with multimodal content blocks, provider settings UI, temperature clamping (Anthropic max 1.0), header builder plumbing, and comprehensive test coverage. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> |
5 months ago |
|
|
cbc278f801 |
feat: add Image Search toggle for Nano Banana 2
Nano Banana 2 (gemini-3.1-flash-image) supports a new searchTypes API that allows enabling web search and image search independently. This adds a useImageSearch toggle visible only for Nano Banana 2, while keeping the existing Google Search toggle using the legacy format for Nano Banana Pro. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> |
5 months ago |
|
|
b71db648b2 |
feat: add extended aspect ratios (1:4, 1:8, 4:1, 8:1) for Nano Banana 2
Make aspect ratio dropdowns model-aware: nano-banana-2 shows 14 ratios while other models keep showing the base 10. Also add nano-banana-2 to the SplitGrid settings model list. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> |
5 months ago |
|
|
2f94e36d9c |
feat: add nano-banana-2 model type and 512px resolution
Add "nano-banana-2" to ModelType union for Gemini 3.1 Flash Image Preview. Add "512" resolution tier. Add MODEL_DISPLAY_NAMES lookup to replace ternaries. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> |
5 months ago |
|
|
8ca36b30bf |
feat(45-01): add ConditionalSwitch type definitions, default data, executor, and validation
- Add MatchMode type (exact, contains, starts-with, ends-with) - Add ConditionalSwitchRule interface with id, value, mode, label, isMatched - Add ConditionalSwitchNodeData interface with incomingText and rules array - Add conditionalSwitch to NodeType union (after switch) - Add ConditionalSwitchNodeData to WorkflowNodeData union - Add default data with single rule (mode: contains, empty value) - Add default dimensions (260x180, wider than Switch for mode dropdown) - Add executeConditionalSwitch passthrough executor - Add conditionalSwitch to VALID_NODE_TYPES in validation - Export ConditionalSwitchNode from components index (component created in next task) |
5 months ago |
|
|
570433012c |
feat(44-01): add SwitchNodeData type, default data, dimensions, and executor
- Add "switch" to NodeType union in types/nodes.ts - Create SwitchNodeData interface with inputType and switches array - Add SwitchNodeData to WorkflowNodeData union - Register switch dimensions (220x120) in nodeDefaults.ts and validation.ts - Add createDefaultNodeData case with single default switch - Implement executeSwitch passthrough executor in simpleNodeExecutors.ts - Add SwitchNode export to components/nodes/index.ts - Add switch dimensions to WorkflowCanvas.tsx default dimensions map Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> |
5 months ago |
|
|
88f66b58a3 |
feat(43-01): add RouterNodeData type, defaults, and executor
- Add 'router' to NodeType union in types/nodes.ts - Add RouterNodeData interface (extends BaseNodeData, no internal state) - Add RouterNodeData to WorkflowNodeData union - Add router dimensions (200x80) to nodeDefaults.ts and validation.ts - Add router default data (empty object) to both files - Add executeRouter pure passthrough function to simpleNodeExecutors.ts - Add RouterNode export to components/nodes/index.ts Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> |
5 months ago |
|
|
4d680b0d11 |
feat: add Array node with selectable routing and auto-route to prompts
|
5 months ago |
|
|
0a46423717 |
feat(quick-009): add VideoFrameGrabNodeData type, defaults, and connected inputs wiring
- Add 'videoFrameGrab' to NodeType union and VideoFrameGrabNodeData interface - Register default dimensions (320x320) and default data in nodeDefaults - Wire getSourceOutput to return image type from videoFrameGrab.outputImage - Add videoFrameGrab dimensions to local Record types in WorkflowCanvas and validation |
5 months ago |
|
|
b44026dc20 |
feat(quick-007): add VideoTrim types, hook, executor, and plumbing
- Add 'videoTrim' to NodeType union and VideoTrimNodeData interface in nodes.ts - Add VideoTrimNodeData to WorkflowNodeData union - Add default dimensions (360x360) and default data to nodeDefaults.ts - Create useTrimVideo.ts hook with MediaBunny frame-by-frame trim + audio preservation - Add getSourceOutput case for videoTrim in connectedInputs.ts - Add executeVideoTrim executor to videoProcessingExecutors.ts - Wire 'videoTrim' case into executeNode.ts dispatcher - Fix duplicate Record<NodeType> dimensions in WorkflowCanvas.tsx and validation.ts |
5 months ago |
|
|
ccb5734683 |
Merge branch 'develop' into fix/fal-3d-url-extraction
|
5 months ago |
|
|
f801b8eb0d |
feat: connect GenerateAudio output to Output node with audio playback
Add audio support to the Output node so GenerateAudio can pipe audio through for playback and download. Adds audio input handle, <audio> player, audio→output connection validation, and executeOutput audio handling. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> |
5 months ago |
|
|
4ab1b89ed9 |
feat: add audio type to API types and connection wiring
Add generateAudio to getNodeHandles() for connection validation, wire audio handle type in connection drop menu, and add "audio" mediaType to GenerateRequest/GenerateResponse API types. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> |
5 months ago |
|
|
2c58afc352 |
feat: add TTS audio generation node support
Add comprehensive text-to-speech (TTS) support with a new generateAudio node that integrates with multiple AI providers (Kie.ai, Replicate, fal.ai, WaveSpeed). Changes: - Add 'text-to-audio' capability to ModelCapability type - Add GenerateAudioNodeData type and CarouselAudioItem for audio history - Create GenerateAudioNode component with audio playback and waveform visualization - Add TTS models from Kie.ai (ElevenLabs Turbo v2.5, Multilingual v2, Eleven V3) - Update fal.ai category mapping to support 'text-to-speech' -> 'text-to-audio' - Add audio filter option to ModelSearchDialog - Register generateAudio node in WorkflowCanvas with fuchsia minimap color - Add generateAudio to ConnectionDropMenu for both audio source and text target - Update connectedInputs to handle audio output from generateAudio nodes - Add default node data and dimensions for generateAudio type - Update quickstart validation to include generateAudio node type The node supports: - Text-to-audio generation with multiple TTS models - Real-time audio playback with waveform visualization - Audio history carousel for navigating generated audio - Dynamic model parameters based on selected provider - Integration with existing audio handle system Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> |
5 months ago |
|
|
b8d31b0376 |
fix: add security guards and type consistency for PR #71
- Add localhost-only guard to /api/open-file (rejects non-localhost with 403) - Restrict open-file paths to user's home directory - Change savedFilename/savedFilePath from optional to required-but-nullable - Remove zip from KNOWN_3D_EXTENSIONS (not a valid 3D format) - Export getExtensionFromUrl for testability Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> |
5 months ago |
|
|
d5071dd5bc |
feat: add savedFilename/savedFilePath fields to Generate3DNodeData
Add optional fields to track the auto-saved 3D model filename and file path, with null defaults in nodeDefaults and quickstart validation. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> |
5 months ago |
|
|
57d0cd860e
|
Release: 3D viewer, execute selected nodes, canvas navigation settings (#66)
* refactor: extract schema utilities from generate route Extract INPUT_PATTERNS, InputMapping, ParameterTypeInfo, getParameterTypesFromSchema, coerceParameterTypes, and getInputMappingFromSchema into schemaUtils.ts with 23 new tests. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: extract Gemini provider from generate route Move MODEL_MAP and generateWithGemini() into providers/gemini.ts. Remove unused imports (GoogleGenAI, uploadImageForUrl, shouldUseImageUrl, deleteImages, ProviderModel) from route.ts. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: extract Replicate provider from generate route Move generateWithReplicate() into providers/replicate.ts. It imports schema utilities from schemaUtils.ts. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: extract fal.ai, Kie.ai, WaveSpeed providers from generate route Move generateWithFalQueue, generateWithKie, generateWithWaveSpeed and all their helpers into providers/fal.ts, providers/kie.ts, providers/wavespeed.ts. Add barrel export at providers/index.ts. route.ts reduced from 2,838 to 518 lines (POST handler + routing only). Re-export clearFalInputMappingCache from route.ts for test backward compat. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: extract API header builder from workflow store Replace 6 duplicated header-building if/else chains (across executeWorkflow and regenerateNode) with buildGenerateHeaders() and buildLlmHeaders() utility functions. Add 13 new tests. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: extract execution utilities from workflow store Move groupNodesByLevel, chunk, revokeBlobUrl, clearNodeImageRefs, and concurrency settings into executionUtils.ts with 21 new tests. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: extract getConnectedInputs and validateWorkflow as pure functions Move getConnectedInputs (136 lines) and validateWorkflow (59 lines) into connectedInputs.ts as pure functions taking (nodeId, nodes, edges). Store methods become thin wrappers. Add 22 new tests. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: define node executor interface and context types Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: extract simple node executors Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: unify nanoBanana execution into shared executor Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: unify generateVideo execution into shared executor Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: unify llmGenerate execution into shared executor Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: unify splitGrid execution into shared executor Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: unify videoStitch and easeCurve executors Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: replace switch/if-else with node executor registry Wire extracted executors into workflowStore, replacing the ~1000-line switch statement in executeWorkflow and ~750-line if-else chain in regenerateNode with executor registry calls. Store reduced from 3,402 to 1,782 lines. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: final cleanup of workflowStore module structure Remove dead trackSaveGeneration function (no longer called after executor extraction) and unused type imports. Store: 3,838 -> 1,721 lines (55% reduction). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: video regeneration spinner stuck + cancel error message Fix video element not reloading on regeneration by adding key prop tied to video history ID. Fix cancel showing timeout message by passing "user-cancelled" reason through AbortController and checking it in all three executor catch blocks. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address PR #59 review — 18 bug, security, and robustness fixes Providers: - fal: don't cache failed schema fetches, remove duplicate param spread, SSRF-validate mediaUrl - gemini: remove redundant header overrides, fix nano-banana model ID - kie: module-level MAX_MEDIA_SIZE, post-download size check, upload size guard - replicate: remove duplicate param spread, validate modelId format - wavespeed: post-download size check, NaN-safe parseInt, prevent prompt overwrite Executors: - generateVideo: validate stored fallback inputs same as regular path - nanoBanana: cap imageHistory at 50 entries - splitGrid: handle img.onerror with warning + null data - videoProcessing: add FileReader onerror/onabort handlers Utilities: - connectedInputs: use ?? instead of || for outputText/template - executionUtils: guard orphan children in topological sort, validate chunk() size Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: additional PR review fixes — SSRF, data semantics, sync tracking, error propagation Providers: - replicate: add SSRF validation on mediaUrl before fetch - fal/kie/replicate/wavespeed: large-video returns data="" with url set instead of putting raw URL in data field (violates GenerationOutput.data semantic) - kie: remove stale WaveSpeed JSDoc block from kie provider file - route.ts: update all output handling to support data="" + url for large videos Executors: - generateVideoExecutor/nanoBananaExecutor: track save-generation fetch in pendingImageSyncs via new trackSaveGeneration context method so auto-save waits for server ID resolution - videoProcessingExecutors: throw errors instead of returning in validation branches (encoderSupported, insufficient videos, no video connected) so Promise.allSettled sees rejections - types.ts: add trackSaveGeneration to NodeExecutionContext interface - workflowStore: wire trackSaveGeneration into both execution context sites Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: content-type fallback, replicate polling/validation, atomic gallery append - fal.ts: Use model capabilities to determine fallback content-type (video/mp4 vs image/png) instead of defaulting to video for all models - replicate.ts: Increase polling timeout to 10 min for video models; filter output array to valid strings before URL validation - nanoBananaExecutor.ts: Replace read-modify-write on outputGallery with atomic appendOutputGalleryImage using Zustand set() callback Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: extract _buildExecutionContext to deduplicate NodeExecutionContext construction Replace identical inline context creation in executeWorkflow and regenerateNode with a single shared helper, ensuring consistent behavior across both code paths. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add keyboard shortcuts help dialog - New KeyboardShortcutsDialog component showing all available shortcuts - Accessible via ? button in header and ? key on canvas - Groups shortcuts by category: General, Add Nodes, Layout, Canvas - Auto-detects Mac vs Windows/Linux for modifier key display - Follows existing modal patterns (Escape to close, backdrop click) * feat: add keyboard shortcuts dialog and 3D GLB viewer node - Keyboard shortcuts: press ? or click keyboard icon to view all shortcuts - 3D GLB viewer: upload .GLB files, orbit/rotate, capture as image output - Fix: restore trailing newline in gemini.ts provider * fix: make Prompt node editable when connected to LLM node When a Prompt node receives text from an LLM Generate node, the text should be editable by the user. Previously, the textarea was marked as readOnly when there was an incoming text connection, preventing edits in both the main view and the expanded modal. Changes: - Track last received LLM output to detect when it changes - Only update prompt when LLM node runs again (output changes) - Allow user edits in between LLM runs - Remove readOnly restriction on textarea - Update placeholder text to indicate editability This allows users to edit the LLM-generated text, which will be replaced only when the LLM node runs again, not on every render. Fixes #1470061054246518927 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * fix: PR review fixes — lazy-load three.js, blob URL cleanup, missing integrations - Remove unused `useLoader` import from GLBViewerNode - Add useEffect cleanup to revoke blob URL on node unmount (memory leak) - Replace alert() with useToast for file validation errors - Lazy-load GLBViewerNode via next/dynamic to avoid bundling three.js for all users - Add glbViewer to ConnectionDropMenu IMAGE_SOURCE_OPTIONS - Add glbViewer case to quickstart validation createDefaultNodeData (build fix) - Restore trailing newline in gemini.ts Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address PR #64 review — blob leak, error handling, tests, docs Move @types/three to devDependencies, fix blob URL cleanup to track changes (not just unmount), add try/catch to capture and scene disposal, remove GLBViewerNode from barrel export to preserve lazy-loading, fix JSDoc, update CLAUDE.md with glbViewer node and ? shortcut, add connectedInputs and nodeDefaults tests for glbViewer. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: improve GLB viewer — fix viewport sizing, add spot light, handle labels, scroll isolation - Fix 3D viewport not filling node by adding resize={{ offsetSize: true }} for correct measurement in CSS-transformed React Flow nodes - Replace grid/axis indicators with spot light for cleaner scene - Add labeled input (3D) and output (Image) handles matching generate node style - Add native wheel event listener to prevent graph zoom/pan while scrolling to zoom 3D model - Remove redundant CSS workarounds (absolute positioning style, extra relative wrapper) - Add edge-to-edge viewport via contentClassName (removes default padding when GLB loaded) - Overlay controls bar on viewport with gradient background Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add customizable canvas navigation settings (#65) * feat: add customizable canvas navigation settings Add a new settings modal that allows users to configure canvas navigation preferences: - Pan Mode: Space + Drag (default), Middle Mouse, or Always On (ComfyUI-style) - Zoom Mode: Alt + Scroll (default), Ctrl + Scroll, or Scroll (no modifier) - Selection Mode: Click (default) or Alt + Drag Features: - Settings persist in localStorage - New canvas settings button in header (monitor icon) - Modal UI with radio button groups for each setting - React Flow props dynamically configured based on user preferences - Updated wheel event handler to respect zoom mode settings This addresses user requests for ComfyUI/TouchDesigner-style navigation where panning and zooming work without holding modifier keys. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * fix: PR #65 review — altDrag selection bug, icon, dedup, tests - Fix altDrag selection mode: use selectionKeyCode="Alt" instead of selectionOnDrag=true which made drag-select work without any key - Replace misleading video camera icon with arrows-pointing-out for canvas navigation settings button - Extract duplicated settings buttons JSX into settingsButtons variable shared by both configured/unconfigured project branches - Add defensive useEffect to sync CanvasSettingsModal state on open - Add missing semicolon in types/index.ts canvas re-export - Add localStorage tests for getCanvasNavigationSettings and saveCanvasNavigationSettings - Add integration tests for updateCanvasNavigationSettings - Fix WorkflowCanvas test mocks to include canvasNavigationSettings Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: move canvas navigation settings into Project Settings modal Consolidate canvas settings from standalone CanvasSettingsModal into a new "Canvas" tab in ProjectSetupModal. Remove "like ComfyUI" text, add Shift+Drag selection mode, and fix save button to bottom of dialog. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: remove double semicolon in types/index.ts Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com> * feat: add executeSelectedNodes with topo sort, abort, and downstream propagation Implements the "Run selected nodes" feature (PR #61) with fixes for all 8 review issues: topological ordering via groupNodesByLevel, AbortController cancellation, glbViewer case coverage, AbortError filtering, downstream consumer propagation with dedup guard, and dynamic button label. Also extracts saveLogSession helper to replace 4 inline duplicates across executeWorkflow and regenerateNode. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: 3D model saving, error handling, and node improvements - Save 3D models (GLB) to generations folder via save-generation API - Add try-catch to WaveSpeed polling loop to handle network errors - Skip downloading 3D model bodies in WaveSpeed (return URL directly) - Fix schemaUtils false-positive matching for short property names - Stabilize GenerateImageNode output handle ID (always "image") - Fix GLBViewerNode: block-body forEach lint, store-based resize - Use useRef instead of useState for PromptNode lastReceivedText - Add executeGlbViewer tests and abort signal support - Fix annotation stale pass-through when upstream image changes - Skip error status on AbortError in all executor catch blocks - Revoke glbUrl blob URLs in clearNodeImageRefs Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: require per-task commits in multi-task plans Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add Generate3DNodeData type definitions Add "generate3d" to NodeType union, Generate3DNodeData interface, Generate3DNodeDefaults, and update NodeDefaultsConfig. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add generate3d node defaults and dimensions Add default dimensions (300x300) and createDefaultNodeData case for the generate3d node type. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: create generate3d executor Extracted from nanoBananaExecutor's 3D handling code. Handles 3D model generation via /api/generate with mediaType: "3d", cost tracking, and auto-save to generations folder. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: create Generate3DNode component Dedicated node component for 3D model generation, modeled after GenerateVideoNode. Features: dynamic input handles from schema, 3D output handle, model browsing, parameter controls, status overlays. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: register generate3d node type across codebase Register in execution index, workflowStore (executeWorkflow, regenerateNode, executeSelectedNodes), nodes index, WorkflowCanvas (nodeTypes, getNodeHandles, minimap color, findCompatibleHandle). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add generate3d source output in connectedInputs Add generate3d case in getSourceOutput() to return 3D URL data, enabling downstream nodes to receive 3D model output. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: route 3D models to generate3d in ModelSearchDialog Add "3d" capability filter, update handleSelectModel to detect 3D models and create generate3d nodes with capabilities passed through, update recent models filter for 3D. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: update ConnectionDropMenu 3D source to use generate3d Change THREE_D_SOURCE_OPTIONS from nanoBanana to generate3d with cube icon and "Generate 3D" label. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: remove 3D code from GenerateImageNode and nanoBananaExecutor - Remove text-to-3d/image-to-3d from IMAGE_CAPABILITIES - Remove is3D memo and conditional handle/label styling - Remove 3D output preview block - Remove output3dUrl from model change handlers - Remove is3DModel detection and mediaType from nanoBanana executor - Remove 3D response handling from nanoBanana executor - Remove output3dUrl from NanoBananaNodeData and its defaults - Remove 3D fallback from nanoBanana in connectedInputs Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: update tests and remaining registrations for generate3d - Add Generate3DNode.test.tsx with render, handle, and output tests - Add 3D handle tests to ConnectionDropMenu.test.tsx - Add 3D model routing test to ModelSearchDialog.test.tsx - Update ModelSearchDialog test expectations for capabilities passthrough - Register generate3d in executeNode.ts dispatcher - Add generate3d to WorkflowCanvas keyboard shortcut dimensions - Add generate3d to quickstart validation (VALID_NODE_TYPES, dimensions, defaults) - Add generate3d to chat tools (VALID_NODE_TYPES, description) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: unwrap array inputs for non-array API parameters When multiple images are connected to a generation node, dynamicInputs aggregates them into arrays. Providers wrapped single values into arrays for array-typed params, but never unwrapped arrays for string-typed params, causing API failures (e.g. fal's image_url receiving an array instead of a string). Add symmetric unwrap logic across all four providers. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: move 3D from floating action bar to Generate submenu Replace top-level glbViewer button with generate3d option in the Generate combo dropdown, between Video and Text (LLM). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: hide CostIndicator when non-Gemini providers are in workflow The pricing calculator only has reliable data for Gemini models. When non-Gemini providers (fal, replicate, kie, wavespeed) are used, the displayed cost is incomplete/misleading. Add hasNonGeminiProviders() utility and use it to hide the CostIndicator entirely in that case. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add 3D capability badges to ModelSearchDialog Add text-to-3d and image-to-3d capability badge styling. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add play/run icon to LLM Generate node title bar Wire onRun and isExecuting props to BaseNode, matching the pattern used in GenerateImageNode and GenerateVideoNode. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: clear imageRef when user provides new image to prevent stale saves When a user pastes/uploads a new image into a node that already has a saved imageRef, the externalization logic incorrectly assumes the base64 is just hydrated data and discards it. Clear *Ref fields whenever new image data is set so the save logic correctly persists the new image. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: guard against undefined from empty array unwrap in fal provider Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add 3x2 grid layout option to split grid node Change layout selector from count-based to layout-based, allowing both 2x3 and 3x2 (portrait) layouts that produce 6 images. Now shows 7 layout options (2x2, 1x5, 2x3, 3x2, 2x4, 3x3, 2x5) with RxC labels. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: charlieshoelace <charlieshoelace@gmail.com> |
5 months ago |
|
|
71776b9464 |
refactor: remove 3D code from GenerateImageNode and nanoBananaExecutor
- Remove text-to-3d/image-to-3d from IMAGE_CAPABILITIES - Remove is3D memo and conditional handle/label styling - Remove 3D output preview block - Remove output3dUrl from model change handlers - Remove is3DModel detection and mediaType from nanoBanana executor - Remove 3D response handling from nanoBanana executor - Remove output3dUrl from NanoBananaNodeData and its defaults - Remove 3D fallback from nanoBanana in connectedInputs Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> |
5 months ago |
|
|
ecb5edc753 |
feat: add Generate3DNodeData type definitions
Add "generate3d" to NodeType union, Generate3DNodeData interface, Generate3DNodeDefaults, and update NodeDefaultsConfig. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> |
5 months ago |
|
|
895c848eaf
|
feat: add customizable canvas navigation settings (#65)
* feat: add customizable canvas navigation settings Add a new settings modal that allows users to configure canvas navigation preferences: - Pan Mode: Space + Drag (default), Middle Mouse, or Always On (ComfyUI-style) - Zoom Mode: Alt + Scroll (default), Ctrl + Scroll, or Scroll (no modifier) - Selection Mode: Click (default) or Alt + Drag Features: - Settings persist in localStorage - New canvas settings button in header (monitor icon) - Modal UI with radio button groups for each setting - React Flow props dynamically configured based on user preferences - Updated wheel event handler to respect zoom mode settings This addresses user requests for ComfyUI/TouchDesigner-style navigation where panning and zooming work without holding modifier keys. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * fix: PR #65 review — altDrag selection bug, icon, dedup, tests - Fix altDrag selection mode: use selectionKeyCode="Alt" instead of selectionOnDrag=true which made drag-select work without any key - Replace misleading video camera icon with arrows-pointing-out for canvas navigation settings button - Extract duplicated settings buttons JSX into settingsButtons variable shared by both configured/unconfigured project branches - Add defensive useEffect to sync CanvasSettingsModal state on open - Add missing semicolon in types/index.ts canvas re-export - Add localStorage tests for getCanvasNavigationSettings and saveCanvasNavigationSettings - Add integration tests for updateCanvasNavigationSettings - Fix WorkflowCanvas test mocks to include canvasNavigationSettings Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: move canvas navigation settings into Project Settings modal Consolidate canvas settings from standalone CanvasSettingsModal into a new "Canvas" tab in ProjectSetupModal. Remove "like ComfyUI" text, add Shift+Drag selection mode, and fix save button to bottom of dialog. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: remove double semicolon in types/index.ts Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com> |
5 months ago |
|
|
3ebaae82de |
feat: improve GLB viewer — fix viewport sizing, add spot light, handle labels, scroll isolation
- Fix 3D viewport not filling node by adding resize={{ offsetSize: true }} for correct measurement in CSS-transformed React Flow nodes
- Replace grid/axis indicators with spot light for cleaner scene
- Add labeled input (3D) and output (Image) handles matching generate node style
- Add native wheel event listener to prevent graph zoom/pan while scrolling to zoom 3D model
- Remove redundant CSS workarounds (absolute positioning style, extra relative wrapper)
- Add edge-to-edge viewport via contentClassName (removes default padding when GLB loaded)
- Overlay controls bar on viewport with gradient background
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
5 months ago |
|
|
886525aa76 |
feat: add keyboard shortcuts dialog and 3D GLB viewer node
- Keyboard shortcuts: press ? or click keyboard icon to view all shortcuts - 3D GLB viewer: upload .GLB files, orbit/rotate, capture as image output - Fix: restore trailing newline in gemini.ts provider |
5 months ago |
|
|
3055143cf1 |
fix: apply loopCount in videoStitch regenerateNode path
The loopCount (1x/2x/3x) feature was only applied in executeWorkflow() but not in regenerateNode(), which is the code path triggered by clicking the "Stitch" button. This adds the blob duplication logic to both code paths and includes the UI controls and type definitions. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> |
5 months ago |
|
|
4b758f14f1 |
feat(quick-004): add easeCurve handle type and wire up connection routing
- Add inheritedFrom field to EaseCurveNodeData interface - Add easeCurve to HandleType union - Update getHandleType, getNodeHandles, isValidConnection for easeCurve - Add easeCurve extraction in getConnectedInputs - Propagate parent bezierHandles/easingPreset in both execution paths - Fix validation.ts default data for easeCurve node Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> |
5 months ago |
|
|
4dafbb39d4 |
feat(42-01): add useApplySpeedCurve hook and EaseCurveNodeData type
- useApplySpeedCurve hook with MediaBunny encoding pipeline (no frame blending, no preview mode) - Standalone applySpeedCurveAsync export for store/API usage - SpeedCurveProgress type for progress tracking - EaseCurveNodeData interface with bezierHandles, easingPreset, outputDuration, status fields - "easeCurve" added to NodeType union and WorkflowNodeData - Default dimensions (340x480) and node data (easeInOutSine preset) registered - Shared applySpeedCurveCore extracts common logic between hook and standalone function Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> |
5 months ago |
|
|
62244c52c2 |
feat(41-01): install MediaBunny and define AudioInput/VideoStitch node types
- Install mediabunny@^1.28.0 for video processing - Add audioInput and videoStitch to NodeType union - Add AudioInputNodeData interface (audioFile, filename, duration, format) - Add VideoStitchClip interface for filmstrip items - Add VideoStitchNodeData interface (clips, clipOrder, outputVideo, progress, encoderSupported) - Update WorkflowNodeData union to include new node types - Extend HandleType to include audio and video handles - Create src/lib/video-encoding.ts with AVC encoding config helpers |
5 months ago |
|
|
f0710bf830 |
Add WaveSpeed provider integration
|
5 months ago |
|
|
fc95d9fc53 |
feat: refactor PromptConstructor, add project setup flow, improve gallery
- Extract autocomplete logic to usePromptAutocomplete hook - Add PromptConstructorEditorModal with portal rendering - Sync PromptConstructor outputText reactively for downstream nodes - Add headerButtons prop to BaseNode for custom header actions - Rename Blank Canvas to New Project with ProjectSetupModal integration - Auto-push generated images to connected OutputGallery nodes - Deduplicate images in OutputGallery during workflow execution - Move PromptNode variable button to header with hover animation - Extract AvailableVariable interface to types/nodes.ts - Update tests for onNewProject rename Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> |
5 months ago |
|
|
e3c8dfaafe |
feat(40-03): install react-compare-slider and register ImageCompare node type
- Install react-compare-slider dependency - Add imageCompare to NodeType union - Add ImageCompareNodeData interface (imageA, imageB fields) - Add to WorkflowNodeData union type - Register in nodeDefaults with 400x360 dimensions - Add to WorkflowCanvas nodeTypes and minimap (teal color) - Add to ConnectionDropMenu IMAGE_TARGET_OPTIONS - Add executeWorkflow case to assign images[0] to imageA, images[1] to imageB - Export ImageCompareNode from components/nodes/index - Add to validation.ts DEFAULT_DIMENSIONS and createDefaultNodeData |
5 months ago |
|
|
af9f88f122 |
feat(40-04): add variable system to PromptNode and define PromptConstructor types
- Add variableName field to PromptNodeData (optional, backward compatible) - Add promptConstructor to NodeType union - Add PromptConstructorNodeData interface (template, outputText, unresolvedVars) - Add to WorkflowNodeData union type - Add promptConstructor to defaultNodeDimensions (340x280) - Add createDefaultNodeData case for promptConstructor - Modified PromptNode with @ variable naming dialog using createPortal - Variable name validation: alphanumeric + underscore, max 30 chars - Blue @ icon when variableName set, dimmed when not set - Dialog shows variable name input, preview, Save/Clear buttons - Register PromptConstructorNode in WorkflowCanvas nodeTypes - Add promptConstructor minimap color (#f472b6 pink) - Add to TEXT_TARGET_OPTIONS and TEXT_SOURCE_OPTIONS in ConnectionDropMenu - Add getConnectedInputs support for promptConstructor outputText - Add executeWorkflow case for promptConstructor: - Finds connected prompt nodes via text edges - Builds variable map from variableName + prompt values - Resolves template by replacing @variableName with values - Tracks unresolved variables in unresolvedVars array - Stores outputText and unresolvedVars on node data - Export PromptConstructorNode from components/nodes/index.ts - Update duplicate defaultDimensions in WorkflowCanvas and quickstart validation |
5 months ago |
|
|
a5979c6c7d |
feat(40-01): define OutputGallery types and register node in all touchpoints
- Add outputGallery to NodeType union in types/nodes.ts - Add OutputGalleryNodeData interface with images array field - Add outputGallery to WorkflowNodeData union - Register in nodeDefaults: dimensions 320x360, default data with empty images array - Export OutputGalleryNode from nodes/index.ts - Register outputGallery in WorkflowCanvas nodeTypes with pink minimap color (#ec4899) - Add outputGallery to ConnectionDropMenu IMAGE_TARGET_OPTIONS with grid icon - Add outputGallery case to executeWorkflow in workflowStore - Add outputGallery to getNodeHandles (image input, no outputs) - Add outputGallery dimensions to keyboard shortcut default dimensions Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> |
5 months ago |
|
|
d2ea913784 |
feat(40-02): add image connection sequence numbering
- Add createdAt timestamp to WorkflowEdgeData interface - Store createdAt on edge creation in onConnect and addEdgeWithType - Add getImageSequenceNumber helper to EdgeToolbar - Display "Image N" label for image connections with 2+ edges to same target - Sequence numbers based on createdAt for stable ordering - Single connections and text connections show no numbering |
5 months ago |
|
|
a9cbb11d56 |
feat: add Kie.ai provider integration
Add Kie.ai as a new provider for image and video generation: Image models (8): - z-image, seedream/4.5-text-to-image, seedream/4.5-edit - nano-banana-pro, gpt-image/1.5-text-to-image, gpt-image/1.5-image-to-image - google/nano-banana, google/nano-banana-edit Video models (11): - sora-2-text-to-video, sora-2-image-to-video - sora-2-pro-text-to-video, sora-2-pro-image-to-video - veo3_fast, veo3, bytedance/seedance-1.5-pro - kling-2.6/text-to-video, kling-2.6/image-to-video - wan/2-6-text-to-video, wan/2-6-image-to-video Key changes: - Add "kie" to ProviderType union - Add generateWithKie() with image upload and task polling - Add hardcoded model list and schemas (no discovery API) - Update workflow store for API key handling - Update UI components with Kie provider badge Co-Authored-By: Claude <noreply@anthropic.com> |
6 months ago |
|
|
e558777a35 |
feat(31-02): export chat types from central index
- Add chat.ts to type re-export hub - Follows existing pattern (quickstart, nodes, etc.) |
6 months ago |
|
|
b263c031b8 |
feat(31-02): create chat types for conversation interface
- ChatRole, ChatMessage, ConversationState types - ChatRequest for /api/chat endpoint - Minimal types (Vercel AI SDK provides its own) |
6 months ago |
|
|
602130a18b |
feat(31-01): define WorkflowProposal types for reviewable workflow structure
Add types for the workflow proposal system: - ProposedNode: node with purpose, title, and suggested settings - ProposedConnection: connection with human-readable description - ProposedGroup: optional grouping with purpose description - WorkflowProposal: complete reviewable workflow structure These types enable the LLM to propose workflow structure before generating full workflow JSON, allowing user review and editing. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> |
6 months ago |
|
|
9b4718e279 |
feat: Template Explorer, Comment Navigation, and Output Node Improvements
## Template Explorer Enhancements - Add rich metadata and thumbnails for community workflows - Create communityWorkflows.ts config for workflow metadata - Reuse TemplateCard for community workflows with tag filtering - Search now includes workflow descriptions ## Comment Navigation System - Add comment navigation icon in header with unviewed count badge - Navigate between nodes with comments using prev/next controls - Tooltips show comment preview on hover ## Output Node Improvements - Add custom filename and createDirectory options for output saves - Remove default React Flow styling from output nodes - Fix video output node connections - Preserve node height on resize ## Image Handling Fixes - Resolve image history race condition and duplicate images on save - Preserve image history IDs when saving to new directory - Verify outputImageRef matches selected history index on save - Persist useExternalImageStorage setting in workflow config - Paste images directly into selected imageInput nodes ## Model & Generation Fixes - Use selectedModel.modelId for Gemini generation - Return 200 with notFound flag instead of 404 for missing files ## Other - Add git-lfs tracking for large workflow files - Remove deprecated example workflows Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> |
6 months ago |