Repository files navigation

Node Banana (Capoom Fork)

A fork of Shrimbly's Node Banana with additional nodes, features, and fixes for production use on a LAN-accessible workstation.

Upstream: This fork tracks shrimbly/node-banana as the upstream remote. All additions are layered on top of the upstream feature set.

Architecture note (splat viewer): The Gaussian Splat Viewer is a separate project (gitcapoom/splat-viewer) — a dependency, never embedded in this repo. Run npm run viewer:install to clone + build it into a gitignored public/_viewer/ folder that /viewer serves directly; alternatively point SPLAT_VIEWER_ORIGIN at a hosted build to reverse-proxy it. See Gaussian Splat Viewer setup.

Node Banana Screenshot


What's Different from Upstream

New Nodes

NodeTypeDescription
Video InputInputLoad video files (MP4, WebM) from disk with thumbnail preview and lazy playback
RotoProcessBezier/polygon shape roto editor producing mattes (full-screen Konva editor, invert toggle)
CompositeProcessFloating-point clone of Nuke's Merge node: 22 merge ops, per-input affine transforms, external BG/FG alpha pins, matte pin, premultiply/swap/opacity controls, per-input blur/defocus filters
BlurProcessGPU blur with five filters (Gaussian, Box, Motion, Zoom, Spin), an optional matte input gating where the blur lands, invert + mix controls
DotProcessSmall circular reroute point for organising edge routing — ctrl+click any edge to insert one; selectable and deletable like any node
ViewerProcessLive tap on the graph — reflects upstream edits in realtime without a run (edit a roto matte and the composite lands here), and is selectable as a source from any node's full-screen view
Color GradeProcessNuke-style grade (blackpoint/whitepoint/lift/gain/multiply/offset/gamma) on the float GPU chain
HSV Color CorrectProcessHue shift / saturation / value on the float GPU chain
Contrast AdjustProcessS-curve contrast with roll-off and pivot on the float GPU chain
Image CropProcessPersistent relative-coordinate crop region with aspect lock
MirrorProcessHorizontal / vertical flips
ReformatProcessResize to target resolution with fill/fit modes and filter choice
Cube ⇄ Pano / Cube ⇄ FacesProcessCubemap cross ↔ equirectangular, and cubemap ↔ six face images
Pano ShiftProcessHorizontal panorama shift with seam wrap-around
Upscale (Grid)GenerateGrid-split upscaling through generator models
Image to SplatGenerateSingle image → 3D Gaussian Splat (feeds the splat viewer)
Sphere Light RenderGenerateLocally-rendered lit grey sphere from rotation/elevation/intensity (lighting reference)
Video CompareProcessSide-by-side video comparison with three modes: Slide (wipe), Blend (opacity), and Difference (pixel diff). Synced playback with wait-for-both restart
Image Compare (enhanced)ProcessAdded Blend and Difference modes with opacity control (upstream only has the slider)
GLB Viewer (enhanced)ViewerThree.js-based 3D model viewer with orbit controls, auto-rotation, background pin visibility toggle, and file persistence across workflow save/reload
Gaussian Splat Viewer (enhanced)ViewerRenamed from "SPZ Viewer". Added XYZ transform controls, camera animation timeline with keyframes, video export (H264/WebM), depth map capture (float-precision), and COLMAP export
Output Node (enhanced)OutputUniversal input handle accepting all media types. "Output Now" button for one-click export with sidecar JSON. Blob URL conversion for 3D files. Performance-optimized selectors

New Features

Float Color Pipeline

  • Color Grade / HSV / Contrast / Blur / Composite chain through 16-bit float GPU textures (WebGL2), so out-of-range values survive between nodes — no 8-bit clamp until the final consumer
  • Live in-node GPU previews at 60 fps; 8-bit PNG committed only after sliders settle
  • Composite inputs can each be pre-filtered (blur/defocus) before the merge, float-preserving

Dynamic Model Input Pins

  • Generator nodes grow input pins from the selected model's schema (mask, control image, multiple image slots, etc.)
  • Stable slot ids survive model switches and reloads; a single edge-conformance pass guarantees edges always match rendered pins (no ghost edges)

Reliability

  • Crash-safe workflow saves: writes go to a temp file, fsync, then atomic rename; the previous good save is kept as a rolling .bak; the loader falls back to the .bak (with a warning toast) if the main file is ever corrupt
  • Auto-save handles multi-hundred-MB media via chunked content hashing and URL-only handling for large provider videos
  • Per-node runs re-execute cheap local processors upstream first, so generators never read stale inputs

