Browse Source

feat(42-03): register EaseCurve in canvas, validation, and menus

- Import and register EaseCurveNode in nodeTypes
- Add easeCurve case to getNodeHandles (video in, video out)
- Add easeCurve to isValidConnection video target list
- Add easeCurve video handle mapping in handleMenuSelect
- Add amber minimap color (#f59e0b) for easeCurve nodes
- Add Ease Curve to VIDEO_TARGET_OPTIONS and VIDEO_SOURCE_OPTIONS

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
handoff-20260429-1057
shrimbly 5 months ago
parent
commit
216f9613f0
  1. 18
      src/components/ConnectionDropMenu.tsx
  2. 12
      src/components/WorkflowCanvas.tsx

18
src/components/ConnectionDropMenu.tsx

@ -210,6 +210,15 @@ const VIDEO_TARGET_OPTIONS: MenuOption[] = [
</svg>
),
},
{
type: "easeCurve",
label: "Ease Curve",
icon: (
<svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
<path strokeLinecap="round" strokeLinejoin="round" d="M3 13.125C3 12.504 3.504 12 4.125 12h2.25c.621 0 1.125.504 1.125 1.125v6.75C7.5 20.496 6.996 21 6.375 21h-2.25A1.125 1.125 0 013 19.875v-6.75zM9.75 8.625c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125v11.25c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 01-1.125-1.125V8.625zM16.5 4.125c0-.621.504-1.125 1.125-1.125h2.25C20.496 3 21 3.504 21 4.125v15.75c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 01-1.125-1.125V4.125z" />
</svg>
),
},
{
type: "generateVideo",
label: "Generate Video",
@ -250,6 +259,15 @@ const VIDEO_SOURCE_OPTIONS: MenuOption[] = [
</svg>
),
},
{
type: "easeCurve",
label: "Ease Curve",
icon: (
<svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
<path strokeLinecap="round" strokeLinejoin="round" d="M3 13.125C3 12.504 3.504 12 4.125 12h2.25c.621 0 1.125.504 1.125 1.125v6.75C7.5 20.496 6.996 21 6.375 21h-2.25A1.125 1.125 0 013 19.875v-6.75zM9.75 8.625c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125v11.25c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 01-1.125-1.125V8.625zM16.5 4.125c0-.621.504-1.125 1.125-1.125h2.25C20.496 3 21 3.504 21 4.125v15.75c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 01-1.125-1.125V4.125z" />
</svg>
),
},
];
// Audio target options (nodes that accept audio input)

12
src/components/WorkflowCanvas.tsx

@ -33,6 +33,7 @@ import {
OutputGalleryNode,
ImageCompareNode,
VideoStitchNode,
EaseCurveNode,
} from "./nodes";
import { EditableEdge, ReferenceEdge } from "./edges";
import { ConnectionDropMenu, MenuAction } from "./ConnectionDropMenu";
@ -63,6 +64,7 @@ const nodeTypes: NodeTypes = {
outputGallery: OutputGalleryNode,
imageCompare: ImageCompareNode,
videoStitch: VideoStitchNode,
easeCurve: EaseCurveNode,
};
const edgeTypes: EdgeTypes = {
@ -118,6 +120,8 @@ const getNodeHandles = (nodeType: string): { inputs: string[]; outputs: string[]
return { inputs: ["image"], outputs: [] };
case "videoStitch":
return { inputs: ["video", "audio"], outputs: ["video"] };
case "easeCurve":
return { inputs: ["video"], outputs: ["video"] };
default:
return { inputs: [], outputs: [] };
}
@ -300,7 +304,7 @@ export function WorkflowCanvas() {
if (!targetNode) return false;
const targetNodeType = targetNode.type;
if (targetNodeType === "generateVideo" || targetNodeType === "videoStitch" || targetNodeType === "output") {
if (targetNodeType === "generateVideo" || targetNodeType === "videoStitch" || targetNodeType === "easeCurve" || targetNodeType === "output") {
// For output node, we allow video even though its handle is typed as "image"
// because output node can display both images and videos
return true;
@ -758,6 +762,10 @@ export function WorkflowCanvas() {
// VideoStitch has dynamic video-N inputs and a video output
targetHandleId = "video-0";
sourceHandleIdForNewNode = "video";
} else if (nodeType === "easeCurve") {
// EaseCurve accepts video input and outputs video
targetHandleId = "video";
sourceHandleIdForNewNode = "video";
} else if (nodeType === "generateVideo") {
// GenerateVideo outputs video
sourceHandleIdForNewNode = "video";
@ -1535,6 +1543,8 @@ export function WorkflowCanvas() {
return "#14b8a6";
case "videoStitch":
return "#f97316";
case "easeCurve":
return "#f59e0b"; // amber-500
default:
return "#94a3b8";
}

Loading…
Cancel
Save