Skip to content

About

Nodes for Comfy UI

Resources

Stars

4 stars

Watchers

0 watching

Forks

Latest commit

 

History

6 Commits

Folders and files

Repository files navigation

Norfmare Nodes for ComfyUI

A custom-node pack for the Norfmare AI animation pipeline. Audio loading and chunking, image cycling, prompt sequencing, transcript-based audio editing — everything wired together so a long workflow can run on a single queue button.

Every node displays as <Name> (Norfmare) so they all sort together in the search box.


Install

Place the folder at ComfyUI/custom_nodes/norfmare_nodes/ (with __init__.py inside). Restart ComfyUI.

Optional dependencies

Feature Install
Timecoded Transcribe / Surgical Slicer pip install faster-whisper
Prompt Relay Cycler requires kijai/ComfyUI-PromptRelay

Both are lazy-imported — the rest of the pack still loads if either is missing. Affected nodes raise a clear error message at runtime telling you what to install.

If faster-whisper throws a CUDA library error on first transcription:

pip install nvidia-cublas-cu12 nvidia-cudnn-cu12==9.*

Reset semantics (applies to all cycling nodes)

Every cycler has a reset_* boolean toggle. The toggle fires once per OFF → ON transition, then auto-disarms internally. Leave it in either position without it locking the node to start every run. To reset again later: flip OFF, then back ON.


Nodes

Audio

Folder Audio Loader (Norfmare) — loads audio files from a folder. Three modes:

  • auto_increment — advances every queue, wraps at end
  • manual — uses the index value as-is
  • random — picks randomly each run

Audio Splitter (Norfmare) — splits a long audio into numbered equal-length clips on disk. Wire an AUDIO input or paste a file path. Output filenames are zero-padded so Folder Audio Loader reads them in order.

Timecoded Transcribe (Norfmare) — runs faster-whisper on an audio input and produces three things in one shot:

  • chunked_transcripts (LIST of strings) — the transcript split into fixed-duration chunks aligned to your video clip length. Set chunk_duration=20 and chunk 0 is exactly what's spoken in seconds 0–20.
  • num_chunks (INT) — the chunk count, plug straight into your batch sequencer.
  • word_data (LIST of word dicts) — raw word-level timing for the editor pipeline below.

Words bucket by their start time, so a word that straddles a chunk boundary stays whole, assigned to whichever chunk it began in. Model stays cached in process memory between runs, so subsequent calls in the same session skip the load step.

Pick Chunk (Norfmare) — pulls one chunk by index out of chunked_transcripts as a STRING. Use it inside a loop to feed one chunk at a time into a prompt builder.

Export Markup (Norfmare) — writes the marked-up transcript to ComfyUI/output/<filename>.txt, plus a <filename>_data.json sidecar containing the word_data. The text file looks like:

[0]Hello [1]everyone [2]um [3]welcome [4]to [5]the [6]uh [7]channel

Open it in any text editor, delete the [N]word tokens you don't want, save. To kill the um and uh:

[0]Hello [1]everyone [3]welcome [4]to [5]the [7]channel

You can retype words, add line breaks, paste it into a notes app — anything between the [N] markers is ignored on parse. Only the markers matter.

Import Markup (Norfmare) — reads the edited file (or pasted text) and outputs a LIST of kept word indices. Has a load_from_file input that auto-re-executes when the file's modification time changes, so re-saving the file picks up new edits without manually re-queueing tricks.

Surgical Slicer (Norfmare) — takes the original AUDIO, the original word_data, and the kept indices, and produces a click-free edited AUDIO. Four-stage cut at every splice:

  1. Padding (default 50 ms) — keeps word edges from getting clipped
  2. Acoustic refinement (default ±100 ms search) — finds the actual silence point near Whisper's reported word boundary, since Whisper's timestamps are good but not perfect
  3. Zero-crossing snap — splices at the nearest waveform zero crossing (mathematically click-free)
  4. Equal-power crossfade (default 8 ms) — kills any residual click. At 8 ms it's inaudible.

Has an optional load_word_data_from_file input pointing at the JSON sidecar — means second-pass slicing skips the transcribe node entirely. ~30 seconds saved per iteration when you're tweaking edits.

The editor workflow

LoadAudio ──► Timecoded Transcribe ──► word_data ──┬──► Export Markup
                                                    │           │
                                                    │     [edit the .txt]
                                                    │           │
                                                    │     Import Markup
                                                    │           │
                                                    └──► Surgical Slicer ──► SaveAudio

Two-pass: run once to generate the markup file, edit it, run again to produce the cut audio.

Image

Folder Image Loader (Norfmare) — sequential image cycler from any folder. repeat_count lets you reuse the same image across N consecutive queue runs before advancing.

Text

Prompt Cycler (Norfmare) — cycles through numbered prompts pasted into a multiline text field. Each prompt starts with N. at the start of a line; periods inside prompts are preserved.

Prompt Relay Cycler (Norfmare) — drop-in replacement for Kijai's PromptRelayEncode. Same MODEL/CLIP/LATENT inputs, same MODEL/CONDITIONING outputs, but with multi-shot scenarios in a text field that cycles across runs. Each scenario block is N. GLOBAL: <global prompt> followed by indented <pixel_length>: <prompt> lines. Requires ComfyUI-PromptRelay.