Output Now (Export Pipeline)

  • One-click export of any connected media (image, video, audio, 3D model) to a user-chosen directory
  • Automatically generates a sidecar .json file containing the upstream workflow (trimmed of carousel history)
  • Sidecar JSON can be re-imported by dragging onto the canvas, reconstructing the full upstream pipeline
  • Blob URLs are converted to base64 client-side before saving (server can't fetch blob URLs)
  • Workflow file stays small after export by externalizing all media fields

LAN / Network Access

  • Server binds to 0.0.0.0 for LAN access from other machines
  • allowedDevOrigins configured for cross-machine dev server access
  • Network path hints (\\server\share) in project setup
  • Web-based directory browser (replaced native OS picker for cross-network compatibility)
  • Client-side file:// URL opening with clipboard copy fallback for non-secure contexts

Cost Tracking

  • Per-generation cost display on all generator nodes using fal.ai Cost Estimation API
  • Session cost accumulator in the header
  • Generate3D and GenerateAudio nodes included in workflow cost breakdown

Media Handling

  • Videos and audio externalized during workflow save (keeps .json files small)
  • 3D models and audio cleared from output node data on save
  • Auto-restore of 3D models in GLB viewers after workflow reload
  • MediaOverlay component for consistent video/image overlay viewing
  • mediaCapture and mediaStorage utilities for thumbnail generation and disk persistence

WorldLabs Enhancements

  • Panorama preview with azimuth dropdowns and standalone viewer URL
  • Multi-image upload with azimuth metadata
  • is_pano checkbox on World Generator node
  • Auto-save SPZ and panorama files to generations folder
  • SessionStorage quota fix for large panorama data

Panorama Pipeline

  • Panorama Editor node with WebGL compositing
  • Perspective crop capture from panorama viewer
  • Focus viewer button and cleanup

Bug Fixes (Beyond Upstream)

  • Replicate: Polling timeout fix for queued predictions
  • Image display: object-contain instead of object-cover (images fit, not fill)
  • Output node: Fixed 5+ issues — folder creation, 3D input routing, reactive content detection, infinite loop from megabyte-length selector strings, invisible context menu edges (wrong handle IDs)
  • Edge routing: Images through "universal" handle were silently dropped; fixed with type === "image" fallback
  • Workflow inflation: Output node externalization now clears all media fields (was missing model3d, audio)
  • Sidecar JSON bloat: extractUpstreamWorkflow trims generate3d carousel history
  • 3D context menu: Renamed "GLB Viewer" to "3D Viewer", removed "Gaussian Splat Viewer", added "Output"
  • Depth map artifacts: Float render target, edge-preserving filter, morphological dilation, stochastic accumulation
  • Path handling: Mixed path separators, stale project directory after settings change, UNC path image loading

Removed from Upstream

  • Apple SHARP node — replaced by sharp-ml on Replicate

Tech Stack

  • Framework: Next.js 16 (App Router)
  • Language: TypeScript
  • Node Editor: @xyflow/react (React Flow v12)
  • Canvas: Konva.js / react-konva
  • 3D: Three.js (GLB viewer, panorama viewer), @sparkjsdev/spark (Gaussian Splatting)
  • State Management: Zustand
  • Styling: Tailwind CSS
  • AI Providers: Google Gemini, OpenAI, WorldLabs Marble, Replicate, fal.ai, Kie.ai, MuAPI, WaveSpeed

Getting Started

Prerequisites

  • Node.js 18+
  • npm

Environment Variables

Create a .env.local file in the root directory:

GEMINI_API_KEY=your_gemini_api_keyOPENAI_API_KEY=your_openai_api_key# Optional, for OpenAI LLM providerKIE_API_KEY=your_kie_api_key# Optional, for Kie.ai models (Sora, Veo, Kling, etc.)WORLDLABS_API_KEY=your_worldlabs_api_key# Optional, for WorldLabs Marble 3D generationREPLICATE_API_KEY=your_replicate_api_key# OptionalFAL_API_KEY=your_fal_api_key# OptionalMUAPI_API_KEY=your_muapi_api_key# Optional, for MuAPI modelsWAVESPEED_API_KEY=your_wavespeed_api_key# Optional, for WaveSpeed models# PORT=3001 # Optional, dev/prod server port (default 3000)# SPLAT_VIEWER_ORIGIN=http://host:8080 # Optional, hosted splat-viewer build to proxy# (not needed if you run `npm run viewer:install`)

Installation

npm install

Development

npm run dev

Open http://localhost:3000 in your browser (or from another machine on the LAN). Set PORT in .env.local to change the port.

Gaussian Splat Viewer (optional)

The /viewer page (Gaussian splat viewing, camera animation, video export) comes from the separate gitcapoom/splat-viewer project. It is a dependency — never embedded in this repo. One command installs it:

npm run viewer:install

This clones the viewer, builds it, and places the build in public/_viewer/ (gitignored). Restart the dev server and /viewer serves it locally. Re-run the command any time to update. Requires git on PATH.

Alternative for multi-app setups: host one build anywhere and set SPLAT_VIEWER_ORIGIN=http://host:port — node-banana reverse-proxies it under its own origin. Everything else works without the viewer installed.

Build

npm run build
npm run start

Node Reference

Input Nodes

NodeHandlesNotes
Image Inputout: imageLoad images from disk or paste
Audio Inputout: audioLoad audio files
Video Inputout: videoLoad MP4/WebM, thumbnail preview
Promptout: textText prompt with variable support
Arrayout: textArray of text values
Prompt Constructorin: text, out: textTemplate with variable interpolation

Generator Nodes

NodeHandlesNotes
Generate Imagein: image+text (+dynamic), out: imageGemini, Replicate, fal.ai, Kie.ai, MuAPI, WaveSpeed. Extra pins appear from the selected model's schema (mask, control image, …)
Upscale (Grid)in: image+text, out: imageGrid-split upscaling through generator models
Generate Videoin: image+text (+dynamic), out: videoVideo generation from image+prompt
Generate 3Din: image+text (+dynamic), out: 3d3D model generation
Image to Splatin: image, out: 3dSingle image → Gaussian Splat
Generate Audioin: text, out: audioAudio/music generation
LLM Generatein: text+image+video, out: textText generation (Gemini, OpenAI, Claude); video input analyzed by Gemini models only
Generate Panoramain: image+text, out: image+textWorldLabs Marble equirectangular pano
Generate Worldin: image, out: 3d+imageWorldLabs Marble 3D Gaussian Splat world
Sphere Light Renderout: imageLocally-rendered lit sphere (lighting reference)

Process Nodes

NodeHandlesNotes
Annotatein: image, out: imageDrawing tools overlay
Pano Editin: image ×2 + text, out: imageComposite an edited perspective back onto an equirect pano
Mask Painterin: image, out: imageInpainting mask editor (brush/eraser/shapes, blur, invert)
Rotoin: image, out: imageBezier/polygon roto shapes → matte
Compositein: image ×5 (BG, BG α, FG, FG α, Matte), out: imageNuke-style Merge: 22 ops, per-input transforms + blur/defocus filters, float pipeline
Blurin: image + matte, out: imageGaussian/Box/Motion/Zoom/Spin, matte-gated, mix control, float pipeline
Color Gradein: image, out: imageBlackpoint/whitepoint/lift/gain/multiply/offset/gamma (float chain)
HSV Color Correctin: image, out: imageHue/saturation/value (float chain)
Contrast Adjustin: image, out: imageS-curve contrast with roll-off + pivot (float chain)
Image Cropin: image, out: imagePersistent relative crop region, aspect lock
Mirrorin: image, out: imageHorizontal/vertical flip
Reformatin: image, out: imageResize with fill/fit modes
Cube ⇄ Panoin: image, out: imageCubemap cross ↔ equirectangular
Cube ⇄ Facesin/out: image ×6Cubemap ↔ six face images
Pano Shiftin: image, out: imageHorizontal shift with seam wrap
Split Gridin: image, out: referenceGrid subdivision
Video Stitchin: video+audio, out: videoConcatenate video clips
Video Trimin: video, out: videoTrim video start/end
Ease Curvein: video, out: videoSpeed ramp with bezier curves
Frame Grabin: video, out: imageExtract frame from video
Image Comparein: image x2Slide, Blend, Difference modes
Video Comparein: video x2Slide, Blend, Difference modes

Viewer Nodes

NodeHandlesNotes
3D Viewer (GLB)in: 3dThree.js orbit viewer, auto-rotation
Gaussian Splat Viewerin: 3dOpens the standalone splat viewer (/viewer): camera animation, DoF, lens distortion, video/depth export, COLMAP I/O
Pano Viewerin: image360 panorama viewer; captures perspective crops
Pano Cropauto-createdPerspective snapshot from the pano viewer, with camera metadata

Output Nodes

NodeHandlesNotes
Outputin: universalExport any media type with sidecar JSON
Output Galleryin: imageCollect multiple images

Route Nodes

NodeHandlesNotes
Routerin/out: anyPass-through routing
Switchin: any, out: switchedToggle outputs
Conditional Switchin: text, out: rule-basedRoute by text matching

Example Workflows

The /examples directory contains example workflow files. To use them:

  1. Start the dev server with npm run dev
  2. Drag any .json file from /examples into the browser window
  3. Review prompts before running — they're tuned for specific examples

Testing

npm test# Watch mode
npm run test:run # Single run
npm run test:coverage # With coverage report

License

MIT

About

Free and open node based generative workflows based on node-banana

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

Node Banana (Capoom Fork)

A fork of Shrimbly's Node Banana with additional nodes, features, and fixes for production use on a LAN-accessible workstation.

Upstream: This fork tracks shrimbly/node-banana as the upstream remote. All additions are layered on top of the upstream feature set.

Architecture note (splat viewer): The Gaussian Splat Viewer is a separate project (gitcapoom/splat-viewer) — a dependency, never embedded in this repo. Run npm run viewer:install to clone + build it into a gitignored public/_viewer/ folder that /viewer serves directly; alternatively point SPLAT_VIEWER_ORIGIN at a hosted build to reverse-proxy it. See Gaussian Splat Viewer setup.

Node Banana Screenshot


What's Different from Upstream

New Nodes

NodeTypeDescription
Video InputInputLoad video files (MP4, WebM) from disk with thumbnail preview and lazy playback
RotoProcessBezier/polygon shape roto editor producing mattes (full-screen Konva editor, invert toggle)
CompositeProcessFloating-point clone of Nuke's Merge node: 22 merge ops, per-input affine transforms, external BG/FG alpha pins, matte pin, premultiply/swap/opacity controls, per-input blur/defocus filters
BlurProcessGPU blur with five filters (Gaussian, Box, Motion, Zoom, Spin), an optional matte input gating where the blur lands, invert + mix controls
DotProcessSmall circular reroute point for organising edge routing — ctrl+click any edge to insert one; selectable and deletable like any node
ViewerProcessLive tap on the graph — reflects upstream edits in realtime without a run (edit a roto matte and the composite lands here), and is selectable as a source from any node's full-screen view
Color GradeProcessNuke-style grade (blackpoint/whitepoint/lift/gain/multiply/offset/gamma) on the float GPU chain
HSV Color CorrectProcessHue shift / saturation / value on the float GPU chain
Contrast AdjustProcessS-curve contrast with roll-off and pivot on the float GPU chain
Image CropProcessPersistent relative-coordinate crop region with aspect lock
MirrorProcessHorizontal / vertical flips
ReformatProcessResize to target resolution with fill/fit modes and filter choice
Cube ⇄ Pano / Cube ⇄ FacesProcessCubemap cross ↔ equirectangular, and cubemap ↔ six face images
Pano ShiftProcessHorizontal panorama shift with seam wrap-around
Upscale (Grid)GenerateGrid-split upscaling through generator models
Image to SplatGenerateSingle image → 3D Gaussian Splat (feeds the splat viewer)
Sphere Light RenderGenerateLocally-rendered lit grey sphere from rotation/elevation/intensity (lighting reference)
Video CompareProcessSide-by-side video comparison with three modes: Slide (wipe), Blend (opacity), and Difference (pixel diff). Synced playback with wait-for-both restart
Image Compare (enhanced)ProcessAdded Blend and Difference modes with opacity control (upstream only has the slider)
GLB Viewer (enhanced)ViewerThree.js-based 3D model viewer with orbit controls, auto-rotation, background pin visibility toggle, and file persistence across workflow save/reload
Gaussian Splat Viewer (enhanced)ViewerRenamed from "SPZ Viewer". Added XYZ transform controls, camera animation timeline with keyframes, video export (H264/WebM), depth map capture (float-precision), and COLMAP export
Output Node (enhanced)OutputUniversal input handle accepting all media types. "Output Now" button for one-click export with sidecar JSON. Blob URL conversion for 3D files. Performance-optimized selectors

New Features

Float Color Pipeline

  • Color Grade / HSV / Contrast / Blur / Composite chain through 16-bit float GPU textures (WebGL2), so out-of-range values survive between nodes — no 8-bit clamp until the final consumer
  • Live in-node GPU previews at 60 fps; 8-bit PNG committed only after sliders settle
  • Composite inputs can each be pre-filtered (blur/defocus) before the merge, float-preserving

Dynamic Model Input Pins

  • Generator nodes grow input pins from the selected model's schema (mask, control image, multiple image slots, etc.)
  • Stable slot ids survive model switches and reloads; a single edge-conformance pass guarantees edges always match rendered pins (no ghost edges)

Reliability

  • Crash-safe workflow saves: writes go to a temp file, fsync, then atomic rename; the previous good save is kept as a rolling .bak; the loader falls back to the .bak (with a warning toast) if the main file is ever corrupt
  • Auto-save handles multi-hundred-MB media via chunked content hashing and URL-only handling for large provider videos
  • Per-node runs re-execute cheap local processors upstream first, so generators never read stale inputs

Output Now (Export Pipeline)

  • One-click export of any connected media (image, video, audio, 3D model) to a user-chosen directory
  • Automatically generates a sidecar .json file containing the upstream workflow (trimmed of carousel history)
  • Sidecar JSON can be re-imported by dragging onto the canvas, reconstructing the full upstream pipeline
  • Blob URLs are converted to base64 client-side before saving (server can't fetch blob URLs)
  • Workflow file stays small after export by externalizing all media fields

LAN / Network Access

  • Server binds to 0.0.0.0 for LAN access from other machines
  • allowedDevOrigins configured for cross-machine dev server access
  • Network path hints (\\server\share) in project setup
  • Web-based directory browser (replaced native OS picker for cross-network compatibility)
  • Client-side file:// URL opening with clipboard copy fallback for non-secure contexts

Cost Tracking

  • Per-generation cost display on all generator nodes using fal.ai Cost Estimation API
  • Session cost accumulator in the header
  • Generate3D and GenerateAudio nodes included in workflow cost breakdown

Media Handling

  • Videos and audio externalized during workflow save (keeps .json files small)
  • 3D models and audio cleared from output node data on save
  • Auto-restore of 3D models in GLB viewers after workflow reload
  • MediaOverlay component for consistent video/image overlay viewing
  • mediaCapture and mediaStorage utilities for thumbnail generation and disk persistence

WorldLabs Enhancements

  • Panorama preview with azimuth dropdowns and standalone viewer URL
  • Multi-image upload with azimuth metadata
  • is_pano checkbox on World Generator node
  • Auto-save SPZ and panorama files to generations folder
  • SessionStorage quota fix for large panorama data

Panorama Pipeline

  • Panorama Editor node with WebGL compositing
  • Perspective crop capture from panorama viewer
  • Focus viewer button and cleanup

Bug Fixes (Beyond Upstream)

  • Replicate: Polling timeout fix for queued predictions
  • Image display: object-contain instead of object-cover (images fit, not fill)
  • Output node: Fixed 5+ issues — folder creation, 3D input routing, reactive content detection, infinite loop from megabyte-length selector strings, invisible context menu edges (wrong handle IDs)
  • Edge routing: Images through "universal" handle were silently dropped; fixed with type === "image" fallback
  • Workflow inflation: Output node externalization now clears all media fields (was missing model3d, audio)
  • Sidecar JSON bloat: extractUpstreamWorkflow trims generate3d carousel history
  • 3D context menu: Renamed "GLB Viewer" to "3D Viewer", removed "Gaussian Splat Viewer", added "Output"
  • Depth map artifacts: Float render target, edge-preserving filter, morphological dilation, stochastic accumulation
  • Path handling: Mixed path separators, stale project directory after settings change, UNC path image loading

Removed from Upstream

  • Apple SHARP node — replaced by sharp-ml on Replicate

Tech Stack

  • Framework: Next.js 16 (App Router)
  • Language: TypeScript
  • Node Editor: @xyflow/react (React Flow v12)
  • Canvas: Konva.js / react-konva
  • 3D: Three.js (GLB viewer, panorama viewer), @sparkjsdev/spark (Gaussian Splatting)
  • State Management: Zustand
  • Styling: Tailwind CSS
  • AI Providers: Google Gemini, OpenAI, WorldLabs Marble, Replicate, fal.ai, Kie.ai, MuAPI, WaveSpeed

Getting Started

Prerequisites

  • Node.js 18+
  • npm

Environment Variables

Create a .env.local file in the root directory:

GEMINI_API_KEY=your_gemini_api_keyOPENAI_API_KEY=your_openai_api_key# Optional, for OpenAI LLM providerKIE_API_KEY=your_kie_api_key# Optional, for Kie.ai models (Sora, Veo, Kling, etc.)WORLDLABS_API_KEY=your_worldlabs_api_key# Optional, for WorldLabs Marble 3D generationREPLICATE_API_KEY=your_replicate_api_key# OptionalFAL_API_KEY=your_fal_api_key# OptionalMUAPI_API_KEY=your_muapi_api_key# Optional, for MuAPI modelsWAVESPEED_API_KEY=your_wavespeed_api_key# Optional, for WaveSpeed models# PORT=3001 # Optional, dev/prod server port (default 3000)# SPLAT_VIEWER_ORIGIN=http://host:8080 # Optional, hosted splat-viewer build to proxy# (not needed if you run `npm run viewer:install`)

Installation

npm install

Development

npm run dev

Open http://localhost:3000 in your browser (or from another machine on the LAN). Set PORT in .env.local to change the port.

Gaussian Splat Viewer (optional)

The /viewer page (Gaussian splat viewing, camera animation, video export) comes from the separate gitcapoom/splat-viewer project. It is a dependency — never embedded in this repo. One command installs it:

npm run viewer:install

This clones the viewer, builds it, and places the build in public/_viewer/ (gitignored). Restart the dev server and /viewer serves it locally. Re-run the command any time to update. Requires git on PATH.

Alternative for multi-app setups: host one build anywhere and set SPLAT_VIEWER_ORIGIN=http://host:port — node-banana reverse-proxies it under its own origin. Everything else works without the viewer installed.

Build

npm run build
npm run start

Node Reference

Input Nodes

NodeHandlesNotes
Image Inputout: imageLoad images from disk or paste
Audio Inputout: audioLoad audio files
Video Inputout: videoLoad MP4/WebM, thumbnail preview
Promptout: textText prompt with variable support
Arrayout: textArray of text values
Prompt Constructorin: text, out: textTemplate with variable interpolation

Generator Nodes

NodeHandlesNotes
Generate Imagein: image+text (+dynamic), out: imageGemini, Replicate, fal.ai, Kie.ai, MuAPI, WaveSpeed. Extra pins appear from the selected model's schema (mask, control image, …)
Upscale (Grid)in: image+text, out: imageGrid-split upscaling through generator models
Generate Videoin: image+text (+dynamic), out: videoVideo generation from image+prompt
Generate 3Din: image+text (+dynamic), out: 3d3D model generation
Image to Splatin: image, out: 3dSingle image → Gaussian Splat
Generate Audioin: text, out: audioAudio/music generation
LLM Generatein: text+image+video, out: textText generation (Gemini, OpenAI, Claude); video input analyzed by Gemini models only
Generate Panoramain: image+text, out: image+textWorldLabs Marble equirectangular pano
Generate Worldin: image, out: 3d+imageWorldLabs Marble 3D Gaussian Splat world
Sphere Light Renderout: imageLocally-rendered lit sphere (lighting reference)

Process Nodes

NodeHandlesNotes
Annotatein: image, out: imageDrawing tools overlay
Pano Editin: image ×2 + text, out: imageComposite an edited perspective back onto an equirect pano
Mask Painterin: image, out: imageInpainting mask editor (brush/eraser/shapes, blur, invert)
Rotoin: image, out: imageBezier/polygon roto shapes → matte
Compositein: image ×5 (BG, BG α, FG, FG α, Matte), out: imageNuke-style Merge: 22 ops, per-input transforms + blur/defocus filters, float pipeline
Blurin: image + matte, out: imageGaussian/Box/Motion/Zoom/Spin, matte-gated, mix control, float pipeline
Color Gradein: image, out: imageBlackpoint/whitepoint/lift/gain/multiply/offset/gamma (float chain)
HSV Color Correctin: image, out: imageHue/saturation/value (float chain)
Contrast Adjustin: image, out: imageS-curve contrast with roll-off + pivot (float chain)
Image Cropin: image, out: imagePersistent relative crop region, aspect lock
Mirrorin: image, out: imageHorizontal/vertical flip
Reformatin: image, out: imageResize with fill/fit modes
Cube ⇄ Panoin: image, out: imageCubemap cross ↔ equirectangular
Cube ⇄ Facesin/out: image ×6Cubemap ↔ six face images
Pano Shiftin: image, out: imageHorizontal shift with seam wrap
Split Gridin: image, out: referenceGrid subdivision
Video Stitchin: video+audio, out: videoConcatenate video clips
Video Trimin: video, out: videoTrim video start/end
Ease Curvein: video, out: videoSpeed ramp with bezier curves
Frame Grabin: video, out: imageExtract frame from video
Image Comparein: image x2Slide, Blend, Difference modes
Video Comparein: video x2Slide, Blend, Difference modes

Viewer Nodes

NodeHandlesNotes
3D Viewer (GLB)in: 3dThree.js orbit viewer, auto-rotation
Gaussian Splat Viewerin: 3dOpens the standalone splat viewer (/viewer): camera animation, DoF, lens distortion, video/depth export, COLMAP I/O
Pano Viewerin: image360 panorama viewer; captures perspective crops
Pano Cropauto-createdPerspective snapshot from the pano viewer, with camera metadata

Output Nodes

NodeHandlesNotes
Outputin: universalExport any media type with sidecar JSON
Output Galleryin: imageCollect multiple images

Route Nodes

NodeHandlesNotes
Routerin/out: anyPass-through routing
Switchin: any, out: switchedToggle outputs
Conditional Switchin: text, out: rule-basedRoute by text matching

Example Workflows

The /examples directory contains example workflow files. To use them:

  1. Start the dev server with npm run dev
  2. Drag any .json file from /examples into the browser window
  3. Review prompts before running — they're tuned for specific examples

Testing

npm test# Watch mode
npm run test:run # Single run
npm run test:coverage # With coverage report

License

MIT

About

Free and open node based generative workflows based on node-banana

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Node Banana (Capoom Fork)

A fork of Shrimbly's Node Banana with additional nodes, features, and fixes for production use on a LAN-accessible workstation.

Upstream: This fork tracks shrimbly/node-banana as the upstream remote. All additions are layered on top of the upstream feature set.

Architecture note (splat viewer): The Gaussian Splat Viewer is a separate project (gitcapoom/splat-viewer) — a dependency, never embedded in this repo. Run npm run viewer:install to clone + build it into a gitignored public/_viewer/ folder that /viewer serves directly; alternatively point SPLAT_VIEWER_ORIGIN at a hosted build to reverse-proxy it. See Gaussian Splat Viewer setup.

Node Banana Screenshot


What's Different from Upstream

New Nodes

NodeTypeDescription
Video InputInputLoad video files (MP4, WebM) from disk with thumbnail preview and lazy playback
RotoProcessBezier/polygon shape roto editor producing mattes (full-screen Konva editor, invert toggle)
CompositeProcessFloating-point clone of Nuke's Merge node: 22 merge ops, per-input affine transforms, external BG/FG alpha pins, matte pin, premultiply/swap/opacity controls, per-input blur/defocus filters
BlurProcessGPU blur with five filters (Gaussian, Box, Motion, Zoom, Spin), an optional matte input gating where the blur lands, invert + mix controls
DotProcessSmall circular reroute point for organising edge routing — ctrl+click any edge to insert one; selectable and deletable like any node
ViewerProcessLive tap on the graph — reflects upstream edits in realtime without a run (edit a roto matte and the composite lands here), and is selectable as a source from any node's full-screen view
Color GradeProcessNuke-style grade (blackpoint/whitepoint/lift/gain/multiply/offset/gamma) on the float GPU chain
HSV Color CorrectProcessHue shift / saturation / value on the float GPU chain
Contrast AdjustProcessS-curve contrast with roll-off and pivot on the float GPU chain
Image CropProcessPersistent relative-coordinate crop region with aspect lock
MirrorProcessHorizontal / vertical flips
ReformatProcessResize to target resolution with fill/fit modes and filter choice
Cube ⇄ Pano / Cube ⇄ FacesProcessCubemap cross ↔ equirectangular, and cubemap ↔ six face images
Pano ShiftProcessHorizontal panorama shift with seam wrap-around
Upscale (Grid)GenerateGrid-split upscaling through generator models
Image to SplatGenerateSingle image → 3D Gaussian Splat (feeds the splat viewer)
Sphere Light RenderGenerateLocally-rendered lit grey sphere from rotation/elevation/intensity (lighting reference)
Video CompareProcessSide-by-side video comparison with three modes: Slide (wipe), Blend (opacity), and Difference (pixel diff). Synced playback with wait-for-both restart
Image Compare (enhanced)ProcessAdded Blend and Difference modes with opacity control (upstream only has the slider)
GLB Viewer (enhanced)ViewerThree.js-based 3D model viewer with orbit controls, auto-rotation, background pin visibility toggle, and file persistence across workflow save/reload
Gaussian Splat Viewer (enhanced)ViewerRenamed from "SPZ Viewer". Added XYZ transform controls, camera animation timeline with keyframes, video export (H264/WebM), depth map capture (float-precision), and COLMAP export
Output Node (enhanced)OutputUniversal input handle accepting all media types. "Output Now" button for one-click export with sidecar JSON. Blob URL conversion for 3D files. Performance-optimized selectors

New Features

Float Color Pipeline

  • Color Grade / HSV / Contrast / Blur / Composite chain through 16-bit float GPU textures (WebGL2), so out-of-range values survive between nodes — no 8-bit clamp until the final consumer
  • Live in-node GPU previews at 60 fps; 8-bit PNG committed only after sliders settle
  • Composite inputs can each be pre-filtered (blur/defocus) before the merge, float-preserving

Dynamic Model Input Pins

  • Generator nodes grow input pins from the selected model's schema (mask, control image, multiple image slots, etc.)
  • Stable slot ids survive model switches and reloads; a single edge-conformance pass guarantees edges always match rendered pins (no ghost edges)

Reliability

  • Crash-safe workflow saves: writes go to a temp file, fsync, then atomic rename; the previous good save is kept as a rolling .bak; the loader falls back to the .bak (with a warning toast) if the main file is ever corrupt
  • Auto-save handles multi-hundred-MB media via chunked content hashing and URL-only handling for large provider videos
  • Per-node runs re-execute cheap local processors upstream first, so generators never read stale inputs

Output Now (Export Pipeline)

  • One-click export of any connected media (image, video, audio, 3D model) to a user-chosen directory
  • Automatically generates a sidecar .json file containing the upstream workflow (trimmed of carousel history)
  • Sidecar JSON can be re-imported by dragging onto the canvas, reconstructing the full upstream pipeline
  • Blob URLs are converted to base64 client-side before saving (server can't fetch blob URLs)
  • Workflow file stays small after export by externalizing all media fields

LAN / Network Access

  • Server binds to 0.0.0.0 for LAN access from other machines
  • allowedDevOrigins configured for cross-machine dev server access
  • Network path hints (\\server\share) in project setup
  • Web-based directory browser (replaced native OS picker for cross-network compatibility)
  • Client-side file:// URL opening with clipboard copy fallback for non-secure contexts

Cost Tracking

  • Per-generation cost display on all generator nodes using fal.ai Cost Estimation API
  • Session cost accumulator in the header
  • Generate3D and GenerateAudio nodes included in workflow cost breakdown

Media Handling

  • Videos and audio externalized during workflow save (keeps .json files small)
  • 3D models and audio cleared from output node data on save
  • Auto-restore of 3D models in GLB viewers after workflow reload
  • MediaOverlay component for consistent video/image overlay viewing
  • mediaCapture and mediaStorage utilities for thumbnail generation and disk persistence

WorldLabs Enhancements

  • Panorama preview with azimuth dropdowns and standalone viewer URL
  • Multi-image upload with azimuth metadata
  • is_pano checkbox on World Generator node
  • Auto-save SPZ and panorama files to generations folder
  • SessionStorage quota fix for large panorama data

Panorama Pipeline

  • Panorama Editor node with WebGL compositing
  • Perspective crop capture from panorama viewer
  • Focus viewer button and cleanup

Bug Fixes (Beyond Upstream)

  • Replicate: Polling timeout fix for queued predictions
  • Image display: object-contain instead of object-cover (images fit, not fill)
  • Output node: Fixed 5+ issues — folder creation, 3D input routing, reactive content detection, infinite loop from megabyte-length selector strings, invisible context menu edges (wrong handle IDs)
  • Edge routing: Images through "universal" handle were silently dropped; fixed with type === "image" fallback
  • Workflow inflation: Output node externalization now clears all media fields (was missing model3d, audio)
  • Sidecar JSON bloat: extractUpstreamWorkflow trims generate3d carousel history
  • 3D context menu: Renamed "GLB Viewer" to "3D Viewer", removed "Gaussian Splat Viewer", added "Output"
  • Depth map artifacts: Float render target, edge-preserving filter, morphological dilation, stochastic accumulation
  • Path handling: Mixed path separators, stale project directory after settings change, UNC path image loading

Removed from Upstream

  • Apple SHARP node — replaced by sharp-ml on Replicate

Tech Stack

  • Framework: Next.js 16 (App Router)
  • Language: TypeScript
  • Node Editor: @xyflow/react (React Flow v12)
  • Canvas: Konva.js / react-konva
  • 3D: Three.js (GLB viewer, panorama viewer), @sparkjsdev/spark (Gaussian Splatting)
  • State Management: Zustand
  • Styling: Tailwind CSS
  • AI Providers: Google Gemini, OpenAI, WorldLabs Marble, Replicate, fal.ai, Kie.ai, MuAPI, WaveSpeed

Getting Started

Prerequisites

  • Node.js 18+
  • npm

Environment Variables

Create a .env.local file in the root directory:

GEMINI_API_KEY=your_gemini_api_keyOPENAI_API_KEY=your_openai_api_key# Optional, for OpenAI LLM providerKIE_API_KEY=your_kie_api_key# Optional, for Kie.ai models (Sora, Veo, Kling, etc.)WORLDLABS_API_KEY=your_worldlabs_api_key# Optional, for WorldLabs Marble 3D generationREPLICATE_API_KEY=your_replicate_api_key# OptionalFAL_API_KEY=your_fal_api_key# OptionalMUAPI_API_KEY=your_muapi_api_key# Optional, for MuAPI modelsWAVESPEED_API_KEY=your_wavespeed_api_key# Optional, for WaveSpeed models# PORT=3001 # Optional, dev/prod server port (default 3000)# SPLAT_VIEWER_ORIGIN=http://host:8080 # Optional, hosted splat-viewer build to proxy# (not needed if you run `npm run viewer:install`)

Installation

npm install

Development

npm run dev

Open http://localhost:3000 in your browser (or from another machine on the LAN). Set PORT in .env.local to change the port.

Gaussian Splat Viewer (optional)

The /viewer page (Gaussian splat viewing, camera animation, video export) comes from the separate gitcapoom/splat-viewer project. It is a dependency — never embedded in this repo. One command installs it:

npm run viewer:install

This clones the viewer, builds it, and places the build in public/_viewer/ (gitignored). Restart the dev server and /viewer serves it locally. Re-run the command any time to update. Requires git on PATH.

Alternative for multi-app setups: host one build anywhere and set SPLAT_VIEWER_ORIGIN=http://host:port — node-banana reverse-proxies it under its own origin. Everything else works without the viewer installed.

Build

npm run build
npm run start

Node Reference

Input Nodes

NodeHandlesNotes
Image Inputout: imageLoad images from disk or paste
Audio Inputout: audioLoad audio files
Video Inputout: videoLoad MP4/WebM, thumbnail preview
Promptout: textText prompt with variable support
Arrayout: textArray of text values
Prompt Constructorin: text, out: textTemplate with variable interpolation

Generator Nodes

NodeHandlesNotes
Generate Imagein: image+text (+dynamic), out: imageGemini, Replicate, fal.ai, Kie.ai, MuAPI, WaveSpeed. Extra pins appear from the selected model's schema (mask, control image, …)
Upscale (Grid)in: image+text, out: imageGrid-split upscaling through generator models
Generate Videoin: image+text (+dynamic), out: videoVideo generation from image+prompt
Generate 3Din: image+text (+dynamic), out: 3d3D model generation
Image to Splatin: image, out: 3dSingle image → Gaussian Splat
Generate Audioin: text, out: audioAudio/music generation
LLM Generatein: text+image+video, out: textText generation (Gemini, OpenAI, Claude); video input analyzed by Gemini models only
Generate Panoramain: image+text, out: image+textWorldLabs Marble equirectangular pano
Generate Worldin: image, out: 3d+imageWorldLabs Marble 3D Gaussian Splat world
Sphere Light Renderout: imageLocally-rendered lit sphere (lighting reference)

Process Nodes

NodeHandlesNotes
Annotatein: image, out: imageDrawing tools overlay
Pano Editin: image ×2 + text, out: imageComposite an edited perspective back onto an equirect pano
Mask Painterin: image, out: imageInpainting mask editor (brush/eraser/shapes, blur, invert)
Rotoin: image, out: imageBezier/polygon roto shapes → matte
Compositein: image ×5 (BG, BG α, FG, FG α, Matte), out: imageNuke-style Merge: 22 ops, per-input transforms + blur/defocus filters, float pipeline
Blurin: image + matte, out: imageGaussian/Box/Motion/Zoom/Spin, matte-gated, mix control, float pipeline
Color Gradein: image, out: imageBlackpoint/whitepoint/lift/gain/multiply/offset/gamma (float chain)
HSV Color Correctin: image, out: imageHue/saturation/value (float chain)
Contrast Adjustin: image, out: imageS-curve contrast with roll-off + pivot (float chain)
Image Cropin: image, out: imagePersistent relative crop region, aspect lock
Mirrorin: image, out: imageHorizontal/vertical flip
Reformatin: image, out: imageResize with fill/fit modes
Cube ⇄ Panoin: image, out: imageCubemap cross ↔ equirectangular
Cube ⇄ Facesin/out: image ×6Cubemap ↔ six face images
Pano Shiftin: image, out: imageHorizontal shift with seam wrap
Split Gridin: image, out: referenceGrid subdivision
Video Stitchin: video+audio, out: videoConcatenate video clips
Video Trimin: video, out: videoTrim video start/end
Ease Curvein: video, out: videoSpeed ramp with bezier curves
Frame Grabin: video, out: imageExtract frame from video
Image Comparein: image x2Slide, Blend, Difference modes
Video Comparein: video x2Slide, Blend, Difference modes

Viewer Nodes

NodeHandlesNotes
3D Viewer (GLB)in: 3dThree.js orbit viewer, auto-rotation
Gaussian Splat Viewerin: 3dOpens the standalone splat viewer (/viewer): camera animation, DoF, lens distortion, video/depth export, COLMAP I/O
Pano Viewerin: image360 panorama viewer; captures perspective crops
Pano Cropauto-createdPerspective snapshot from the pano viewer, with camera metadata

Output Nodes

NodeHandlesNotes
Outputin: universalExport any media type with sidecar JSON
Output Galleryin: imageCollect multiple images

Route Nodes

NodeHandlesNotes
Routerin/out: anyPass-through routing
Switchin: any, out: switchedToggle outputs
Conditional Switchin: text, out: rule-basedRoute by text matching

Example Workflows

The /examples directory contains example workflow files. To use them:

  1. Start the dev server with npm run dev
  2. Drag any .json file from /examples into the browser window
  3. Review prompts before running — they're tuned for specific examples

Testing

npm test# Watch mode
npm run test:run # Single run
npm run test:coverage # With coverage report

License

MIT

About

Free and open node based generative workflows based on node-banana

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Node Banana (Capoom Fork)

A fork of Shrimbly's Node Banana with additional nodes, features, and fixes for production use on a LAN-accessible workstation.

Upstream: This fork tracks shrimbly/node-banana as the upstream remote. All additions are layered on top of the upstream feature set.

Architecture note (splat viewer): The Gaussian Splat Viewer is a separate project (gitcapoom/splat-viewer) — a dependency, never embedded in this repo. Run npm run viewer:install to clone + build it into a gitignored public/_viewer/ folder that /viewer serves directly; alternatively point SPLAT_VIEWER_ORIGIN at a hosted build to reverse-proxy it. See Gaussian Splat Viewer setup.

Node Banana Screenshot


What's Different from Upstream

New Nodes

NodeTypeDescription
Video InputInputLoad video files (MP4, WebM) from disk with thumbnail preview and lazy playback
RotoProcessBezier/polygon shape roto editor producing mattes (full-screen Konva editor, invert toggle)
CompositeProcessFloating-point clone of Nuke's Merge node: 22 merge ops, per-input affine transforms, external BG/FG alpha pins, matte pin, premultiply/swap/opacity controls, per-input blur/defocus filters
BlurProcessGPU blur with five filters (Gaussian, Box, Motion, Zoom, Spin), an optional matte input gating where the blur lands, invert + mix controls
DotProcessSmall circular reroute point for organising edge routing — ctrl+click any edge to insert one; selectable and deletable like any node
ViewerProcessLive tap on the graph — reflects upstream edits in realtime without a run (edit a roto matte and the composite lands here), and is selectable as a source from any node's full-screen view
Color GradeProcessNuke-style grade (blackpoint/whitepoint/lift/gain/multiply/offset/gamma) on the float GPU chain
HSV Color CorrectProcessHue shift / saturation / value on the float GPU chain
Contrast AdjustProcessS-curve contrast with roll-off and pivot on the float GPU chain
Image CropProcessPersistent relative-coordinate crop region with aspect lock
MirrorProcessHorizontal / vertical flips
ReformatProcessResize to target resolution with fill/fit modes and filter choice
Cube ⇄ Pano / Cube ⇄ FacesProcessCubemap cross ↔ equirectangular, and cubemap ↔ six face images
Pano ShiftProcessHorizontal panorama shift with seam wrap-around
Upscale (Grid)GenerateGrid-split upscaling through generator models
Image to SplatGenerateSingle image → 3D Gaussian Splat (feeds the splat viewer)
Sphere Light RenderGenerateLocally-rendered lit grey sphere from rotation/elevation/intensity (lighting reference)
Video CompareProcessSide-by-side video comparison with three modes: Slide (wipe), Blend (opacity), and Difference (pixel diff). Synced playback with wait-for-both restart
Image Compare (enhanced)ProcessAdded Blend and Difference modes with opacity control (upstream only has the slider)
GLB Viewer (enhanced)ViewerThree.js-based 3D model viewer with orbit controls, auto-rotation, background pin visibility toggle, and file persistence across workflow save/reload
Gaussian Splat Viewer (enhanced)ViewerRenamed from "SPZ Viewer". Added XYZ transform controls, camera animation timeline with keyframes, video export (H264/WebM), depth map capture (float-precision), and COLMAP export
Output Node (enhanced)OutputUniversal input handle accepting all media types. "Output Now" button for one-click export with sidecar JSON. Blob URL conversion for 3D files. Performance-optimized selectors

New Features

Float Color Pipeline

  • Color Grade / HSV / Contrast / Blur / Composite chain through 16-bit float GPU textures (WebGL2), so out-of-range values survive between nodes — no 8-bit clamp until the final consumer
  • Live in-node GPU previews at 60 fps; 8-bit PNG committed only after sliders settle
  • Composite inputs can each be pre-filtered (blur/defocus) before the merge, float-preserving

Dynamic Model Input Pins

  • Generator nodes grow input pins from the selected model's schema (mask, control image, multiple image slots, etc.)
  • Stable slot ids survive model switches and reloads; a single edge-conformance pass guarantees edges always match rendered pins (no ghost edges)

Reliability

  • Crash-safe workflow saves: writes go to a temp file, fsync, then atomic rename; the previous good save is kept as a rolling .bak; the loader falls back to the .bak (with a warning toast) if the main file is ever corrupt
  • Auto-save handles multi-hundred-MB media via chunked content hashing and URL-only handling for large provider videos
  • Per-node runs re-execute cheap local processors upstream first, so generators never read stale inputs

Output Now (Export Pipeline)

  • One-click export of any connected media (image, video, audio, 3D model) to a user-chosen directory
  • Automatically generates a sidecar .json file containing the upstream workflow (trimmed of carousel history)
  • Sidecar JSON can be re-imported by dragging onto the canvas, reconstructing the full upstream pipeline
  • Blob URLs are converted to base64 client-side before saving (server can't fetch blob URLs)
  • Workflow file stays small after export by externalizing all media fields

LAN / Network Access

  • Server binds to 0.0.0.0 for LAN access from other machines
  • allowedDevOrigins configured for cross-machine dev server access
  • Network path hints (\\server\share) in project setup
  • Web-based directory browser (replaced native OS picker for cross-network compatibility)
  • Client-side file:// URL opening with clipboard copy fallback for non-secure contexts

Cost Tracking

  • Per-generation cost display on all generator nodes using fal.ai Cost Estimation API
  • Session cost accumulator in the header
  • Generate3D and GenerateAudio nodes included in workflow cost breakdown

Media Handling

  • Videos and audio externalized during workflow save (keeps .json files small)
  • 3D models and audio cleared from output node data on save
  • Auto-restore of 3D models in GLB viewers after workflow reload
  • MediaOverlay component for consistent video/image overlay viewing
  • mediaCapture and mediaStorage utilities for thumbnail generation and disk persistence

WorldLabs Enhancements

  • Panorama preview with azimuth dropdowns and standalone viewer URL
  • Multi-image upload with azimuth metadata
  • is_pano checkbox on World Generator node
  • Auto-save SPZ and panorama files to generations folder
  • SessionStorage quota fix for large panorama data

Panorama Pipeline

  • Panorama Editor node with WebGL compositing
  • Perspective crop capture from panorama viewer
  • Focus viewer button and cleanup

Bug Fixes (Beyond Upstream)

  • Replicate: Polling timeout fix for queued predictions
  • Image display: object-contain instead of object-cover (images fit, not fill)
  • Output node: Fixed 5+ issues — folder creation, 3D input routing, reactive content detection, infinite loop from megabyte-length selector strings, invisible context menu edges (wrong handle IDs)
  • Edge routing: Images through "universal" handle were silently dropped; fixed with type === "image" fallback
  • Workflow inflation: Output node externalization now clears all media fields (was missing model3d, audio)
  • Sidecar JSON bloat: extractUpstreamWorkflow trims generate3d carousel history
  • 3D context menu: Renamed "GLB Viewer" to "3D Viewer", removed "Gaussian Splat Viewer", added "Output"
  • Depth map artifacts: Float render target, edge-preserving filter, morphological dilation, stochastic accumulation
  • Path handling: Mixed path separators, stale project directory after settings change, UNC path image loading

Removed from Upstream

  • Apple SHARP node — replaced by sharp-ml on Replicate

Tech Stack

  • Framework: Next.js 16 (App Router)
  • Language: TypeScript
  • Node Editor: @xyflow/react (React Flow v12)
  • Canvas: Konva.js / react-konva
  • 3D: Three.js (GLB viewer, panorama viewer), @sparkjsdev/spark (Gaussian Splatting)
  • State Management: Zustand
  • Styling: Tailwind CSS
  • AI Providers: Google Gemini, OpenAI, WorldLabs Marble, Replicate, fal.ai, Kie.ai, MuAPI, WaveSpeed

Getting Started

Prerequisites

  • Node.js 18+
  • npm

Environment Variables

Create a .env.local file in the root directory:

GEMINI_API_KEY=your_gemini_api_keyOPENAI_API_KEY=your_openai_api_key# Optional, for OpenAI LLM providerKIE_API_KEY=your_kie_api_key# Optional, for Kie.ai models (Sora, Veo, Kling, etc.)WORLDLABS_API_KEY=your_worldlabs_api_key# Optional, for WorldLabs Marble 3D generationREPLICATE_API_KEY=your_replicate_api_key# OptionalFAL_API_KEY=your_fal_api_key# OptionalMUAPI_API_KEY=your_muapi_api_key# Optional, for MuAPI modelsWAVESPEED_API_KEY=your_wavespeed_api_key# Optional, for WaveSpeed models# PORT=3001 # Optional, dev/prod server port (default 3000)# SPLAT_VIEWER_ORIGIN=http://host:8080 # Optional, hosted splat-viewer build to proxy# (not needed if you run `npm run viewer:install`)

Installation

npm install

Development

npm run dev

Open http://localhost:3000 in your browser (or from another machine on the LAN). Set PORT in .env.local to change the port.

Gaussian Splat Viewer (optional)

The /viewer page (Gaussian splat viewing, camera animation, video export) comes from the separate gitcapoom/splat-viewer project. It is a dependency — never embedded in this repo. One command installs it:

npm run viewer:install

This clones the viewer, builds it, and places the build in public/_viewer/ (gitignored). Restart the dev server and /viewer serves it locally. Re-run the command any time to update. Requires git on PATH.

Alternative for multi-app setups: host one build anywhere and set SPLAT_VIEWER_ORIGIN=http://host:port — node-banana reverse-proxies it under its own origin. Everything else works without the viewer installed.

Build

npm run build
npm run start

Node Reference

Input Nodes

NodeHandlesNotes
Image Inputout: imageLoad images from disk or paste
Audio Inputout: audioLoad audio files
Video Inputout: videoLoad MP4/WebM, thumbnail preview
Promptout: textText prompt with variable support
Arrayout: textArray of text values
Prompt Constructorin: text, out: textTemplate with variable interpolation

Generator Nodes

NodeHandlesNotes
Generate Imagein: image+text (+dynamic), out: imageGemini, Replicate, fal.ai, Kie.ai, MuAPI, WaveSpeed. Extra pins appear from the selected model's schema (mask, control image, …)
Upscale (Grid)in: image+text, out: imageGrid-split upscaling through generator models
Generate Videoin: image+text (+dynamic), out: videoVideo generation from image+prompt
Generate 3Din: image+text (+dynamic), out: 3d3D model generation
Image to Splatin: image, out: 3dSingle image → Gaussian Splat
Generate Audioin: text, out: audioAudio/music generation
LLM Generatein: text+image+video, out: textText generation (Gemini, OpenAI, Claude); video input analyzed by Gemini models only
Generate Panoramain: image+text, out: image+textWorldLabs Marble equirectangular pano
Generate Worldin: image, out: 3d+imageWorldLabs Marble 3D Gaussian Splat world
Sphere Light Renderout: imageLocally-rendered lit sphere (lighting reference)

Process Nodes

NodeHandlesNotes
Annotatein: image, out: imageDrawing tools overlay
Pano Editin: image ×2 + text, out: imageComposite an edited perspective back onto an equirect pano
Mask Painterin: image, out: imageInpainting mask editor (brush/eraser/shapes, blur, invert)
Rotoin: image, out: imageBezier/polygon roto shapes → matte
Compositein: image ×5 (BG, BG α, FG, FG α, Matte), out: imageNuke-style Merge: 22 ops, per-input transforms + blur/defocus filters, float pipeline
Blurin: image + matte, out: imageGaussian/Box/Motion/Zoom/Spin, matte-gated, mix control, float pipeline
Color Gradein: image, out: imageBlackpoint/whitepoint/lift/gain/multiply/offset/gamma (float chain)
HSV Color Correctin: image, out: imageHue/saturation/value (float chain)
Contrast Adjustin: image, out: imageS-curve contrast with roll-off + pivot (float chain)
Image Cropin: image, out: imagePersistent relative crop region, aspect lock
Mirrorin: image, out: imageHorizontal/vertical flip
Reformatin: image, out: imageResize with fill/fit modes
Cube ⇄ Panoin: image, out: imageCubemap cross ↔ equirectangular
Cube ⇄ Facesin/out: image ×6Cubemap ↔ six face images
Pano Shiftin: image, out: imageHorizontal shift with seam wrap
Split Gridin: image, out: referenceGrid subdivision
Video Stitchin: video+audio, out: videoConcatenate video clips
Video Trimin: video, out: videoTrim video start/end
Ease Curvein: video, out: videoSpeed ramp with bezier curves
Frame Grabin: video, out: imageExtract frame from video
Image Comparein: image x2Slide, Blend, Difference modes
Video Comparein: video x2Slide, Blend, Difference modes

Viewer Nodes

NodeHandlesNotes
3D Viewer (GLB)in: 3dThree.js orbit viewer, auto-rotation
Gaussian Splat Viewerin: 3dOpens the standalone splat viewer (/viewer): camera animation, DoF, lens distortion, video/depth export, COLMAP I/O
Pano Viewerin: image360 panorama viewer; captures perspective crops
Pano Cropauto-createdPerspective snapshot from the pano viewer, with camera metadata

Output Nodes

NodeHandlesNotes
Outputin: universalExport any media type with sidecar JSON
Output Galleryin: imageCollect multiple images

Route Nodes

NodeHandlesNotes
Routerin/out: anyPass-through routing
Switchin: any, out: switchedToggle outputs
Conditional Switchin: text, out: rule-basedRoute by text matching

Example Workflows

The /examples directory contains example workflow files. To use them:

  1. Start the dev server with npm run dev
  2. Drag any .json file from /examples into the browser window
  3. Review prompts before running — they're tuned for specific examples

Testing

npm test# Watch mode
npm run test:run # Single run
npm run test:coverage # With coverage report

License

MIT

About

Free and open node based generative workflows based on node-banana

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

Node Banana (Capoom Fork)

A fork of Shrimbly's Node Banana with additional nodes, features, and fixes for production use on a LAN-accessible workstation.

Upstream: This fork tracks shrimbly/node-banana as the upstream remote. All additions are layered on top of the upstream feature set.

Architecture note (splat viewer): The Gaussian Splat Viewer is a separate project (gitcapoom/splat-viewer) — a dependency, never embedded in this repo. Run npm run viewer:install to clone + build it into a gitignored public/_viewer/ folder that /viewer serves directly; alternatively point SPLAT_VIEWER_ORIGIN at a hosted build to reverse-proxy it. See Gaussian Splat Viewer setup.

Node Banana Screenshot


What's Different from Upstream

New Nodes

NodeTypeDescription
Video InputInputLoad video files (MP4, WebM) from disk with thumbnail preview and lazy playback
RotoProcessBezier/polygon shape roto editor producing mattes (full-screen Konva editor, invert toggle)
CompositeProcessFloating-point clone of Nuke's Merge node: 22 merge ops, per-input affine transforms, external BG/FG alpha pins, matte pin, premultiply/swap/opacity controls, per-input blur/defocus filters
BlurProcessGPU blur with five filters (Gaussian, Box, Motion, Zoom, Spin), an optional matte input gating where the blur lands, invert + mix controls
DotProcessSmall circular reroute point for organising edge routing — ctrl+click any edge to insert one; selectable and deletable like any node
ViewerProcessLive tap on the graph — reflects upstream edits in realtime without a run (edit a roto matte and the composite lands here), and is selectable as a source from any node's full-screen view
Color GradeProcessNuke-style grade (blackpoint/whitepoint/lift/gain/multiply/offset/gamma) on the float GPU chain
HSV Color CorrectProcessHue shift / saturation / value on the float GPU chain
Contrast AdjustProcessS-curve contrast with roll-off and pivot on the float GPU chain
Image CropProcessPersistent relative-coordinate crop region with aspect lock
MirrorProcessHorizontal / vertical flips
ReformatProcessResize to target resolution with fill/fit modes and filter choice
Cube ⇄ Pano / Cube ⇄ FacesProcessCubemap cross ↔ equirectangular, and cubemap ↔ six face images
Pano ShiftProcessHorizontal panorama shift with seam wrap-around
Upscale (Grid)GenerateGrid-split upscaling through generator models
Image to SplatGenerateSingle image → 3D Gaussian Splat (feeds the splat viewer)
Sphere Light RenderGenerateLocally-rendered lit grey sphere from rotation/elevation/intensity (lighting reference)
Video CompareProcessSide-by-side video comparison with three modes: Slide (wipe), Blend (opacity), and Difference (pixel diff). Synced playback with wait-for-both restart
Image Compare (enhanced)ProcessAdded Blend and Difference modes with opacity control (upstream only has the slider)
GLB Viewer (enhanced)ViewerThree.js-based 3D model viewer with orbit controls, auto-rotation, background pin visibility toggle, and file persistence across workflow save/reload
Gaussian Splat Viewer (enhanced)ViewerRenamed from "SPZ Viewer". Added XYZ transform controls, camera animation timeline with keyframes, video export (H264/WebM), depth map capture (float-precision), and COLMAP export
Output Node (enhanced)OutputUniversal input handle accepting all media types. "Output Now" button for one-click export with sidecar JSON. Blob URL conversion for 3D files. Performance-optimized selectors

New Features

Float Color Pipeline

  • Color Grade / HSV / Contrast / Blur / Composite chain through 16-bit float GPU textures (WebGL2), so out-of-range values survive between nodes — no 8-bit clamp until the final consumer
  • Live in-node GPU previews at 60 fps; 8-bit PNG committed only after sliders settle
  • Composite inputs can each be pre-filtered (blur/defocus) before the merge, float-preserving

Dynamic Model Input Pins

  • Generator nodes grow input pins from the selected model's schema (mask, control image, multiple image slots, etc.)
  • Stable slot ids survive model switches and reloads; a single edge-conformance pass guarantees edges always match rendered pins (no ghost edges)

Reliability

  • Crash-safe workflow saves: writes go to a temp file, fsync, then atomic rename; the previous good save is kept as a rolling .bak; the loader falls back to the .bak (with a warning toast) if the main file is ever corrupt
  • Auto-save handles multi-hundred-MB media via chunked content hashing and URL-only handling for large provider videos
  • Per-node runs re-execute cheap local processors upstream first, so generators never read stale inputs

Output Now (Export Pipeline)

  • One-click export of any connected media (image, video, audio, 3D model) to a user-chosen directory
  • Automatically generates a sidecar .json file containing the upstream workflow (trimmed of carousel history)
  • Sidecar JSON can be re-imported by dragging onto the canvas, reconstructing the full upstream pipeline
  • Blob URLs are converted to base64 client-side before saving (server can't fetch blob URLs)
  • Workflow file stays small after export by externalizing all media fields

LAN / Network Access

  • Server binds to 0.0.0.0 for LAN access from other machines
  • allowedDevOrigins configured for cross-machine dev server access
  • Network path hints (\\server\share) in project setup
  • Web-based directory browser (replaced native OS picker for cross-network compatibility)
  • Client-side file:// URL opening with clipboard copy fallback for non-secure contexts

Cost Tracking

  • Per-generation cost display on all generator nodes using fal.ai Cost Estimation API
  • Session cost accumulator in the header
  • Generate3D and GenerateAudio nodes included in workflow cost breakdown

Media Handling

  • Videos and audio externalized during workflow save (keeps .json files small)
  • 3D models and audio cleared from output node data on save
  • Auto-restore of 3D models in GLB viewers after workflow reload
  • MediaOverlay component for consistent video/image overlay viewing
  • mediaCapture and mediaStorage utilities for thumbnail generation and disk persistence

WorldLabs Enhancements

  • Panorama preview with azimuth dropdowns and standalone viewer URL
  • Multi-image upload with azimuth metadata
  • is_pano checkbox on World Generator node
  • Auto-save SPZ and panorama files to generations folder
  • SessionStorage quota fix for large panorama data

Panorama Pipeline

  • Panorama Editor node with WebGL compositing
  • Perspective crop capture from panorama viewer
  • Focus viewer button and cleanup

Bug Fixes (Beyond Upstream)

  • Replicate: Polling timeout fix for queued predictions
  • Image display: object-contain instead of object-cover (images fit, not fill)
  • Output node: Fixed 5+ issues — folder creation, 3D input routing, reactive content detection, infinite loop from megabyte-length selector strings, invisible context menu edges (wrong handle IDs)
  • Edge routing: Images through "universal" handle were silently dropped; fixed with type === "image" fallback
  • Workflow inflation: Output node externalization now clears all media fields (was missing model3d, audio)
  • Sidecar JSON bloat: extractUpstreamWorkflow trims generate3d carousel history
  • 3D context menu: Renamed "GLB Viewer" to "3D Viewer", removed "Gaussian Splat Viewer", added "Output"
  • Depth map artifacts: Float render target, edge-preserving filter, morphological dilation, stochastic accumulation
  • Path handling: Mixed path separators, stale project directory after settings change, UNC path image loading

Removed from Upstream

  • Apple SHARP node — replaced by sharp-ml on Replicate

Tech Stack

  • Framework: Next.js 16 (App Router)
  • Language: TypeScript
  • Node Editor: @xyflow/react (React Flow v12)
  • Canvas: Konva.js / react-konva
  • 3D: Three.js (GLB viewer, panorama viewer), @sparkjsdev/spark (Gaussian Splatting)
  • State Management: Zustand
  • Styling: Tailwind CSS
  • AI Providers: Google Gemini, OpenAI, WorldLabs Marble, Replicate, fal.ai, Kie.ai, MuAPI, WaveSpeed

Getting Started

Prerequisites

  • Node.js 18+
  • npm

Environment Variables

Create a .env.local file in the root directory:

GEMINI_API_KEY=your_gemini_api_keyOPENAI_API_KEY=your_openai_api_key# Optional, for OpenAI LLM providerKIE_API_KEY=your_kie_api_key# Optional, for Kie.ai models (Sora, Veo, Kling, etc.)WORLDLABS_API_KEY=your_worldlabs_api_key# Optional, for WorldLabs Marble 3D generationREPLICATE_API_KEY=your_replicate_api_key# OptionalFAL_API_KEY=your_fal_api_key# OptionalMUAPI_API_KEY=your_muapi_api_key# Optional, for MuAPI modelsWAVESPEED_API_KEY=your_wavespeed_api_key# Optional, for WaveSpeed models# PORT=3001 # Optional, dev/prod server port (default 3000)# SPLAT_VIEWER_ORIGIN=http://host:8080 # Optional, hosted splat-viewer build to proxy# (not needed if you run `npm run viewer:install`)

Installation

npm install

Development

npm run dev

Open http://localhost:3000 in your browser (or from another machine on the LAN). Set PORT in .env.local to change the port.

Gaussian Splat Viewer (optional)

The /viewer page (Gaussian splat viewing, camera animation, video export) comes from the separate gitcapoom/splat-viewer project. It is a dependency — never embedded in this repo. One command installs it:

npm run viewer:install

This clones the viewer, builds it, and places the build in public/_viewer/ (gitignored). Restart the dev server and /viewer serves it locally. Re-run the command any time to update. Requires git on PATH.

Alternative for multi-app setups: host one build anywhere and set SPLAT_VIEWER_ORIGIN=http://host:port — node-banana reverse-proxies it under its own origin. Everything else works without the viewer installed.

Build

npm run build
npm run start

Node Reference

Input Nodes

NodeHandlesNotes
Image Inputout: imageLoad images from disk or paste
Audio Inputout: audioLoad audio files
Video Inputout: videoLoad MP4/WebM, thumbnail preview
Promptout: textText prompt with variable support
Arrayout: textArray of text values
Prompt Constructorin: text, out: textTemplate with variable interpolation

Generator Nodes

NodeHandlesNotes
Generate Imagein: image+text (+dynamic), out: imageGemini, Replicate, fal.ai, Kie.ai, MuAPI, WaveSpeed. Extra pins appear from the selected model's schema (mask, control image, …)
Upscale (Grid)in: image+text, out: imageGrid-split upscaling through generator models
Generate Videoin: image+text (+dynamic), out: videoVideo generation from image+prompt
Generate 3Din: image+text (+dynamic), out: 3d3D model generation
Image to Splatin: image, out: 3dSingle image → Gaussian Splat
Generate Audioin: text, out: audioAudio/music generation
LLM Generatein: text+image+video, out: textText generation (Gemini, OpenAI, Claude); video input analyzed by Gemini models only
Generate Panoramain: image+text, out: image+textWorldLabs Marble equirectangular pano
Generate Worldin: image, out: 3d+imageWorldLabs Marble 3D Gaussian Splat world
Sphere Light Renderout: imageLocally-rendered lit sphere (lighting reference)

Process Nodes

NodeHandlesNotes
Annotatein: image, out: imageDrawing tools overlay
Pano Editin: image ×2 + text, out: imageComposite an edited perspective back onto an equirect pano
Mask Painterin: image, out: imageInpainting mask editor (brush/eraser/shapes, blur, invert)
Rotoin: image, out: imageBezier/polygon roto shapes → matte
Compositein: image ×5 (BG, BG α, FG, FG α, Matte), out: imageNuke-style Merge: 22 ops, per-input transforms + blur/defocus filters, float pipeline
Blurin: image + matte, out: imageGaussian/Box/Motion/Zoom/Spin, matte-gated, mix control, float pipeline
Color Gradein: image, out: imageBlackpoint/whitepoint/lift/gain/multiply/offset/gamma (float chain)
HSV Color Correctin: image, out: imageHue/saturation/value (float chain)
Contrast Adjustin: image, out: imageS-curve contrast with roll-off + pivot (float chain)
Image Cropin: image, out: imagePersistent relative crop region, aspect lock
Mirrorin: image, out: imageHorizontal/vertical flip
Reformatin: image, out: imageResize with fill/fit modes
Cube ⇄ Panoin: image, out: imageCubemap cross ↔ equirectangular
Cube ⇄ Facesin/out: image ×6Cubemap ↔ six face images
Pano Shiftin: image, out: imageHorizontal shift with seam wrap
Split Gridin: image, out: referenceGrid subdivision
Video Stitchin: video+audio, out: videoConcatenate video clips
Video Trimin: video, out: videoTrim video start/end
Ease Curvein: video, out: videoSpeed ramp with bezier curves
Frame Grabin: video, out: imageExtract frame from video
Image Comparein: image x2Slide, Blend, Difference modes
Video Comparein: video x2Slide, Blend, Difference modes

Viewer Nodes

NodeHandlesNotes
3D Viewer (GLB)in: 3dThree.js orbit viewer, auto-rotation
Gaussian Splat Viewerin: 3dOpens the standalone splat viewer (/viewer): camera animation, DoF, lens distortion, video/depth export, COLMAP I/O
Pano Viewerin: image360 panorama viewer; captures perspective crops
Pano Cropauto-createdPerspective snapshot from the pano viewer, with camera metadata

Output Nodes

NodeHandlesNotes
Outputin: universalExport any media type with sidecar JSON
Output Galleryin: imageCollect multiple images

Route Nodes

NodeHandlesNotes
Routerin/out: anyPass-through routing
Switchin: any, out: switchedToggle outputs
Conditional Switchin: text, out: rule-basedRoute by text matching

Example Workflows

The /examples directory contains example workflow files. To use them:

  1. Start the dev server with npm run dev
  2. Drag any .json file from /examples into the browser window
  3. Review prompts before running — they're tuned for specific examples

Testing

npm test# Watch mode
npm run test:run # Single run
npm run test:coverage # With coverage report

License

MIT

About

Free and open node based generative workflows based on node-banana

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Node Banana (Capoom Fork)

A fork of Shrimbly's Node Banana with additional nodes, features, and fixes for production use on a LAN-accessible workstation.

Upstream: This fork tracks shrimbly/node-banana as the upstream remote. All additions are layered on top of the upstream feature set.

Architecture note (splat viewer): The Gaussian Splat Viewer is a separate project (gitcapoom/splat-viewer) — a dependency, never embedded in this repo. Run npm run viewer:install to clone + build it into a gitignored public/_viewer/ folder that /viewer serves directly; alternatively point SPLAT_VIEWER_ORIGIN at a hosted build to reverse-proxy it. See Gaussian Splat Viewer setup.

Node Banana Screenshot


What's Different from Upstream

New Nodes

NodeTypeDescription
Video InputInputLoad video files (MP4, WebM) from disk with thumbnail preview and lazy playback
RotoProcessBezier/polygon shape roto editor producing mattes (full-screen Konva editor, invert toggle)
CompositeProcessFloating-point clone of Nuke's Merge node: 22 merge ops, per-input affine transforms, external BG/FG alpha pins, matte pin, premultiply/swap/opacity controls, per-input blur/defocus filters
BlurProcessGPU blur with five filters (Gaussian, Box, Motion, Zoom, Spin), an optional matte input gating where the blur lands, invert + mix controls
DotProcessSmall circular reroute point for organising edge routing — ctrl+click any edge to insert one; selectable and deletable like any node
ViewerProcessLive tap on the graph — reflects upstream edits in realtime without a run (edit a roto matte and the composite lands here), and is selectable as a source from any node's full-screen view
Color GradeProcessNuke-style grade (blackpoint/whitepoint/lift/gain/multiply/offset/gamma) on the float GPU chain
HSV Color CorrectProcessHue shift / saturation / value on the float GPU chain
Contrast AdjustProcessS-curve contrast with roll-off and pivot on the float GPU chain
Image CropProcessPersistent relative-coordinate crop region with aspect lock
MirrorProcessHorizontal / vertical flips
ReformatProcessResize to target resolution with fill/fit modes and filter choice
Cube ⇄ Pano / Cube ⇄ FacesProcessCubemap cross ↔ equirectangular, and cubemap ↔ six face images
Pano ShiftProcessHorizontal panorama shift with seam wrap-around
Upscale (Grid)GenerateGrid-split upscaling through generator models
Image to SplatGenerateSingle image → 3D Gaussian Splat (feeds the splat viewer)
Sphere Light RenderGenerateLocally-rendered lit grey sphere from rotation/elevation/intensity (lighting reference)
Video CompareProcessSide-by-side video comparison with three modes: Slide (wipe), Blend (opacity), and Difference (pixel diff). Synced playback with wait-for-both restart
Image Compare (enhanced)ProcessAdded Blend and Difference modes with opacity control (upstream only has the slider)
GLB Viewer (enhanced)ViewerThree.js-based 3D model viewer with orbit controls, auto-rotation, background pin visibility toggle, and file persistence across workflow save/reload
Gaussian Splat Viewer (enhanced)ViewerRenamed from "SPZ Viewer". Added XYZ transform controls, camera animation timeline with keyframes, video export (H264/WebM), depth map capture (float-precision), and COLMAP export
Output Node (enhanced)OutputUniversal input handle accepting all media types. "Output Now" button for one-click export with sidecar JSON. Blob URL conversion for 3D files. Performance-optimized selectors

New Features

Float Color Pipeline

  • Color Grade / HSV / Contrast / Blur / Composite chain through 16-bit float GPU textures (WebGL2), so out-of-range values survive between nodes — no 8-bit clamp until the final consumer
  • Live in-node GPU previews at 60 fps; 8-bit PNG committed only after sliders settle
  • Composite inputs can each be pre-filtered (blur/defocus) before the merge, float-preserving

Dynamic Model Input Pins

  • Generator nodes grow input pins from the selected model's schema (mask, control image, multiple image slots, etc.)
  • Stable slot ids survive model switches and reloads; a single edge-conformance pass guarantees edges always match rendered pins (no ghost edges)

Reliability

  • Crash-safe workflow saves: writes go to a temp file, fsync, then atomic rename; the previous good save is kept as a rolling .bak; the loader falls back to the .bak (with a warning toast) if the main file is ever corrupt
  • Auto-save handles multi-hundred-MB media via chunked content hashing and URL-only handling for large provider videos
  • Per-node runs re-execute cheap local processors upstream first, so generators never read stale inputs

Output Now (Export Pipeline)

  • One-click export of any connected media (image, video, audio, 3D model) to a user-chosen directory
  • Automatically generates a sidecar .json file containing the upstream workflow (trimmed of carousel history)
  • Sidecar JSON can be re-imported by dragging onto the canvas, reconstructing the full upstream pipeline
  • Blob URLs are converted to base64 client-side before saving (server can't fetch blob URLs)
  • Workflow file stays small after export by externalizing all media fields

LAN / Network Access

  • Server binds to 0.0.0.0 for LAN access from other machines
  • allowedDevOrigins configured for cross-machine dev server access
  • Network path hints (\\server\share) in project setup
  • Web-based directory browser (replaced native OS picker for cross-network compatibility)
  • Client-side file:// URL opening with clipboard copy fallback for non-secure contexts

Cost Tracking

  • Per-generation cost display on all generator nodes using fal.ai Cost Estimation API
  • Session cost accumulator in the header
  • Generate3D and GenerateAudio nodes included in workflow cost breakdown

Media Handling

  • Videos and audio externalized during workflow save (keeps .json files small)
  • 3D models and audio cleared from output node data on save
  • Auto-restore of 3D models in GLB viewers after workflow reload
  • MediaOverlay component for consistent video/image overlay viewing
  • mediaCapture and mediaStorage utilities for thumbnail generation and disk persistence

WorldLabs Enhancements

  • Panorama preview with azimuth dropdowns and standalone viewer URL
  • Multi-image upload with azimuth metadata
  • is_pano checkbox on World Generator node
  • Auto-save SPZ and panorama files to generations folder
  • SessionStorage quota fix for large panorama data

Panorama Pipeline

  • Panorama Editor node with WebGL compositing
  • Perspective crop capture from panorama viewer
  • Focus viewer button and cleanup

Bug Fixes (Beyond Upstream)

  • Replicate: Polling timeout fix for queued predictions
  • Image display: object-contain instead of object-cover (images fit, not fill)
  • Output node: Fixed 5+ issues — folder creation, 3D input routing, reactive content detection, infinite loop from megabyte-length selector strings, invisible context menu edges (wrong handle IDs)
  • Edge routing: Images through "universal" handle were silently dropped; fixed with type === "image" fallback
  • Workflow inflation: Output node externalization now clears all media fields (was missing model3d, audio)
  • Sidecar JSON bloat: extractUpstreamWorkflow trims generate3d carousel history
  • 3D context menu: Renamed "GLB Viewer" to "3D Viewer", removed "Gaussian Splat Viewer", added "Output"
  • Depth map artifacts: Float render target, edge-preserving filter, morphological dilation, stochastic accumulation
  • Path handling: Mixed path separators, stale project directory after settings change, UNC path image loading

Removed from Upstream

  • Apple SHARP node — replaced by sharp-ml on Replicate

Tech Stack

  • Framework: Next.js 16 (App Router)
  • Language: TypeScript
  • Node Editor: @xyflow/react (React Flow v12)
  • Canvas: Konva.js / react-konva
  • 3D: Three.js (GLB viewer, panorama viewer), @sparkjsdev/spark (Gaussian Splatting)
  • State Management: Zustand
  • Styling: Tailwind CSS
  • AI Providers: Google Gemini, OpenAI, WorldLabs Marble, Replicate, fal.ai, Kie.ai, MuAPI, WaveSpeed

Getting Started

Prerequisites

  • Node.js 18+
  • npm

Environment Variables

Create a .env.local file in the root directory:

GEMINI_API_KEY=your_gemini_api_keyOPENAI_API_KEY=your_openai_api_key# Optional, for OpenAI LLM providerKIE_API_KEY=your_kie_api_key# Optional, for Kie.ai models (Sora, Veo, Kling, etc.)WORLDLABS_API_KEY=your_worldlabs_api_key# Optional, for WorldLabs Marble 3D generationREPLICATE_API_KEY=your_replicate_api_key# OptionalFAL_API_KEY=your_fal_api_key# OptionalMUAPI_API_KEY=your_muapi_api_key# Optional, for MuAPI modelsWAVESPEED_API_KEY=your_wavespeed_api_key# Optional, for WaveSpeed models# PORT=3001 # Optional, dev/prod server port (default 3000)# SPLAT_VIEWER_ORIGIN=http://host:8080 # Optional, hosted splat-viewer build to proxy# (not needed if you run `npm run viewer:install`)

Installation

npm install

Development

npm run dev

Open http://localhost:3000 in your browser (or from another machine on the LAN). Set PORT in .env.local to change the port.

Gaussian Splat Viewer (optional)

The /viewer page (Gaussian splat viewing, camera animation, video export) comes from the separate gitcapoom/splat-viewer project. It is a dependency — never embedded in this repo. One command installs it:

npm run viewer:install

This clones the viewer, builds it, and places the build in public/_viewer/ (gitignored). Restart the dev server and /viewer serves it locally. Re-run the command any time to update. Requires git on PATH.

Alternative for multi-app setups: host one build anywhere and set SPLAT_VIEWER_ORIGIN=http://host:port — node-banana reverse-proxies it under its own origin. Everything else works without the viewer installed.

Build

npm run build
npm run start

Node Reference

Input Nodes

NodeHandlesNotes
Image Inputout: imageLoad images from disk or paste
Audio Inputout: audioLoad audio files
Video Inputout: videoLoad MP4/WebM, thumbnail preview
Promptout: textText prompt with variable support
Arrayout: textArray of text values
Prompt Constructorin: text, out: textTemplate with variable interpolation

Generator Nodes

NodeHandlesNotes
Generate Imagein: image+text (+dynamic), out: imageGemini, Replicate, fal.ai, Kie.ai, MuAPI, WaveSpeed. Extra pins appear from the selected model's schema (mask, control image, …)
Upscale (Grid)in: image+text, out: imageGrid-split upscaling through generator models
Generate Videoin: image+text (+dynamic), out: videoVideo generation from image+prompt
Generate 3Din: image+text (+dynamic), out: 3d3D model generation
Image to Splatin: image, out: 3dSingle image → Gaussian Splat
Generate Audioin: text, out: audioAudio/music generation
LLM Generatein: text+image+video, out: textText generation (Gemini, OpenAI, Claude); video input analyzed by Gemini models only
Generate Panoramain: image+text, out: image+textWorldLabs Marble equirectangular pano
Generate Worldin: image, out: 3d+imageWorldLabs Marble 3D Gaussian Splat world
Sphere Light Renderout: imageLocally-rendered lit sphere (lighting reference)

Process Nodes

NodeHandlesNotes
Annotatein: image, out: imageDrawing tools overlay
Pano Editin: image ×2 + text, out: imageComposite an edited perspective back onto an equirect pano
Mask Painterin: image, out: imageInpainting mask editor (brush/eraser/shapes, blur, invert)
Rotoin: image, out: imageBezier/polygon roto shapes → matte
Compositein: image ×5 (BG, BG α, FG, FG α, Matte), out: imageNuke-style Merge: 22 ops, per-input transforms + blur/defocus filters, float pipeline
Blurin: image + matte, out: imageGaussian/Box/Motion/Zoom/Spin, matte-gated, mix control, float pipeline
Color Gradein: image, out: imageBlackpoint/whitepoint/lift/gain/multiply/offset/gamma (float chain)
HSV Color Correctin: image, out: imageHue/saturation/value (float chain)
Contrast Adjustin: image, out: imageS-curve contrast with roll-off + pivot (float chain)
Image Cropin: image, out: imagePersistent relative crop region, aspect lock
Mirrorin: image, out: imageHorizontal/vertical flip
Reformatin: image, out: imageResize with fill/fit modes
Cube ⇄ Panoin: image, out: imageCubemap cross ↔ equirectangular
Cube ⇄ Facesin/out: image ×6Cubemap ↔ six face images
Pano Shiftin: image, out: imageHorizontal shift with seam wrap
Split Gridin: image, out: referenceGrid subdivision
Video Stitchin: video+audio, out: videoConcatenate video clips
Video Trimin: video, out: videoTrim video start/end
Ease Curvein: video, out: videoSpeed ramp with bezier curves
Frame Grabin: video, out: imageExtract frame from video
Image Comparein: image x2Slide, Blend, Difference modes
Video Comparein: video x2Slide, Blend, Difference modes

Viewer Nodes

NodeHandlesNotes
3D Viewer (GLB)in: 3dThree.js orbit viewer, auto-rotation
Gaussian Splat Viewerin: 3dOpens the standalone splat viewer (/viewer): camera animation, DoF, lens distortion, video/depth export, COLMAP I/O
Pano Viewerin: image360 panorama viewer; captures perspective crops
Pano Cropauto-createdPerspective snapshot from the pano viewer, with camera metadata

Output Nodes

NodeHandlesNotes
Outputin: universalExport any media type with sidecar JSON
Output Galleryin: imageCollect multiple images

Route Nodes

NodeHandlesNotes
Routerin/out: anyPass-through routing
Switchin: any, out: switchedToggle outputs
Conditional Switchin: text, out: rule-basedRoute by text matching

Example Workflows

The /examples directory contains example workflow files. To use them:

  1. Start the dev server with npm run dev
  2. Drag any .json file from /examples into the browser window
  3. Review prompts before running — they're tuned for specific examples

Testing

npm test# Watch mode
npm run test:run # Single run
npm run test:coverage # With coverage report

License

MIT

About

Free and open node based generative workflows based on node-banana

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Node Banana (Capoom Fork)

A fork of Shrimbly's Node Banana with additional nodes, features, and fixes for production use on a LAN-accessible workstation.

Upstream: This fork tracks shrimbly/node-banana as the upstream remote. All additions are layered on top of the upstream feature set.

Architecture note (splat viewer): The Gaussian Splat Viewer is a separate project (gitcapoom/splat-viewer) — a dependency, never embedded in this repo. Run npm run viewer:install to clone + build it into a gitignored public/_viewer/ folder that /viewer serves directly; alternatively point SPLAT_VIEWER_ORIGIN at a hosted build to reverse-proxy it. See Gaussian Splat Viewer setup.

Node Banana Screenshot


What's Different from Upstream

New Nodes

NodeTypeDescription
Video InputInputLoad video files (MP4, WebM) from disk with thumbnail preview and lazy playback
RotoProcessBezier/polygon shape roto editor producing mattes (full-screen Konva editor, invert toggle)
CompositeProcessFloating-point clone of Nuke's Merge node: 22 merge ops, per-input affine transforms, external BG/FG alpha pins, matte pin, premultiply/swap/opacity controls, per-input blur/defocus filters
BlurProcessGPU blur with five filters (Gaussian, Box, Motion, Zoom, Spin), an optional matte input gating where the blur lands, invert + mix controls
DotProcessSmall circular reroute point for organising edge routing — ctrl+click any edge to insert one; selectable and deletable like any node
ViewerProcessLive tap on the graph — reflects upstream edits in realtime without a run (edit a roto matte and the composite lands here), and is selectable as a source from any node's full-screen view
Color GradeProcessNuke-style grade (blackpoint/whitepoint/lift/gain/multiply/offset/gamma) on the float GPU chain
HSV Color CorrectProcessHue shift / saturation / value on the float GPU chain
Contrast AdjustProcessS-curve contrast with roll-off and pivot on the float GPU chain
Image CropProcessPersistent relative-coordinate crop region with aspect lock
MirrorProcessHorizontal / vertical flips
ReformatProcessResize to target resolution with fill/fit modes and filter choice
Cube ⇄ Pano / Cube ⇄ FacesProcessCubemap cross ↔ equirectangular, and cubemap ↔ six face images
Pano ShiftProcessHorizontal panorama shift with seam wrap-around
Upscale (Grid)GenerateGrid-split upscaling through generator models
Image to SplatGenerateSingle image → 3D Gaussian Splat (feeds the splat viewer)
Sphere Light RenderGenerateLocally-rendered lit grey sphere from rotation/elevation/intensity (lighting reference)
Video CompareProcessSide-by-side video comparison with three modes: Slide (wipe), Blend (opacity), and Difference (pixel diff). Synced playback with wait-for-both restart
Image Compare (enhanced)ProcessAdded Blend and Difference modes with opacity control (upstream only has the slider)
GLB Viewer (enhanced)ViewerThree.js-based 3D model viewer with orbit controls, auto-rotation, background pin visibility toggle, and file persistence across workflow save/reload
Gaussian Splat Viewer (enhanced)ViewerRenamed from "SPZ Viewer". Added XYZ transform controls, camera animation timeline with keyframes, video export (H264/WebM), depth map capture (float-precision), and COLMAP export
Output Node (enhanced)OutputUniversal input handle accepting all media types. "Output Now" button for one-click export with sidecar JSON. Blob URL conversion for 3D files. Performance-optimized selectors

New Features

Float Color Pipeline

  • Color Grade / HSV / Contrast / Blur / Composite chain through 16-bit float GPU textures (WebGL2), so out-of-range values survive between nodes — no 8-bit clamp until the final consumer
  • Live in-node GPU previews at 60 fps; 8-bit PNG committed only after sliders settle
  • Composite inputs can each be pre-filtered (blur/defocus) before the merge, float-preserving

Dynamic Model Input Pins

  • Generator nodes grow input pins from the selected model's schema (mask, control image, multiple image slots, etc.)
  • Stable slot ids survive model switches and reloads; a single edge-conformance pass guarantees edges always match rendered pins (no ghost edges)

Reliability

  • Crash-safe workflow saves: writes go to a temp file, fsync, then atomic rename; the previous good save is kept as a rolling .bak; the loader falls back to the .bak (with a warning toast) if the main file is ever corrupt
  • Auto-save handles multi-hundred-MB media via chunked content hashing and URL-only handling for large provider videos
  • Per-node runs re-execute cheap local processors upstream first, so generators never read stale inputs

Output Now (Export Pipeline)

  • One-click export of any connected media (image, video, audio, 3D model) to a user-chosen directory
  • Automatically generates a sidecar .json file containing the upstream workflow (trimmed of carousel history)
  • Sidecar JSON can be re-imported by dragging onto the canvas, reconstructing the full upstream pipeline
  • Blob URLs are converted to base64 client-side before saving (server can't fetch blob URLs)
  • Workflow file stays small after export by externalizing all media fields

LAN / Network Access

  • Server binds to 0.0.0.0 for LAN access from other machines
  • allowedDevOrigins configured for cross-machine dev server access
  • Network path hints (\\server\share) in project setup
  • Web-based directory browser (replaced native OS picker for cross-network compatibility)
  • Client-side file:// URL opening with clipboard copy fallback for non-secure contexts

Cost Tracking

  • Per-generation cost display on all generator nodes using fal.ai Cost Estimation API
  • Session cost accumulator in the header
  • Generate3D and GenerateAudio nodes included in workflow cost breakdown

Media Handling

  • Videos and audio externalized during workflow save (keeps .json files small)
  • 3D models and audio cleared from output node data on save
  • Auto-restore of 3D models in GLB viewers after workflow reload
  • MediaOverlay component for consistent video/image overlay viewing
  • mediaCapture and mediaStorage utilities for thumbnail generation and disk persistence

WorldLabs Enhancements

  • Panorama preview with azimuth dropdowns and standalone viewer URL
  • Multi-image upload with azimuth metadata
  • is_pano checkbox on World Generator node
  • Auto-save SPZ and panorama files to generations folder
  • SessionStorage quota fix for large panorama data

Panorama Pipeline

  • Panorama Editor node with WebGL compositing
  • Perspective crop capture from panorama viewer
  • Focus viewer button and cleanup

Bug Fixes (Beyond Upstream)

  • Replicate: Polling timeout fix for queued predictions
  • Image display: object-contain instead of object-cover (images fit, not fill)
  • Output node: Fixed 5+ issues — folder creation, 3D input routing, reactive content detection, infinite loop from megabyte-length selector strings, invisible context menu edges (wrong handle IDs)
  • Edge routing: Images through "universal" handle were silently dropped; fixed with type === "image" fallback
  • Workflow inflation: Output node externalization now clears all media fields (was missing model3d, audio)
  • Sidecar JSON bloat: extractUpstreamWorkflow trims generate3d carousel history
  • 3D context menu: Renamed "GLB Viewer" to "3D Viewer", removed "Gaussian Splat Viewer", added "Output"
  • Depth map artifacts: Float render target, edge-preserving filter, morphological dilation, stochastic accumulation
  • Path handling: Mixed path separators, stale project directory after settings change, UNC path image loading

Removed from Upstream

  • Apple SHARP node — replaced by sharp-ml on Replicate

Tech Stack

  • Framework: Next.js 16 (App Router)
  • Language: TypeScript
  • Node Editor: @xyflow/react (React Flow v12)
  • Canvas: Konva.js / react-konva
  • 3D: Three.js (GLB viewer, panorama viewer), @sparkjsdev/spark (Gaussian Splatting)
  • State Management: Zustand
  • Styling: Tailwind CSS
  • AI Providers: Google Gemini, OpenAI, WorldLabs Marble, Replicate, fal.ai, Kie.ai, MuAPI, WaveSpeed

Getting Started

Prerequisites

  • Node.js 18+
  • npm

Environment Variables

Create a .env.local file in the root directory:

GEMINI_API_KEY=your_gemini_api_keyOPENAI_API_KEY=your_openai_api_key# Optional, for OpenAI LLM providerKIE_API_KEY=your_kie_api_key# Optional, for Kie.ai models (Sora, Veo, Kling, etc.)WORLDLABS_API_KEY=your_worldlabs_api_key# Optional, for WorldLabs Marble 3D generationREPLICATE_API_KEY=your_replicate_api_key# OptionalFAL_API_KEY=your_fal_api_key# OptionalMUAPI_API_KEY=your_muapi_api_key# Optional, for MuAPI modelsWAVESPEED_API_KEY=your_wavespeed_api_key# Optional, for WaveSpeed models# PORT=3001 # Optional, dev/prod server port (default 3000)# SPLAT_VIEWER_ORIGIN=http://host:8080 # Optional, hosted splat-viewer build to proxy# (not needed if you run `npm run viewer:install`)

Installation

npm install

Development

npm run dev

Open http://localhost:3000 in your browser (or from another machine on the LAN). Set PORT in .env.local to change the port.

Gaussian Splat Viewer (optional)

The /viewer page (Gaussian splat viewing, camera animation, video export) comes from the separate gitcapoom/splat-viewer project. It is a dependency — never embedded in this repo. One command installs it:

npm run viewer:install

This clones the viewer, builds it, and places the build in public/_viewer/ (gitignored). Restart the dev server and /viewer serves it locally. Re-run the command any time to update. Requires git on PATH.

Alternative for multi-app setups: host one build anywhere and set SPLAT_VIEWER_ORIGIN=http://host:port — node-banana reverse-proxies it under its own origin. Everything else works without the viewer installed.

Build

npm run build
npm run start

Node Reference

Input Nodes

NodeHandlesNotes
Image Inputout: imageLoad images from disk or paste
Audio Inputout: audioLoad audio files
Video Inputout: videoLoad MP4/WebM, thumbnail preview
Promptout: textText prompt with variable support
Arrayout: textArray of text values
Prompt Constructorin: text, out: textTemplate with variable interpolation

Generator Nodes

NodeHandlesNotes
Generate Imagein: image+text (+dynamic), out: imageGemini, Replicate, fal.ai, Kie.ai, MuAPI, WaveSpeed. Extra pins appear from the selected model's schema (mask, control image, …)
Upscale (Grid)in: image+text, out: imageGrid-split upscaling through generator models
Generate Videoin: image+text (+dynamic), out: videoVideo generation from image+prompt
Generate 3Din: image+text (+dynamic), out: 3d3D model generation
Image to Splatin: image, out: 3dSingle image → Gaussian Splat
Generate Audioin: text, out: audioAudio/music generation
LLM Generatein: text+image+video, out: textText generation (Gemini, OpenAI, Claude); video input analyzed by Gemini models only
Generate Panoramain: image+text, out: image+textWorldLabs Marble equirectangular pano
Generate Worldin: image, out: 3d+imageWorldLabs Marble 3D Gaussian Splat world
Sphere Light Renderout: imageLocally-rendered lit sphere (lighting reference)

Process Nodes

NodeHandlesNotes
Annotatein: image, out: imageDrawing tools overlay
Pano Editin: image ×2 + text, out: imageComposite an edited perspective back onto an equirect pano
Mask Painterin: image, out: imageInpainting mask editor (brush/eraser/shapes, blur, invert)
Rotoin: image, out: imageBezier/polygon roto shapes → matte
Compositein: image ×5 (BG, BG α, FG, FG α, Matte), out: imageNuke-style Merge: 22 ops, per-input transforms + blur/defocus filters, float pipeline
Blurin: image + matte, out: imageGaussian/Box/Motion/Zoom/Spin, matte-gated, mix control, float pipeline
Color Gradein: image, out: imageBlackpoint/whitepoint/lift/gain/multiply/offset/gamma (float chain)
HSV Color Correctin: image, out: imageHue/saturation/value (float chain)
Contrast Adjustin: image, out: imageS-curve contrast with roll-off + pivot (float chain)
Image Cropin: image, out: imagePersistent relative crop region, aspect lock
Mirrorin: image, out: imageHorizontal/vertical flip
Reformatin: image, out: imageResize with fill/fit modes
Cube ⇄ Panoin: image, out: imageCubemap cross ↔ equirectangular
Cube ⇄ Facesin/out: image ×6Cubemap ↔ six face images
Pano Shiftin: image, out: imageHorizontal shift with seam wrap
Split Gridin: image, out: referenceGrid subdivision
Video Stitchin: video+audio, out: videoConcatenate video clips
Video Trimin: video, out: videoTrim video start/end
Ease Curvein: video, out: videoSpeed ramp with bezier curves
Frame Grabin: video, out: imageExtract frame from video
Image Comparein: image x2Slide, Blend, Difference modes
Video Comparein: video x2Slide, Blend, Difference modes

Viewer Nodes

NodeHandlesNotes
3D Viewer (GLB)in: 3dThree.js orbit viewer, auto-rotation
Gaussian Splat Viewerin: 3dOpens the standalone splat viewer (/viewer): camera animation, DoF, lens distortion, video/depth export, COLMAP I/O
Pano Viewerin: image360 panorama viewer; captures perspective crops
Pano Cropauto-createdPerspective snapshot from the pano viewer, with camera metadata

Output Nodes

NodeHandlesNotes
Outputin: universalExport any media type with sidecar JSON
Output Galleryin: imageCollect multiple images

Route Nodes

NodeHandlesNotes
Routerin/out: anyPass-through routing
Switchin: any, out: switchedToggle outputs
Conditional Switchin: text, out: rule-basedRoute by text matching

Example Workflows

The /examples directory contains example workflow files. To use them:

  1. Start the dev server with npm run dev
  2. Drag any .json file from /examples into the browser window
  3. Review prompts before running — they're tuned for specific examples

Testing

npm test# Watch mode
npm run test:run # Single run
npm run test:coverage # With coverage report

License

MIT

About

Free and open node based generative workflows based on node-banana

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

Node Banana (Capoom Fork)

A fork of Shrimbly's Node Banana with additional nodes, features, and fixes for production use on a LAN-accessible workstation.

Upstream: This fork tracks shrimbly/node-banana as the upstream remote. All additions are layered on top of the upstream feature set.

Architecture note (splat viewer): The Gaussian Splat Viewer is a separate project (gitcapoom/splat-viewer) — a dependency, never embedded in this repo. Run npm run viewer:install to clone + build it into a gitignored public/_viewer/ folder that /viewer serves directly; alternatively point SPLAT_VIEWER_ORIGIN at a hosted build to reverse-proxy it. See Gaussian Splat Viewer setup.

Node Banana Screenshot


What's Different from Upstream

New Nodes

NodeTypeDescription
Video InputInputLoad video files (MP4, WebM) from disk with thumbnail preview and lazy playback
RotoProcessBezier/polygon shape roto editor producing mattes (full-screen Konva editor, invert toggle)
CompositeProcessFloating-point clone of Nuke's Merge node: 22 merge ops, per-input affine transforms, external BG/FG alpha pins, matte pin, premultiply/swap/opacity controls, per-input blur/defocus filters
BlurProcessGPU blur with five filters (Gaussian, Box, Motion, Zoom, Spin), an optional matte input gating where the blur lands, invert + mix controls
DotProcessSmall circular reroute point for organising edge routing — ctrl+click any edge to insert one; selectable and deletable like any node
ViewerProcessLive tap on the graph — reflects upstream edits in realtime without a run (edit a roto matte and the composite lands here), and is selectable as a source from any node's full-screen view
Color GradeProcessNuke-style grade (blackpoint/whitepoint/lift/gain/multiply/offset/gamma) on the float GPU chain
HSV Color CorrectProcessHue shift / saturation / value on the float GPU chain
Contrast AdjustProcessS-curve contrast with roll-off and pivot on the float GPU chain
Image CropProcessPersistent relative-coordinate crop region with aspect lock
MirrorProcessHorizontal / vertical flips
ReformatProcessResize to target resolution with fill/fit modes and filter choice
Cube ⇄ Pano / Cube ⇄ FacesProcessCubemap cross ↔ equirectangular, and cubemap ↔ six face images
Pano ShiftProcessHorizontal panorama shift with seam wrap-around
Upscale (Grid)GenerateGrid-split upscaling through generator models
Image to SplatGenerateSingle image → 3D Gaussian Splat (feeds the splat viewer)
Sphere Light RenderGenerateLocally-rendered lit grey sphere from rotation/elevation/intensity (lighting reference)
Video CompareProcessSide-by-side video comparison with three modes: Slide (wipe), Blend (opacity), and Difference (pixel diff). Synced playback with wait-for-both restart
Image Compare (enhanced)ProcessAdded Blend and Difference modes with opacity control (upstream only has the slider)
GLB Viewer (enhanced)ViewerThree.js-based 3D model viewer with orbit controls, auto-rotation, background pin visibility toggle, and file persistence across workflow save/reload
Gaussian Splat Viewer (enhanced)ViewerRenamed from "SPZ Viewer". Added XYZ transform controls, camera animation timeline with keyframes, video export (H264/WebM), depth map capture (float-precision), and COLMAP export
Output Node (enhanced)OutputUniversal input handle accepting all media types. "Output Now" button for one-click export with sidecar JSON. Blob URL conversion for 3D files. Performance-optimized selectors

New Features

Float Color Pipeline

  • Color Grade / HSV / Contrast / Blur / Composite chain through 16-bit float GPU textures (WebGL2), so out-of-range values survive between nodes — no 8-bit clamp until the final consumer
  • Live in-node GPU previews at 60 fps; 8-bit PNG committed only after sliders settle
  • Composite inputs can each be pre-filtered (blur/defocus) before the merge, float-preserving

Dynamic Model Input Pins

  • Generator nodes grow input pins from the selected model's schema (mask, control image, multiple image slots, etc.)
  • Stable slot ids survive model switches and reloads; a single edge-conformance pass guarantees edges always match rendered pins (no ghost edges)

Reliability

  • Crash-safe workflow saves: writes go to a temp file, fsync, then atomic rename; the previous good save is kept as a rolling .bak; the loader falls back to the .bak (with a warning toast) if the main file is ever corrupt
  • Auto-save handles multi-hundred-MB media via chunked content hashing and URL-only handling for large provider videos
  • Per-node runs re-execute cheap local processors upstream first, so generators never read stale inputs

Output Now (Export Pipeline)

  • One-click export of any connected media (image, video, audio, 3D model) to a user-chosen directory
  • Automatically generates a sidecar .json file containing the upstream workflow (trimmed of carousel history)
  • Sidecar JSON can be re-imported by dragging onto the canvas, reconstructing the full upstream pipeline
  • Blob URLs are converted to base64 client-side before saving (server can't fetch blob URLs)
  • Workflow file stays small after export by externalizing all media fields

LAN / Network Access

  • Server binds to 0.0.0.0 for LAN access from other machines
  • allowedDevOrigins configured for cross-machine dev server access
  • Network path hints (\\server\share) in project setup
  • Web-based directory browser (replaced native OS picker for cross-network compatibility)
  • Client-side file:// URL opening with clipboard copy fallback for non-secure contexts

Cost Tracking

  • Per-generation cost display on all generator nodes using fal.ai Cost Estimation API
  • Session cost accumulator in the header
  • Generate3D and GenerateAudio nodes included in workflow cost breakdown

Media Handling

  • Videos and audio externalized during workflow save (keeps .json files small)
  • 3D models and audio cleared from output node data on save
  • Auto-restore of 3D models in GLB viewers after workflow reload
  • MediaOverlay component for consistent video/image overlay viewing
  • mediaCapture and mediaStorage utilities for thumbnail generation and disk persistence

WorldLabs Enhancements

  • Panorama preview with azimuth dropdowns and standalone viewer URL
  • Multi-image upload with azimuth metadata
  • is_pano checkbox on World Generator node
  • Auto-save SPZ and panorama files to generations folder
  • SessionStorage quota fix for large panorama data

Panorama Pipeline

  • Panorama Editor node with WebGL compositing
  • Perspective crop capture from panorama viewer
  • Focus viewer button and cleanup

Bug Fixes (Beyond Upstream)

  • Replicate: Polling timeout fix for queued predictions
  • Image display: object-contain instead of object-cover (images fit, not fill)
  • Output node: Fixed 5+ issues — folder creation, 3D input routing, reactive content detection, infinite loop from megabyte-length selector strings, invisible context menu edges (wrong handle IDs)
  • Edge routing: Images through "universal" handle were silently dropped; fixed with type === "image" fallback
  • Workflow inflation: Output node externalization now clears all media fields (was missing model3d, audio)
  • Sidecar JSON bloat: extractUpstreamWorkflow trims generate3d carousel history
  • 3D context menu: Renamed "GLB Viewer" to "3D Viewer", removed "Gaussian Splat Viewer", added "Output"
  • Depth map artifacts: Float render target, edge-preserving filter, morphological dilation, stochastic accumulation
  • Path handling: Mixed path separators, stale project directory after settings change, UNC path image loading

Removed from Upstream

  • Apple SHARP node — replaced by sharp-ml on Replicate

Tech Stack

  • Framework: Next.js 16 (App Router)
  • Language: TypeScript
  • Node Editor: @xyflow/react (React Flow v12)
  • Canvas: Konva.js / react-konva
  • 3D: Three.js (GLB viewer, panorama viewer), @sparkjsdev/spark (Gaussian Splatting)
  • State Management: Zustand
  • Styling: Tailwind CSS
  • AI Providers: Google Gemini, OpenAI, WorldLabs Marble, Replicate, fal.ai, Kie.ai, MuAPI, WaveSpeed

Getting Started

Prerequisites

  • Node.js 18+
  • npm

Environment Variables

Create a .env.local file in the root directory:

GEMINI_API_KEY=your_gemini_api_keyOPENAI_API_KEY=your_openai_api_key# Optional, for OpenAI LLM providerKIE_API_KEY=your_kie_api_key# Optional, for Kie.ai models (Sora, Veo, Kling, etc.)WORLDLABS_API_KEY=your_worldlabs_api_key# Optional, for WorldLabs Marble 3D generationREPLICATE_API_KEY=your_replicate_api_key# OptionalFAL_API_KEY=your_fal_api_key# OptionalMUAPI_API_KEY=your_muapi_api_key# Optional, for MuAPI modelsWAVESPEED_API_KEY=your_wavespeed_api_key# Optional, for WaveSpeed models# PORT=3001 # Optional, dev/prod server port (default 3000)# SPLAT_VIEWER_ORIGIN=http://host:8080 # Optional, hosted splat-viewer build to proxy# (not needed if you run `npm run viewer:install`)

Installation

npm install

Development

npm run dev

Open http://localhost:3000 in your browser (or from another machine on the LAN). Set PORT in .env.local to change the port.

Gaussian Splat Viewer (optional)

The /viewer page (Gaussian splat viewing, camera animation, video export) comes from the separate gitcapoom/splat-viewer project. It is a dependency — never embedded in this repo. One command installs it:

npm run viewer:install

This clones the viewer, builds it, and places the build in public/_viewer/ (gitignored). Restart the dev server and /viewer serves it locally. Re-run the command any time to update. Requires git on PATH.

Alternative for multi-app setups: host one build anywhere and set SPLAT_VIEWER_ORIGIN=http://host:port — node-banana reverse-proxies it under its own origin. Everything else works without the viewer installed.

Build

npm run build
npm run start

Node Reference

Input Nodes

NodeHandlesNotes
Image Inputout: imageLoad images from disk or paste
Audio Inputout: audioLoad audio files
Video Inputout: videoLoad MP4/WebM, thumbnail preview
Promptout: textText prompt with variable support
Arrayout: textArray of text values
Prompt Constructorin: text, out: textTemplate with variable interpolation

Generator Nodes

NodeHandlesNotes
Generate Imagein: image+text (+dynamic), out: imageGemini, Replicate, fal.ai, Kie.ai, MuAPI, WaveSpeed. Extra pins appear from the selected model's schema (mask, control image, …)
Upscale (Grid)in: image+text, out: imageGrid-split upscaling through generator models
Generate Videoin: image+text (+dynamic), out: videoVideo generation from image+prompt
Generate 3Din: image+text (+dynamic), out: 3d3D model generation
Image to Splatin: image, out: 3dSingle image → Gaussian Splat
Generate Audioin: text, out: audioAudio/music generation
LLM Generatein: text+image+video, out: textText generation (Gemini, OpenAI, Claude); video input analyzed by Gemini models only
Generate Panoramain: image+text, out: image+textWorldLabs Marble equirectangular pano
Generate Worldin: image, out: 3d+imageWorldLabs Marble 3D Gaussian Splat world
Sphere Light Renderout: imageLocally-rendered lit sphere (lighting reference)

Process Nodes

NodeHandlesNotes
Annotatein: image, out: imageDrawing tools overlay
Pano Editin: image ×2 + text, out: imageComposite an edited perspective back onto an equirect pano
Mask Painterin: image, out: imageInpainting mask editor (brush/eraser/shapes, blur, invert)
Rotoin: image, out: imageBezier/polygon roto shapes → matte
Compositein: image ×5 (BG, BG α, FG, FG α, Matte), out: imageNuke-style Merge: 22 ops, per-input transforms + blur/defocus filters, float pipeline
Blurin: image + matte, out: imageGaussian/Box/Motion/Zoom/Spin, matte-gated, mix control, float pipeline
Color Gradein: image, out: imageBlackpoint/whitepoint/lift/gain/multiply/offset/gamma (float chain)
HSV Color Correctin: image, out: imageHue/saturation/value (float chain)
Contrast Adjustin: image, out: imageS-curve contrast with roll-off + pivot (float chain)
Image Cropin: image, out: imagePersistent relative crop region, aspect lock
Mirrorin: image, out: imageHorizontal/vertical flip
Reformatin: image, out: imageResize with fill/fit modes
Cube ⇄ Panoin: image, out: imageCubemap cross ↔ equirectangular
Cube ⇄ Facesin/out: image ×6Cubemap ↔ six face images
Pano Shiftin: image, out: imageHorizontal shift with seam wrap
Split Gridin: image, out: referenceGrid subdivision
Video Stitchin: video+audio, out: videoConcatenate video clips
Video Trimin: video, out: videoTrim video start/end
Ease Curvein: video, out: videoSpeed ramp with bezier curves
Frame Grabin: video, out: imageExtract frame from video
Image Comparein: image x2Slide, Blend, Difference modes
Video Comparein: video x2Slide, Blend, Difference modes

Viewer Nodes

NodeHandlesNotes
3D Viewer (GLB)in: 3dThree.js orbit viewer, auto-rotation
Gaussian Splat Viewerin: 3dOpens the standalone splat viewer (/viewer): camera animation, DoF, lens distortion, video/depth export, COLMAP I/O
Pano Viewerin: image360 panorama viewer; captures perspective crops
Pano Cropauto-createdPerspective snapshot from the pano viewer, with camera metadata

Output Nodes

NodeHandlesNotes
Outputin: universalExport any media type with sidecar JSON
Output Galleryin: imageCollect multiple images

Route Nodes

NodeHandlesNotes
Routerin/out: anyPass-through routing
Switchin: any, out: switchedToggle outputs
Conditional Switchin: text, out: rule-basedRoute by text matching

Example Workflows

The /examples directory contains example workflow files. To use them:

  1. Start the dev server with npm run dev
  2. Drag any .json file from /examples into the browser window
  3. Review prompts before running — they're tuned for specific examples

Testing

npm test# Watch mode
npm run test:run # Single run
npm run test:coverage # With coverage report

License

MIT

About

Free and open node based generative workflows based on node-banana

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages