Always display parameters inline instead of behind a collapsible
"Parameters" header. The toggle added unnecessary interaction cost.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove provider and model dropdowns from the video control panel,
replacing them with the cleaner model name + provider display block
with Browse button — matching the image node's updated layout.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add hoveredNodeId to store, set from BaseNode mouse events, read in
FloatingNodeHeader. Controls now appear when hovering any part of
the node, not just the floating header strip.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Bump ControlPanel from z-[50] to z-[90] so the layered box-shadow
paints in front of the React Flow canvas stacking context, not
behind it. Still below z-[100] used by modals and toolbars.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Apply Tobias Ahlin / Josh Comeau layered shadow technique: each
layer doubles offset and blur (1/2/4/8/16/32px) with decreasing
opacity. Each layer covers a narrow distance band so no single
layer interpolates over a large range, eliminating banding.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
CSS linear-gradient bands on large areas due to 8-bit color depth.
box-shadow is compositor-rendered and produces smooth falloff without
visible stepping artifacts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the narrow hard-edged gradient strip with a wide, smooth
multi-stop gradient that extends behind the panel for a natural
shadow falloff instead of a stepped/hard edge.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- LLMGenerateNode: Remove inline provider/model/parameter controls
- LLMGenerateNode: Convert to full-bleed layout with fullBleed prop
- LLMGenerateNode: Show only text output area in node body
- LLMGenerateNode: Keep floating action buttons (copy, regenerate, clear)
- ControlPanel: Add Max Tokens slider to LLMControls (256-16384 range)
- ControlPanel: Add shadow/gradient overlay on left edge of panel
- WorkflowCanvas: Fix type errors with node.data union types (Rule 1 bug fix)
Implement custom drag handling on FloatingNodeHeader so users can
reposition nodes by clicking and dragging the header bar. Supports
multi-selection dragging and properly ignores interactive elements
(buttons, inputs). Adds cursor-grab to indicate draggability.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reduce vertical padding from py-2 to py-1 and offset from -36 to -26
so the title sits closer to the node top edge.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Handles were inside the content div that had overflow-clip, causing them
to be clipped. Move clipping to a wrapper around just the media content
so handles remain unclipped — same pattern as GenerateImage/VideoNode.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The content div's `relative` positioning creates a stacking context that
paints over the handles. Adding zIndex: 10 matches the pattern used by
GenerateImageNode and GenerateVideoNode.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use overflow-visible unconditionally on BaseNode outer wrapper so
handles are never clipped. Content clipping is already handled by each
node's content div (overflow-hidden/overflow-clip). Add rounded-lg to
OutputNode's content container for rounded corners on edge-to-edge media.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use overflow-visible instead of overflow-clip for fullBleed nodes so
handle circles and labels extend beyond the node boundary. Add
overflow-hidden rounded-lg to image/video content containers to
preserve rounded corners on media.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace dashed-border selector assertions with text-based assertions
since full-bleed nodes use a background fill instead of a dashed
border for their empty state.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Video fills the entire node with no padding or chrome. Carousel
controls overlay at the bottom with backdrop blur (matching
GenerateImageNode pattern). Removed inline parameters since they
are displayed in the floating panel. Hidden ModelParameters kept
for schema-loading side effect (dynamic handles). All handles use
z-index to stay visible over content.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Textarea fills the entire node with no visible border. Available
variables display as a fixed semi-transparent footer pinned at the
bottom. Unresolved variables warning overlays at the top. Autocomplete
dropdown remains functional. Handles use z-index to stay visible.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Textarea fills the entire node with no visible border or chrome.
Variable name badge overlays at the bottom-left. Handles use
z-index to stay visible over the content surface.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Handles were painted behind the full-bleed image content since they
share the same stacking context. Adding zIndex: 10 to all handles
and their labels ensures they render on top of the image.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The header width calculation was preferring node.style.width (set at
creation time, often stale) over node.measured.width (actual DOM size).
This caused headers to be narrower than nodes after image generation
or manual resizing. Now uses measured → style → default fallback chain,
matching the existing pattern used elsewhere in the file.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace gap-2 with justify-between so header controls (comment,
expand, run) stay flush-right against the node boundary on all widths.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use node.style.width (number or string), node.measured.width, or
default dimensions — in that priority order. Headers now match the
actual node width after user resize.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- FloatingNodeHeader: Controls (comment, expand, run) now sit flush-right
against the node edge with tighter spacing.
- ControlPanel: Remove "Model" label. Model name sits directly under the
settings title, separated by a horizontal divider.
- Add new-tab link icon next to provider name that opens model details page.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- ControlPanel: Replace provider/model dropdowns with model name text +
Browse button. Fixed width, no horizontal scroll.
- GenerateImageNode: Carousel controls now overlay on image bottom with
semi-transparent dark background for legibility.
- BaseNode: Add fullBleed prop for borderless mode. Image IS the node -
no visible container, border, or padding.
- GenerateImageNode uses fullBleed mode. Empty state uses subtle fill
instead of dashed border.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove header props (title, customTitle, comment, etc.) from BaseNode calls
- Apply full-bleed content pattern with contentClassName
- Replace dashed border empty states with subtle fills (bg-neutral-900/40)
- Move floating UI elements to absolute positioning
Part of batch update for all 21 remaining node files.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Removed header props from encoder-not-supported BaseNode
- Added contentClassName for full-bleed pattern
- 2 more BaseNode instances in this file still need updating
- Note: Other node edits were reverted by linter/formatter
- Removed aspect ratio, resolution, and search toggles from node body
- Removed ModelParameters component from node body
- Parameters will be shown in ControlPanel (Plan 02 integration)
- Image preview now has room to fill node in full-bleed pattern
Task 1 partial progress: GenerateImageNode parameters removed, 24 more nodes need header props removed and full-bleed content applied
- ImageInputNode: remove header props, use contentClassName with overflow-clip, full-bleed image with object-cover
- OutputNode: same full-bleed pattern, floating download button overlays content
- nodeDimensions: add calculateNodeSizeForFullBleed for nodes without header chrome
- Empty states use subtle bg-neutral-900/40 fill with centered icons (no dashed borders)
Task 1 in progress - 23 more nodes need same pattern applied
- Created ControlPanel component rendering on right side of viewport
- Fixed position with pointer-events-none wrapper, auto scrolling
- Filters to single selected configurable node (7 types)
- Placeholder controls for each node type (Task 2 will implement)
- Integrated into WorkflowCanvas after ChatPanel
- Panel appears/disappears based on node selection
- Import ViewportPortal from @xyflow/react
- Add NODE_TITLES mapping for all node types
- Create getNodeTitle helper (checks selectedModel.displayName for generate nodes)
- Create getNodeTitlePrefix helper (returns ProviderBadge for nodes with provider)
- Wire up handleCustomTitleChange and handleCommentChange callbacks
- Render FloatingNodeHeader for each node inside ViewportPortal
- Headers positioned above nodes, width matches node width
- onExpand/onRun callbacks not wired yet (will be added in Plan 03)
- Comment editing and title editing fully functional
The server-reported availableProviders were only set on fresh API calls.
When models were served from localStorage cache, the provider filter
icons reverted to only showing Gemini/fal.ai. Now availableProviders
is stored in and restored from the model cache.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The ModelSearchDialog only checked client-side localStorage keys to
determine available providers, missing providers configured via .env
server-side vars. Now the /api/models endpoint returns an
availableProviders array and the dialog merges both sources.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Create shared getModelPageUrl utility in src/utils/providerUrls.ts
- Add external-link icon to GenerateImageNode header (before Browse button)
- Add external-link icon to GenerateVideoNode header (before Browse button)
- Add external-link icon to Generate3DNode header (before Browse button)
- Icon only appears when model is selected and provider has a page URL
- Gemini models show no link (returns null); Replicate/fal/Kie/WaveSpeed show links
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Gemini and fal.ai always shown (always-available providers)
- Replicate, Kie.ai, WaveSpeed icons only shown when API key is configured
- Reset provider filter to "all" if selected provider becomes unavailable
- Fix WaveSpeed active color from orange to purple (matching its badge color)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove Annotate button assertion from basic rendering test
- Remove Annotate click test case
- Add All Nodes Menu test suite (4 tests: render, open, select, close)
- Update Browse Models tests for "All models" text label
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove Annotate shortcut button from action bar
- Add AllNodesMenu dropdown with all 22 node types in 6 categories
- Replace magnifying glass Browse models icon with "All models" text button
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ConnectionDropMenu tests expected stale last items and item counts after
Router, Switch, and Conditional Switch were added. WorkflowCanvas tests
were missing dimmedNodeIds from the mock store state.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
After disconnecting an image edge, the target node's inputImages data
was not cleared. On regeneration, useStoredFallback would pick up the
stale images and send them to the API, causing results to still resemble
the old reference. Now removeEdge and onEdgesChange call
clearStaleInputImages to reset inputImages when no image-source edges
remain on the target node.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The else-if chain in blockedTypes detection meant that when a switch/
conditionalSwitch node was itself dimmed but had an enabled output,
the finalDimmed.has(source) check was skipped entirely. Changed the
dimmed-source check from else-if to a standalone if so it runs for
all source types, including switch and conditionalSwitch.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Instead of setting inputSchema via useEffect (which runs after render),
set it directly in handleModelChange and handleBrowseModelSelect. This
ensures dynamic handles (including image-0 for I2V models) are rendered
in the same update cycle as model selection, preventing connection issues
where the image handle wouldn't accept connections.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Instead of an inline text field, negative prompt is now a proper text
handle on the node that can receive connections from prompt/LLM nodes.
Updates the API route to merge dynamicInputs.negative_prompt into the
Veo parameters, and aligns the model schema definition accordingly.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>