Nodes/lf-nodes/Scene Spec
ComfyUI Node

Scene Spec

One node, one scene, in ComfyUI's visual-novel authoring suite

By lucafoscili·Created 2 years ago·Updated a day ago· 35
Scene Spec
  • scene_id
  • scene_body
  • graph
  • graph
  • scene
  • scene_ref
titleOpening

Writing a branching narrative in a node editor sounds absurd, and then you remember that a visual novel is basically a directed graph of scenes and choices - which is precisely the kind of thing ComfyUI already models. LF_SceneSpec is the pack's scene-authoring node: one node declares exactly one scene, and you chain scenes together to build a full narrative graph. It's part of a small suite (Scene Spec, VN Switch, VN State, Compile VN) that authors, validates, and compiles deterministic, target-neutral narrative graphs - think "the story as data," with no renderer, engine, or live state attached.

The framing matters: this suite is CPU-only and target-neutral. It produces a validated JSON declaration of a scene - participants, beats of dialogue, choices, art requests - not a playable game. A consumer (a game engine, a workflow runner, a web app) takes the compiled bundle and does the actual rendering. What you get here is the authoring contract: describe the story precisely once, in a form that can be validated and reused.

What a scene body looks like

The scene_body textarea takes one strict-JSON object with exactly five root fields:

{
  "participants": [],
  "entryPredicate": {},
  "beats": [ { "text": "A new story begins." } ],
  "choices": [],
  "artRequests": []
}
  • participants - semantic IDs for who's in the scene.
  • entryPredicate - optional condition for entering the scene.
  • beats - dialogue beats; each needs an id and either text or a localizationKey.
  • choices - branching options; each needs an id and either label or a localizationKey, and may carry visibility/availability predicates, effects, and a nextSceneId.
  • artRequests - requests for images per beat/choice (this is a ComfyUI suite, after all - art is data too).

Missing LF-owned child IDs get materialized only by the authoring UI once the JSON is valid, so headless/API users must supply their own IDs.

The identity system - read this

scene_id isn't a free-form label; it's an LF_ID, a persistent identity generated once by the authoring UI and kept stable in the node. The title becomes the friendly label, and IDs must follow the contract (ASCII letters/digits plus . _ : / -, max 200 chars). You also get a graph input/output: leave it empty for the first scene, then chain each preceding graph output into the next scene's graph input. Outputs are graph (the declaration chain), scene (the validated scene as generic JSON), and scene_ref (a typed reference other nodes use to point at this scene). Narrative transitions stay symbolic - the execution chain can remain linear even as the graph branches.

Installing and where it fits

It's in the LF Nodes pack:

cd ComfyUI/custom_nodes
git clone https://github.com/lucafoscili/lf-nodes.git

restart (or ComfyUI Manager → "LF Nodes"). No model downloads - the whole VN suite is pure Python. Pack notes as usual: Pillow pinned 12.2.0, and the repo was rewritten/archived in 2025, so clone lucafoscili/lf-nodes.

Reach for this when you're building a story pipeline in ComfyUI: describe scenes here, branch with LF_VNSwitch, define fixture state with LF_VNState, and finish at LF_VNCompile. The main gotcha is invalid JSON - the body must parse strictly, and the authoring UI is where missing child IDs get filled in, so hand-writing bodies for headless runs means being scrupulous about IDs. If that's your setup, keep the contract doc (the pack's docs/VISUAL_NOVEL.md) open. It's a niche tool, but for deterministic narrative-as-data it's a surprisingly clean one.

Category✨ LF Nodes/Visual Novel

Inputs (4)

NameTypeDefaultDescription
scene_idLF_IDLF-owned persistent scene identity. Generated once by the authoring UI.
titleSTRINGOpeningOptional author-facing scene title.
scene_bodyLF_TEXTAREA{ "participants": [], "entryPredicate": {}, "beats": [ { "text": "A new story begins." } ], "choices": [], "artRequests": [] }One strict-JSON scene body containing participants, entryPredicate, beats, choices, and artRequests. Missing LF-owned child IDs are materialized only by the authoring UI after valid JSON.
graphoptLF_VN_GRAPHAn existing declaration chain. Narrative transitions remain symbolic, so this execution chain may stay linear.

Outputs (3)

NameTypeDescription
graphLF_VN_GRAPHDeclaration chain with this scene appended in authored order.
sceneJSONValidated scene declaration through a generic JSON socket.
scene_refLF_REFPersistent scene reference for typed LF_REF connections.