diff --git a/.planning/STATE.md b/.planning/STATE.md
index 0041879a..0f92ef8c 100644
--- a/.planning/STATE.md
+++ b/.planning/STATE.md
@@ -9,19 +9,19 @@ See: .planning/PROJECT.md (updated 2026-01-09)
## Current Position
-Phase: 35 of 35 (Large Workflow Handling)
-Plan: 3 of 3 in current phase
-Status: Complete
-Last activity: 2026-01-31 - Completed plan 03 (Client-side wiring and selection chip)
+Phase: 40 of 40 (Node Enhancements)
+Plan: 2 of 4 in current phase
+Status: In Progress
+Last activity: 2026-02-01 - Completed 40-02-PLAN.md (Connection numbering)
-Progress: ██████████ 100%
+Progress: ███████████░ 94%
## Performance Metrics
**Velocity:**
-- Total plans completed: 37
-- Average duration: 6.9 min
-- Total execution time: 4.25 hours
+- Total plans completed: 38
+- Average duration: 6.7 min
+- Total execution time: 4.28 hours
**By Phase:**
@@ -57,10 +57,11 @@ Progress: ██████████ 100%
| 33. Workflow Edit Safety | 2/2 | 5 min | 5 min |
| 34. Agentic Workflow Editing | 3/3 | 13 min | 4.3 min |
| 35. Large Workflow Handling | 3/3 | 18 min | 6 min |
+| 40. Node Enhancements | 2/4 | 2 min | 2 min |
**Recent Trend:**
-- Last 5 plans: 8 min, <1 min, 10 min, 3 min, 10 min, 5 min
-- Trend: Phase 35 complete - large workflow handling with selection-aware chat context (TDD + execution)
+- Last 5 plans: <1 min, 10 min, 3 min, 10 min, 5 min, 2 min
+- Trend: Phase 40 in progress - node enhancements (connection numbering complete)
## Accumulated Context
@@ -180,6 +181,9 @@ Recent decisions affecting current work:
- Ref fields (imageRef, outputImageRef, etc.) completely removed from LLM context
- All node parameters, positions, and model settings preserved in stripped context
- Enhanced WorkflowContext includes full StrippedNode[] with all non-binary data
+- createdAt timestamp on edge data for stable connection ordering
+- Image edge sequence numbers shown only when 2+ connections to same target
+- EdgeToolbar displays "Image N" labels for multi-image connections
### Deferred Issues
@@ -215,7 +219,7 @@ Recent decisions affecting current work:
## Session Continuity
-Last session: 2026-01-31
-Stopped at: Completed Phase 35 Plan 03 (Client-side wiring and selection chip) - Phase 35 COMPLETE
+Last session: 2026-02-01
+Stopped at: Completed 40-02-PLAN.md (Connection numbering)
Resume file: None
-Next action: Phase 35 completes Milestone v1.4 (Agentic Workflow Builder). Ready for Milestone v1.5 (Store Refactoring) or new priorities.
+Next action: Continue Phase 40 - 2 more plans remaining (OutputGallery, ImageCompare, PromptConstructor)
diff --git a/src/components/ConnectionDropMenu.tsx b/src/components/ConnectionDropMenu.tsx
index 7f460ef5..9f4ff10f 100644
--- a/src/components/ConnectionDropMenu.tsx
+++ b/src/components/ConnectionDropMenu.tsx
@@ -70,6 +70,15 @@ const IMAGE_TARGET_OPTIONS: MenuOption[] = [
),
},
+ {
+ type: "outputGallery",
+ label: "Output Gallery",
+ icon: (
+
+ ),
+ },
];
const TEXT_TARGET_OPTIONS: MenuOption[] = [
diff --git a/src/components/WorkflowCanvas.tsx b/src/components/WorkflowCanvas.tsx
index c313268e..557ef427 100644
--- a/src/components/WorkflowCanvas.tsx
+++ b/src/components/WorkflowCanvas.tsx
@@ -28,6 +28,7 @@ import {
LLMGenerateNode,
SplitGridNode,
OutputNode,
+ OutputGalleryNode,
} from "./nodes";
import { EditableEdge, ReferenceEdge } from "./edges";
import { ConnectionDropMenu, MenuAction } from "./ConnectionDropMenu";
@@ -52,6 +53,7 @@ const nodeTypes: NodeTypes = {
llmGenerate: LLMGenerateNode,
splitGrid: SplitGridNode,
output: OutputNode,
+ outputGallery: OutputGalleryNode,
};
const edgeTypes: EdgeTypes = {
@@ -96,6 +98,8 @@ const getNodeHandles = (nodeType: string): { inputs: string[]; outputs: string[]
return { inputs: ["image"], outputs: ["reference"] };
case "output":
return { inputs: ["image"], outputs: [] };
+ case "outputGallery":
+ return { inputs: ["image"], outputs: [] };
default:
return { inputs: [], outputs: [] };
}
@@ -887,6 +891,7 @@ export function WorkflowCanvas() {
llmGenerate: { width: 320, height: 360 },
splitGrid: { width: 300, height: 320 },
output: { width: 320, height: 320 },
+ outputGallery: { width: 320, height: 360 },
};
const dims = defaultDimensions[nodeType];
addNode(nodeType, { x: centerX - dims.width / 2, y: centerY - dims.height / 2 });
@@ -1374,6 +1379,8 @@ export function WorkflowCanvas() {
return "#f59e0b";
case "output":
return "#ef4444";
+ case "outputGallery":
+ return "#ec4899";
default:
return "#94a3b8";
}
diff --git a/src/components/nodes/index.ts b/src/components/nodes/index.ts
index acb08ccf..21988113 100644
--- a/src/components/nodes/index.ts
+++ b/src/components/nodes/index.ts
@@ -6,4 +6,5 @@ export { GenerateVideoNode } from "./GenerateVideoNode";
export { LLMGenerateNode } from "./LLMGenerateNode";
export { SplitGridNode } from "./SplitGridNode";
export { OutputNode } from "./OutputNode";
+export { OutputGalleryNode } from "./OutputGalleryNode";
export { GroupNode } from "./GroupNode";
diff --git a/src/store/utils/nodeDefaults.ts b/src/store/utils/nodeDefaults.ts
index 05c19b76..9443c17b 100644
--- a/src/store/utils/nodeDefaults.ts
+++ b/src/store/utils/nodeDefaults.ts
@@ -8,6 +8,7 @@ import {
LLMGenerateNodeData,
SplitGridNodeData,
OutputNodeData,
+ OutputGalleryNodeData,
WorkflowNodeData,
GroupColor,
SelectedModel,
@@ -27,6 +28,7 @@ export const defaultNodeDimensions: Record {
image: null,
outputFilename: "",
} as OutputNodeData;
+ case "outputGallery":
+ return {
+ images: [],
+ } as OutputGalleryNodeData;
}
};
diff --git a/src/store/workflowStore.ts b/src/store/workflowStore.ts
index 81c72c8f..37d2fc62 100644
--- a/src/store/workflowStore.ts
+++ b/src/store/workflowStore.ts
@@ -1774,6 +1774,12 @@ export const useWorkflowStore = create((set, get) => ({
}
break;
}
+
+ case "outputGallery": {
+ const { images } = getConnectedInputs(node.id);
+ updateNodeData(node.id, { images });
+ break;
+ }
}
}
diff --git a/src/types/nodes.ts b/src/types/nodes.ts
index 8bb23dd1..d167d161 100644
--- a/src/types/nodes.ts
+++ b/src/types/nodes.ts
@@ -30,7 +30,8 @@ export type NodeType =
| "generateVideo"
| "llmGenerate"
| "splitGrid"
- | "output";
+ | "output"
+ | "outputGallery";
/**
* Node execution status
@@ -165,6 +166,13 @@ export interface OutputNodeData extends BaseNodeData {
outputFilename?: string; // Custom filename for saved outputs (without extension)
}
+/**
+ * Output Gallery node - displays scrollable thumbnail grid of images with lightbox
+ */
+export interface OutputGalleryNodeData extends BaseNodeData {
+ images: string[]; // Array of base64 data URLs from connected nodes
+}
+
/**
* Split Grid node - splits image into grid cells for parallel processing
*/
@@ -202,7 +210,8 @@ export type WorkflowNodeData =
| GenerateVideoNodeData
| LLMGenerateNodeData
| SplitGridNodeData
- | OutputNodeData;
+ | OutputNodeData
+ | OutputGalleryNodeData;
/**
* Workflow node with typed data (extended with optional groupId)