norfmare_aroll

A-roll talking-head compositor for ComfyUI. Held stills + automatic mouth animation (Rhubarb) + deterministic pose timing. No diffusion, no morphing, no per-frame generation. Everything runs as ComfyUI nodes.

What it does

Takes a voice track and a small library of hand-made still poses, and outputs a finished talking-head video where:

  • the correct mouth shape is placed on each character at each moment (driven by Rhubarb Lip Sync),
  • the pose changes on natural speech pauses (no LLM required),
  • each held pose gets a gentle "moving hold" drift so it breathes instead of sitting dead - all via transforms, so zero morph,
  • frames stream to disk and are muxed to mp4 with ffmpeg (15-min safe on 12 GB VRAM, because nothing is held as one big tensor).

Install

  1. Copy the norfmare_aroll folder into ComfyUI/custom_nodes/.
  2. Needs: numpy, pillow, opencv-python (almost always already in a ComfyUI env). Optional: mediapipe (only for face anchor mode).
  3. For lip sync, download Rhubarb from github.com/DanielSWolf/rhubarb-lip-sync and either put it on PATH or pass the full path into the node.
  4. ffmpeg must be on PATH (it already is for most ComfyUI installs). Restart ComfyUI. Nodes appear under Add Node > Norfmare > A-Roll.

Asset conventions

Pose library folder - one PNG per pose, transparent background. upright.png slumped.png cocky.png ... pose_id = filename stem. These are what the timeline switches between. Optional: a sidecar upright.json next to it with a hand-set anchor: {"x":0.50,"y":0.62,"scale":0.18,"angle":0.0} (anchors are normalised 0..1 of the canvas; scale = mouth width fraction)

Mouth set folder - one PNG per Rhubarb shape, transparent background. A.png B.png C.png D.png E.png F.png (+ optional G.png H.png X.png) X = rest/closed. These are your hand-drawn mouths in your art style.

Anchor modes (NFV_LoadPoseLibrary)

sidecar_or_blob - use sidecar json if present, else auto-find a dark hole (Dork Boy's mouth hole on a light body). DEFAULT. sidecar_or_face - sidecar else mediapipe face mouth (Sad Alec etc.) blob / face - force auto-detect, ignore sidecar sidecar_only - manual anchors only If a pose ends up with no anchor it gets a centre fallback and is listed in the node's info output so you can fix it.

The graph (A-roll, no LLM)

LoadAudio ─┬─> NFV_RhubarbLipSync ──> mouth_cues ─┐ │ (recognizer = phonetic for Norwegian) ├─> NFV_AutoPoseTimeline ─> timeline ──┤ │ ▲ │ NFV_LoadPoseLibrary ─┴─> pose_lib ────────────────┤ NFV_LoadMouthSet ───────> mouth_set ──────────────┤ v NFV_TalkingHeadCompositor ──> mp4 + preview (feed the same AUDIO in for the soundtrack)

Norwegian

Rhubarb's accurate recognizer (pocketSphinx) is English only. For Norwegian VO use recognizer = phonetic - language-independent, slightly looser timing, fine for stylised cartoon mouths.

The liveliness dial

Compositor liveliness 0..1: 0.0 = pure snap-cut, dead-still holds (most South-Park / Gilliam) 0.4 = subtle breath + sway (default) 1.0 = obvious drift, sway, micro-zoom All of it is transform-based. It never reintroduces morph.

Pose-change wobble + swish

On every pose change the compositor can:

  • WOBBLE: a damped overshoot (the puppet 'lands' into the new pose). Toggle wobble; wobble_amount 0..1 scales it. Pure transform, zero morph.
  • SWISH: a whoosh SFX placed exactly on each pose-change time, mixed into the voice track. Toggle swish; swish_gain sets level. Leave swish_wav blank for a synthesized whoosh, or point it at your own .wav. Pose-change times come straight from the timeline, so both stay in sync with the cuts automatically.

Optional blink

Point blink_png at a closed-eyes PNG and set blink_x/y/scale; eyes close briefly every blink_interval seconds. Leave blank to disable.

Upgrade path (when you want editorial smarts)

The compositor is deliberately dumb. To let an LLM decide poses instead of the pause-based auto-timeline, have it write a JSON like: {"timeline":[{"start":0.0,"end":3.2,"pose_id":"slumped"}, ...]} and feed it through NFV_PoseTimelineFromJSON in place of NFV_AutoPoseTimeline. Nothing else changes. Same for mouth cues via NFV_LoadMouthCuesJSON if you run Rhubarb yourself.

Honest limits (v1)

  • Poses are held stills; this is limited/cutout animation, not full motion. That's the point - it's what kills the morph.
  • Anchors assume a fairly stable head within a pose. Big in-pose head moves would need per-frame anchors (not in v1).
  • Auto-timeline cuts on pauses and rotates poses without repeats; it has no sense of meaning. That lives in the LLM upgrade path above.
  • The mouth set is shared across poses and placed at each pose's anchor; if a pose needs a differently-shaped mouth, give it its own anchor/scale.

License

MIT for this code. faster-whisper is MIT. Whisper itself is MIT (OpenAI). All commercially clear.

About

Nodes for Comfy UI

Resources

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages