diff --git a/.gitattributes b/.gitattributes index d301f80c3c3ead754cfe81c3469221667bebea43..33251842d09934c50e90f811ff99ad6b7942f144 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1264,3 +1264,28 @@ checkpoint_h3_context_loop/h3_chains/twerk_sur_lit_fl2va_2/reviews/clip_0003.2d3 checkpoint_h3_context_loop/h3_chains/twerk_sur_lit_fl2va_2/segments/clip_0001.6b9aeb22d21146e3811ef0e8c3d3f9be.mp4 filter=lfs diff=lfs merge=lfs -text checkpoint_h3_context_loop/h3_chains/twerk_sur_lit_fl2va_2/segments/clip_0002.2f3e5fc154f04b70aa603272e3509f79.mp4 filter=lfs diff=lfs merge=lfs -text checkpoint_h3_context_loop/h3_chains/twerk_sur_lit_fl2va_2/segments/clip_0003.bb8250496ae84b96ae7a727f88420d5f.mp4 filter=lfs diff=lfs merge=lfs -text +ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/assets/adapter_chaos_derope_triptych.mp4 filter=lfs diff=lfs merge=lfs -text +ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/assets/adapter_drop_full3x_triptych.mp4 filter=lfs diff=lfs merge=lfs -text +ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/assets/adapter_mage_pinned_quad.mp4 filter=lfs diff=lfs merge=lfs -text +ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/assets/adapter_ref2va_colour_muting.mp4 filter=lfs diff=lfs merge=lfs -text +ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/assets/adapter_rooftop_ood_triptych.mp4 filter=lfs diff=lfs merge=lfs -text +ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/assets/adapter_t2c_insert_quad.mp4 filter=lfs diff=lfs merge=lfs -text +ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/assets/baseline_vs_regenerated_sbs.mp4 filter=lfs diff=lfs merge=lfs -text +ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/assets/derope_sbs.gif filter=lfs diff=lfs merge=lfs -text +ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/assets/featherweight_flf_triptych.mp4 filter=lfs diff=lfs merge=lfs -text +ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/assets/featherweight_i2v_triptych.mp4 filter=lfs diff=lfs merge=lfs -text +ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/assets/featherweight_int8_vs_w4a8_quad.mp4 filter=lfs diff=lfs merge=lfs -text +ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/assets/featherweight_ref_triptych.mp4 filter=lfs diff=lfs merge=lfs -text +ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/assets/kitsune_threeway.gif filter=lfs diff=lfs merge=lfs -text +ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/assets/kitsune_threeway_sbs.mp4 filter=lfs diff=lfs merge=lfs -text +ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/assets/oracle_map.gif filter=lfs diff=lfs merge=lfs -text +ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/assets/oracle_map.mp4 filter=lfs diff=lfs merge=lfs -text +ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/assets/panrun_sbs.mp4 filter=lfs diff=lfs merge=lfs -text +ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/assets/preview_ladder_grid.mp4 filter=lfs diff=lfs merge=lfs -text +ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/assets/time_burst_plate.mp4 filter=lfs diff=lfs merge=lfs -text +ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/assets/time_burst_result.mp4 filter=lfs diff=lfs merge=lfs -text +ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/assets/uniform_vs_adaptive.gif filter=lfs diff=lfs merge=lfs -text +ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/assets/uniform_vs_adaptive_sbs.mp4 filter=lfs diff=lfs merge=lfs -text +ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/docs/latents/frame0.png filter=lfs diff=lfs merge=lfs -text +ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/docs/latents/frame72.png filter=lfs diff=lfs merge=lfs -text +ComfyUI-MiniMaxH3-Context-Loop/__pycache__/chain_nodes.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text diff --git a/ComfyUI-MiniMaxH3-Context-Loop/.github/workflows/publish_action.yml b/ComfyUI-MiniMaxH3-Context-Loop/.github/workflows/publish_action.yml new file mode 100644 index 0000000000000000000000000000000000000000..a9a5fed52d2672dbdade80442170a972f4554f20 --- /dev/null +++ b/ComfyUI-MiniMaxH3-Context-Loop/.github/workflows/publish_action.yml @@ -0,0 +1,24 @@ +name: Publish to Comfy Registry + +on: + workflow_dispatch: + push: + branches: + - main + paths: + - pyproject.toml + +permissions: + contents: read + +jobs: + publish-node: + name: Publish custom node + runs-on: ubuntu-latest + steps: + - name: Check out code + uses: actions/checkout@v4 + - name: Publish custom node + uses: Comfy-Org/publish-node-action@main + with: + personal_access_token: ${{ secrets.REGISTRY_ACCESS_TOKEN }} diff --git a/ComfyUI-MiniMaxH3-Context-Loop/.gitignore b/ComfyUI-MiniMaxH3-Context-Loop/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..f707b710c5cf21d90e0645426fdabd25118591bf --- /dev/null +++ b/ComfyUI-MiniMaxH3-Context-Loop/.gitignore @@ -0,0 +1,3 @@ +__pycache__/ +*.pyc +.release-drafts/ diff --git a/ComfyUI-MiniMaxH3-Context-Loop/AGENT_PROMPT_ASSISTANT_STUDY.md b/ComfyUI-MiniMaxH3-Context-Loop/AGENT_PROMPT_ASSISTANT_STUDY.md new file mode 100644 index 0000000000000000000000000000000000000000..f7206ac3a536d3633bfafa6542adc60f137b0e4a --- /dev/null +++ b/ComfyUI-MiniMaxH3-Context-Loop/AGENT_PROMPT_ASSISTANT_STUDY.md @@ -0,0 +1,328 @@ +# Agent-backed prompt assistant study + +## Finding + +Yes, the Scene Prompt Editor can host an interactive prompt assistant for Codex +and Hermes. + +The first implementation now exists on this study branch together with the +`feature/prompt-assistant-bridge` comfyui-mcp branch. It follows the isolated, +staged design below. Codex uses app-server; the initial Hermes adapter uses its +tool-restricted one-shot interface while a persistent ACP adapter remains a +possible later optimization. + +The recommended architecture is: + +```text +Scene Prompt Editor DOM widget + | + | prompt-assist request / progress / staged result + v +comfyui-mcp local orchestrator + | + +-- Codex app-server backend + +-- Hermes tool-restricted one-shot adapter (initial) + +-- persistent ACP adapter (later option) +``` + +The assistant should have its own restricted conversation and a correlated +request/response protocol. It should not borrow the sidebar panel's main chat +session, open a second socket under the panel's workflow identity, or launch an +agent process from ComfyUI's Python server. + +## What exists today + +### This pack + +`MiniMaxH3ChainScenePromptEditor` is a pass-through Python node. Its useful +behavior lives in `web/h3_chain_scene_prompt_editor.js` as a DOM widget. + +The editor finds the upstream `MiniMaxH3ChainPlan`, parses its `plan_json`, and +writes the active scene's real `shots[n].prompt` back to that Plan widget on +every edit. There is no duplicate prompt value. This is a good base for an +assistant because a draft can be staged beside the textarea and applied through +the existing `writePlan()` path. + +### comfyui-mcp and its panel + +The panel already connects a browser client to a local `comfyui-mcp` +orchestrator over WebSocket. The orchestrator owns provider authentication, +agent sessions, streaming, model discovery, interruption, and live ComfyUI +tools. Codex is a native orchestrator backend. + +Hermes support currently means `comfyui-mcp setup hermes`: it registers the +ComfyUI MCP server in Hermes so a Hermes console agent can control ComfyUI. +Hermes is not currently a panel-orchestrator backend and does not speak the +panel bridge protocol. + +The panel bridge cannot safely be reused as-is by this node: + +- its bridge client is private to the panel bundle; +- a workflow route is designed to have one live browser socket; +- the orchestrator deliberately shares one conversation per provider across + panel tabs and workflows; +- `user_message` replies are chat frames, not request-correlated rewrite + results. + +A second node client using the current `hello`/`user_message` protocol could +replace the panel's route or mix rewrite output into the user's main panel +conversation. + +### Agent-native integration surfaces + +Codex documents app-server as the interface for a deep product integration. It +provides threads, turns, streamed events, approvals, interruption, and JSON-RPC. +`codex exec` is intended for non-interactive scripts and is useful for a small +one-shot proof of concept, but app-server (or the Codex SDK which controls it) +is the appropriate persistent implementation. `comfyui-mcp` already contains a +Codex app-server adapter, so that work should be reused. + +The installed Hermes CLI exposes three relevant surfaces: + +- `hermes --oneshot` for a scriptable one-shot response; +- `hermes --resume ` for continuing a stored session; +- `hermes acp` and `hermes serve` for editor/backend integrations. + +ACP or the backend service is preferable for the final persistent assistant. +One-shot mode is sufficient to validate prompt quality and UX before adding a +full Hermes backend adapter. + +## Recommended user experience + +Add a collapsible **Prompt Assistant** area below the scene textarea: + +- provider: Codex or Hermes; +- action presets: Rewrite, Improve continuity, Shorten, Critique; +- a free-form instruction box and Send/Stop buttons; +- a compact transcript for follow-up requests; +- a staged draft view with Apply, Copy, and Discard; +- connection, working, and error status that does not replace the editor's + existing Plan synchronization status. + +The agent's result must be staged. Streaming tokens must never mutate the Plan. +Only an explicit Apply/Replace action should call the existing `writePlan()` +path. + +Suggested interaction: + +1. The user edits the current scene prompt. +2. The user asks, for example, "Make the camera movement more precise and keep + the unfinished action for scene 4." +3. The node sends the current scene, shared prompt, and bounded neighboring + continuity context. +4. The UI shows working/progress state while the assistant builds a structured + result. +5. The node shows the proposed prompt separately. +6. The user applies or discards it, then can continue chatting about the staged + draft. + +The entire plan should not be sent by default. Useful bounded context is: + +- shared prompt; +- current scene id, duration, and prompt; +- previous scene's ending and next scene's opening (or the complete neighboring + prompts while they remain under a strict size limit); +- reference tags available to the workflow; +- the prompt-writing rules bundled with this pack. + +## Implemented bridge protocol + +The implementation adds a prompt-assistant client kind and correlated frames to +`comfyui-mcp`. + +Client request: + +```json +{ + "type": "prompt_assist_request", + "request_id": "pa-uuid", + "conversation_id": "h3-browser-instance-uuid", + "provider": "codex", + "mode": "rewrite", + "instruction": "Improve camera precision and ending continuity.", + "source_revision": "opaque-source-text-and-scene-id-revision", + "context": { + "scene_id": "clip_0003", + "source_prompt": "...", + "selected_text": null, + "shared_prompt": "...", + "previous_prompt": "...", + "next_prompt": "..." + } +} +``` + +Server frames: + +```json +{"type":"prompt_assist_started","request_id":"pa-uuid","provider":"codex"} +{"type":"prompt_assist_progress","request_id":"pa-uuid"} +{ + "type": "prompt_assist_result", + "request_id": "pa-uuid", + "source_revision": "opaque-source-text-and-scene-id-revision", + "message": "What changed and why.", + "rewritten_prompt": "The complete proposed scene prompt." +} +{"type":"prompt_assist_error","request_id":"pa-uuid","error":"..."} +``` + +Cancellation: + +```json +{"type":"prompt_assist_cancel","request_id":"pa-uuid"} +``` + +The canonical final result is schema-constrained. A conversational message and +the complete replacement prompt are separate fields. Codex enforces the schema; +the initial Hermes adapter also accepts a plain-text fallback so older local +Hermes models remain usable. + +For an HTTPS-hosted ComfyUI, use the panel's existing advertised secure bridge +mechanism. A page served over HTTPS cannot directly use an insecure localhost +WebSocket. + +## Session and tool boundaries + +Use a session key such as: + +```text +prompt-assistant:::::: +``` + +This session must be separate from `orchestrator::`, the panel's main +conversation. Switching providers should preserve each provider's assistant +session, as the panel already does for its provider conversations. + +The prompt assistant should be text-only and tool-free by default: + +- no shell or file editing; +- no graph mutation tools; +- no workflow execution; +- no web access unless the user explicitly enables it later; +- read-only, minimal sandbox for Codex; +- bounded prompt, response, turn duration, and queued request count. + +This keeps "rewrite my prompt" from becoming an implicit authorization for an +agent to edit the workspace or run the graph. If graph-aware tools are wanted +later, they should be a separate explicit mode. + +The current console session should not be scraped through a pseudo-terminal or +shared concurrently. A console and the node may resume the same stored session +by id at different times, but the normal node experience should use a dedicated +assistant session. The UI may expose Copy session id / Reset conversation for +advanced use. + +## Edit-safety rules + +Every request records the active scene id and a revision hash of the source +text. When a result arrives: + +- if both still match, enable Apply; +- if the user changed scenes or edited the source, keep the result staged but + show "Source changed while the assistant was working"; +- never apply a late result to whichever scene happens to be active; +- keep the user's current text available as a one-step local undo after Apply; +- discard or cancel outstanding requests when the node is removed; +- cap transcript persistence and do not serialize auth data or bridge tokens in + the workflow. + +Prompt text is untrusted data. Put it in a clearly delimited data field and keep +the rewrite instruction outside that field. The structured result schema is the +authority for what may be applied. + +## Implementation phases + +### Phase 0: one-shot UX proof (superseded) + +The original proposal was a manually started local development sidecar outside +ComfyUI's Python process. The native bridge was implemented directly instead, +so no separate sidecar is required. + +- Codex: `codex exec --ephemeral --sandbox read-only` with structured output. +- Hermes: `hermes --oneshot` with tools disabled and a structured-output + contract where supported. +- Node: provider picker, instruction, staged result, conflict detection, Apply. + +This proves prompt quality and editor ergonomics. It should be marked a local +development mode, not the shipping architecture. + +### Phase 1: native comfyui-mcp capability (implemented for Codex and initial Hermes) + +- add the prompt-assist frame family and dedicated session manager; +- reuse the current Codex backend/app-server lifecycle; +- use Hermes' tool-restricted one-shot adapter initially; ACP remains the + persistent-session optimization; +- expose provider readiness specifically for prompt assistance; +- support progress state, cancellation, reset, and structured final output; +- keep the existing panel protocol and shared panel sessions unchanged. + +### Phase 2: production editor UI (initial implementation complete) + +- implement the assistant panel in `web/h3_chain_scene_prompt_editor.js`; +- factor transport and revision helpers into testable `.mjs` modules; +- keep a transient node transcript plus bounded orchestrator transcript state; + neither is serialized into the workflow; +- include selected text as special context and provide an editable staged + replacement with original/proposal comparison; +- document startup and unavailable-provider states. + +## Test plan + +Current frontend tests cover bounded context construction, source revisions, +stale-draft detection, bridge discovery, deferred conversation reset, Plan +round-trips, and the editor's staged controls. Current orchestrator tests cover +request validation, output parsing, correlated result/cancellation, transcript +reset and provider separation, Codex isolation settings, auxiliary socket +routing, and existing conversation-boundary behavior. + +A later browser-level automation pass should additionally cover: + +- request context for first, middle, and last scenes; +- multiline prompt round trips; +- request/result correlation with out-of-order replies; +- navigation and source edits while a request is in flight; +- Apply, Discard, and one-step undo through real DOM events; +- cancellation and node removal; +- bridge loss/reconnect without duplicate Apply; +- no bridge token, credential, or transcript leakage into `plan_json`. + +Orchestrator tests should cover: + +- assistant sessions never resolve to the panel's shared session key; +- no panel/graph tools are registered for assistant turns; +- provider switch and per-provider resume; +- schema validation and size/time limits; +- cancellation before and during generation; +- Codex and Hermes adapters produce the same canonical result frames; +- a malicious prompt cannot change the requested response shape or tool policy. + +A browser smoke test should edit a real Plan prompt, request a rewrite, verify +that agent progress does not change `plan_json`, Apply the draft, and confirm +both the large editor and the Plan editor show the same saved text. + +## Decision + +Proceed with Phase 0 only as a short-lived UX experiment. The production target +should be Phase 1 plus Phase 2: a provider-neutral prompt-assist capability in +`comfyui-mcp` and a staged assistant UI in this editor. + +This gives Codex and Hermes one consistent node experience, keeps user +authentication and agent processes out of ComfyUI, preserves Registry-friendly +separation, avoids interference with the sidebar agent, and leaves room for the +same assistant transport to serve other prompt-editor nodes later. + +## Evidence reviewed + +- this pack's `chain_nodes.py`, `web/h3_chain_scene_prompt_editor.js`, and + `web/h3_chain_plan_core.mjs`; +- `/media/p5/comfyui-mcp/src/orchestrator/agent-backend.ts`, `index.ts`, + `codex-backend.ts`, and `src/services/agent-setup.ts`; +- `/media/p5/comfyui-mcp-panel/__init__.py` and + `web/js/comfyui-mcp-panel.js`; +- the locally installed `codex exec`, `hermes`, `hermes acp`, and + `hermes serve` command contracts; +- OpenAI's current [Codex App Server](https://learn.chatgpt.com/docs/app-server.md), + [Codex SDK](https://learn.chatgpt.com/docs/codex-sdk.md), and + [non-interactive mode](https://learn.chatgpt.com/docs/non-interactive-mode.md) + documentation. diff --git a/ComfyUI-MiniMaxH3-Context-Loop/CHANGELOG.md b/ComfyUI-MiniMaxH3-Context-Loop/CHANGELOG.md new file mode 100644 index 0000000000000000000000000000000000000000..b2727b51160956db794b47d7186b509b86fe11a0 --- /dev/null +++ b/ComfyUI-MiniMaxH3-Context-Loop/CHANGELOG.md @@ -0,0 +1,1347 @@ +# Changelog + +Newest first. The [README](README.md#changelog) keeps a short highlight reel; +this file records the detailed changes. + +## v0.6.5 — Explicit upscale anchor settings and source summaries + +- Added semantic-anchor size and presentation-mode overrides to latent, pixel, + and inherited VIDEO upscale conditioning. Choices match Tagged Scene Options, + with `inherit` preserving saved settings or the connected anchor bundle. +- Overrides apply to cached, rebuilt, and connected references. Changed anchor + settings rebuild presentation and prompt labels from verified saved media in + a separate reusable cache without modifying the original checkpoint/cache. +- Checkpoint Manager now names the output branch, available scenes, Original or + DeRoPE source, exact Original fallback scenes, and workflow pin state. Preview + browsing stays separate from the source; downstream range controls still + determine which scenes are processed. +- Preserved existing positional pixel/VIDEO widget values. Added CPU recovery, + cache reuse, source-preservation, schema and frontend output-summary tests. + +## v0.6.4 — Preserve reference sizing during recovery + +- Recover saved Match/Max sizing through static input links and modern Tagged + Scene Options, including when the reference tensors have been lost. +- Apply upscale sizing overrides to cached and reconstructed references, not + only connected Tagged overrides. Match-to-Max changes re-encode original + picture masters; legacy caches recover those masters from saved media. +- Preserve source caches and unrelated reference roles; report the actual + effective policy and rebuild count. Added CPU policy/geometry regressions. + +## v0.6.3 — Cancellation-safe processing saves + +- DeRoPE/upscale publication retains media after uncertain checkpoint commits; + a failed manifest refresh no longer deletes a successfully saved scene. +- VIDEO PNG exports journal staged publication and recover interrupted frame + copies or index commits on retry. Earlier scenes remain untouched; conflicting + incomplete files are preserved in the recovery staging folder. +- Recreated VIDEO containers reuse existing PNGs when their delivered pixels + match at the selected precision, including legacy exports. Changed renders, + branches, and edited committed PNGs are still protected from silent adoption. +- Added CPU cancellation/fault-injection and real process-exit regression tests. + See [processing cancellation and resume](docs/processing-resume.md). + +## v0.6.2 — Upscale reference recovery and durable exports + +- Backported reference-cache deduplication, legacy conversion, reconstruction, + and upscale saving fixes from nightly without adding workflow-ownership + locking or unrelated nightly review features. +- Missing cache manifests or tensors can be rebuilt from verified saved media + and reference identities, including semantic anchors, saved presentation + settings, and timed references when their immutable timing snapshot exists. + Recovery never executes an archived workflow, resolves an old tag against + today's replacement asset, or silently drops references to text-only. +- New caches store content-addressed per-reference safetensors. Existing bundles + remain readable; `tools/convert_reference_caches.py` provides dry-run/apply + conversion. Legacy bundles are removed only after their converted tensors + have been verified and used by a successfully saved render. +- Each new generation or alternate take keeps an immutable Plan/API/workflow + recovery snapshot. Failed scene publication removes only its uncommitted + artifacts; failed advisory root/editorial refreshes retain the committed take. + Historical and attributed checkpoint selections use their own recovery Plan, + with root-archive compatibility for older saves. +- Added Original/DeRoPE/Latent Upscale/Pixel Upscale checkpoint views, saved + DeRoPE source selection with original fallback, explicit processing ranges, + and final-cut alternate selection across full-sequence deferred upscales. +- Added preview-confirmed processed-take deletion and chapter-snapshot retirement. + Later independent pixel takes remain intact; actual source/context dependencies, + original checkpoints, shared references, and unrelated exports stay protected. +- PNG export now accepts file-backed VIDEO plus upscale state, publishes one + scene at a time, and passes the same VIDEO downstream only after publication. + Existing output slots remain unchanged; VIDEO is appended. Users choose 8- or + 16-bit RGB PNGs. Frames are decoded incrementally with bounded worker queues; + no full-chain pixel batch or VAE is required in VIDEO mode. +- PNG publication falls back to exclusive buffered copies when network storage + denies hard links. Timestamp drift triggers content-hash verification instead + of rejection. Changed/missing PNG contents still prevent reuse without overwriting + the user's files; timestamp tolerance is not permission to adopt edited frames. + +- Grouped full-mix/vocal/instrumental sources in the Carousel and a reusable + Audio Tracks node. Full mixes are never doubled with stems; stems-only mixes + are frame-aligned, peak-protected and previewable. Audio archives include + every track and validate their recovery hashes. +- Per-scene Lip-sync Inherit/On/Off in Plan Studio and the Plan editor, using + the established source-target/reference/carry fields. Grouped lip-sync uses + vocals only; delivery remains the full mix. Existing single-track workflows + are unchanged. Missing vocals and mismatched stem durations fail clearly. +- Chapter PNG/WAV exports can reuse verified unchanged PNGs and append newly + generated scenes in the same folder. Identical exports skip VAE decoding; + growing soundtracks are rebuilt atomically to preserve audio joins. Changed + takes, trims, placements, settings, damaged/missing files, and interrupted or + unverifiable legacy exports use a new folder without replacing prior frames. + A fresh-export switch, per-export process lock, file integrity records, and + export-index history preserve explicit recovery and whole-Run behaviour. + +## v0.6.1 — Chapter output and authoring polish + +- Ported the standalone Prompt IDE's marker editing, context-aware completions, + timestamps, and presentation settings while retaining connected Plan editing, + reference discovery, prompt revisions, and optimizer support. No task-aware + template panel was added. +- Added chapter width/height controls in Plan Studio. Locked saved scenes pin + their chapter's original size; incompatible cross-resolution video context + still requires an independent boundary. Export differently sized chapters + separately rather than silently resizing saved media. +- Added immutable Chapter Delivery and Chapter Recovery manifests, including + export of generated scenes from unfinished chapters. Saved chapter snapshots + retain their editorial state, audio timing, and exact checkpoint lineage. + Checkpoint deletion protects artifacts referenced by these snapshots. + PNG exports retain main's separate numbered export folders. +- Added workflow-local checkpoint output and **Selected chapter only** scope. + Pins do not change project-wide active branches or the connected Plan. + Local/chapter selection is read-only, including legacy checkpoint scanning; + a missing pinned revision is rejected rather than silently recreated. +- Added chapter-scoped deferred upscale runs with original scene numbering, + source-audio offsets, isolated profiles, and compatibility validation limited + to the selected chapter's media. Improved saved context-independence evidence, + chapter-boundary validation, and compatibility fingerprint handling. +- Added optional pixel-upscale conditioning width/height (`0 = auto`) to the + nodes and example recipe. Overrides affect conditioning and reference size, + not the actual image batch dimensions. +- Fixed narrow Plan Studio controls overlapping, improved light-theme contrast, + and refreshed shared helper cache keys consistently. +- Fixed scene duplication rewriting context links and preserving the copied + prompt instead of inheriting the following scene's prompt. + +Workflow-ownership locking remains nightly-only; these ports do not add it to main. + +## v0.6.0 — Production context authoring and synchronized export + +### Release preparation + +- Rebuilt the 0.6 example catalog from named recipes and this release's node + definitions, rather than reserializing archived workflows. The 19 examples + have typed widget validation, required-input and bidirectional-link checks, + title-aware layout checks, and companion setup guides. Studio Plan outputs + are connected to Loop Start; the Carousel and Checkpoint Manager are included. + Older examples remain in `example_workflows/Archive/0.5/`. + +- Corrected release-workflow execution settings and switched maintained source + video examples to native VIDEO inputs. Bounded smoke renders exercised the + 15 non-upscale examples; the test setup and its Ref2VA model-substitution + limits are recorded in [Workflow validation](tools/v06/README.md#layout-and-release-checks). + These checks are not a full-resolution quality or GPU-memory guarantee. + +- Added an experimental pixel-upscale backend and DLSS5 + USDU example, adapted + from **Illynir's** contribution. Pixel Current Scene decodes saved video + checkpoints one scene at a time; Pixel Conditioning uses the actual upscaled + image dimensions, rebuilds matching references at that size, and passes the + same images to the refiner without applying a second upscale. Image-only + segment saving preserves original audio and supports resume and assembly. + Pixel mode does not require or splice HQ latent continuity. CPU integration + tests cover geometry, audio, trimming, recursion, and resume; external + DLSS5/USDU GPU refinement remains untested. See the + [experimental workflow guide](). + +- Added visible Carousel semantic-anchor size and mode controls, with an + **inherit** choice that delegates to downstream Tagged Scene Options without + requiring another Options wire into the Carousel. Older explicit values + remain readable. The controls can be hidden without changing their values. + +- Hardened asynchronous project switching, run restoration, and editorial + saving. Responses from an old run or detached workflow no longer update the + newly selected graph; saves serialize with revision checks so late responses + cannot overwrite newer edits. Switching or closing a project flushes pending + editorial changes. Unused stale Studio scene entries can be reconciled, + while entries carrying saved work remain protected. + +- Fixed source-audio preview and waveform mapping after scene-length changes, + including clearing the previous run's source preview on project switches. + Empty-scene navigation and seeking now preserve the selected scene and + playhead instead of jumping to a rendered or prompted scene. + +- Clear a selected final-cut alternate when its base scene is regenerated, + retaining the saved alternate revision without applying it to the wrong + generation lineage. Connected Review Gate previews now replace the redundant + silent Segment + Checkpoint preview. + +- Restored the concise README changelog, corrected the release banner from + NIGHTLY to 0.6, and updated the installation URL to the renamed Context-Loop + repository. Existing custom-node folder names and serialized node IDs do not + need to change. + +### Features and fixes + +- Fixed Windows mapped network drives used as ComfyUI input/output directories + (#45). Root and artifact paths now resolve consistently before calculating + relative paths, preventing drive-letter/UNC mount errors during segment and + recovery-archive saving, Run Manager access, and Asset Carousel imports. + +- Refreshed browser cache keys for Checkpoint Manager, prompt editors, Plan + Studio, and Asset Carousel helpers. Added checks to prevent cache keys from + being downgraded to stale versions during future updates. + +- Fixed Prompt Editor reference discovery when the Studio render engine lives + inside a subgraph. Editors now read the connected upstream Project Asset + Carousel directly instead of requiring a traversable downstream Ref2VA + wrapper. + +- Fixed Project Asset Carousel Run-name editing so pauses after a space, + underscore, or hyphen no longer let an asynchronous catalog refresh erase + the separator. The field now preserves the exact draft while typing and + commits its folder-safe project name on Enter or blur. + +- Fixed Checkpoint Manager hiding the safe rollback operation for an earlier + checkpoint that was already on the active branch. It now offers **Roll + active branch back**, retires later active pointers in one operation, and + keeps all immutable revisions. The deletion inspector now distinguishes + this non-destructive rollback from leaf-by-leaf permanent deletion. + +- Hardened Scene Prompt Editor and Rich Scene Prompt Editor workflow teardown. + Closing a workflow now cancels pending Plan propagation, prompt analysis, + history saves, timers, and listeners without repainting or mutating a graph + while ComfyUI is removing it. Cleanup failures are isolated so one editor + cannot prevent the remaining workflow nodes from closing. + +- Replaced the Project Asset Carousel's filtered browser suggestion popup with + a real project picker attached to the editable Run name field. The arrow now + always lists every existing project with its asset and unassigned counts, + while the text field still accepts a new Run name. + +- Fixed Review Gate delivery when Project Assets owns the Plan run name. The + hidden, stale Plan widget no longer rejects the exact pending review or + participates in run-name fallback matching. Report and original fix by + **Psylent_Gamer (4090)** via Banodoco, adapted to the current Plan/Modern Plan + routing implementation. + +- Fixed path-backed video and motion references in `restart_each_scene` mode + being cropped or padded to the generated scene length. They now retain + their own complete 24 fps reference duration; only `sequential` references + use scene-sized timeline windows. + +- Extended **Export PNG Sequence** into an independent picture/audio exporter. + Its video and audio VAE sockets are now both optional: connect either one for + PNG-only or WAV-only output, or both for a continuous PNG sequence plus a + synchronized `audio.wav`. The WAV is decoded from the saved H3 audio latents, + preserves AV overlap ownership, and follows the same selected scene order and + latent-safe trims as the exported frames. Existing video-VAE connections and + output indexes remain valid; `audio_path` is appended as a new output. + +- Accelerated **Export PNG Sequence** with chunked batch conversion and up to + eight bounded parallel atomic PNG writers, inspired by JSON-Dynamic's Fast + Absolute Saver. New nodes default to lossless compression level 1; existing + saved compression values remain unchanged. The exporter now shows ComfyUI + progress, logs per-scene verify/load/GPU-decode/convert/save timings, updates + `export.partial.json` after every chunk, honors cancellation between chunks, + and caches successful checkpoint hashes by immutable hash, size, and mtime. + Strict verification remains available as an optional input. + +- Corrected the user-visible **Contex Loop** typo to **Context Loop** across + node titles, Add Node categories, settings, documentation, branding, and + bundled workflow titles. Serialized node IDs and settings keys remain + unchanged for compatibility. + +- Fixed Review candidate acceptance and rerolls leaving Plan Studio and + prompt-editor companions on stale scene metadata. Selecting a 10x candidate + now refreshes the complete Plan—including seed, length, steps, context, and + scene order—while prompt-only edits retain their selection- and undo-safe + fast path. The shared companion module now has an explicit cache revision, + with safe fallbacks for partially refreshed browser sessions. + +- Added the multi-block **Picture Context Builder** to Plan Studio. Scene Context + now owns picture/audio totals, boundary implementation, and spatial proxy; + selecting 1–N picture blocks exposes every H3-native repartition through + ordered boundary selectors plus an independent earlier-scene source and + latent window for every block. Repeated sources are supported, audio stays + locked to its continuous predecessor path by default, and checkpoint, + resume, trim, review, and dependency metadata track every selected block. + Released one/two-block Plan fields remain a read-only compatibility path. + +- Added **MiniMax H3 Plan (Modern)** as a clean, opt-in replacement for the + original Plan node. It preserves the familiar vertical scene-column editor + and exact Plan output sockets, but organizes its controls into Project, + Canvas, Generation defaults, and Delivery while requiring Generation Profile + and exposing no legacy context/audio/continuation fallbacks. The original + Plan remains unchanged; its **Upgrade to Modern Plan…** action preserves + scenes, supported settings, placement, and graph connections. Plan Studio, + prompt editors, Review, reroll, Run/Checkpoint Managers, project assets, and + recovery archives recognize both Plan types. + +- Fixed zero-picture-context resume validation. When a visually new scene + carries only the preceding generated audio, strict history checks now ignore + that predecessor's unrelated incoming visual-boundary recipe while retaining + prompt/model/source identity and artifact-integrity checks. Resume errors now + report the consumed streams and selected scene's effective video/audio + context lengths. + +- Hardened the Manager-facing HTTP surface. Direct prompt optimization now + uses a server-owned exact-origin allow-list and validates every redirect; + custom or local providers require `H3_PROMPT_OPTIMIZER_ALLOWED_ORIGINS`. + Carousel imports can read only enumerated ComfyUI input, project, or chain + media; Plan Studio browser media is confined to configured ComfyUI roots + with real-path/symlink checks; and host folder opening is limited to + loopback clients. + +- Composed visual context now supports two independently positioned native + latent windows from the same saved scene. A split such as 5+34 can reuse one + source movie for both blocks, including on Scene 2, while generated-audio + continuity remains attached to the immediate timeline predecessor. + +- Completed the post-Issue-42 payload audit. Delegated Motion Context now + verifies the live video/audio Guide merge before calling every upstream + provider version, including older providers that do not fail preflight. + The behavioral probe now uses real tiny tensors, and release cache, + workflow, and regression fixtures are synchronized. + +- Fixed Issue #42 on partially updated ComfyUI builds and internal Motion + Context fallback paths. Chain now behaviorally verifies both video and + audio keyframe/reference payload merging before sampling and installs its + marker-gated compatibility merge only when native Guide layout exists but + the payload still drops Guide tensors. This covers the reported 37-step + stereo mismatch (`714` reserved rows versus `640` supplied rows), Patch + Priority, longer/audio-only carry, and other internal-engine routes. + +- Made prompt reference tags case-sensitive from display through conversion. + The rich editor no longer presents a wrong-case alias as a valid asset, so + `@Maison` and `@maison` remain distinct. Completion search is still + case-insensitive and inserts the asset's canonical spelling. + +- Fixed a Loop Start runtime crash introduced by structured source-duration + diagnostics. Source Timeline binding now derives the active audio-source + requirements before calculating required frames, matching the preflight + path and eliminating the `source_requirements` NameError. + +- Completed the structured preflight diagnostic contract. All hard preflight + categories now carry their precise trigger, including scene ID, setting, + value, origin, and tag where applicable; duration/capacity failures report + required versus available frames, the last complete scene, and the first + affected scene. Diagnostics retain the compatible primary `action` while + adding ranked alternative solutions, and validation failures are separated + by Plan, scene selection, source, reference, runtime, and resume stage rather + than collapsing into one generic internal error. Source-duration validation + now measures only through the last scene that actually consumes source audio + unless the final soundtrack itself is sourced. + +- Made blocking preflight errors identify their actionable origin. Missing + source-audio diagnostics now list every triggering scene ID, the exact + effective setting (`source_reference`, `source_audio_target`, or final + output audio), and whether it came from a scene override or Chain Policy; + they also name the disconnected Loop Start sockets. Other structured + preflight errors now render their available scene, setting, origin, and tag + context on separate readable lines before the corrective action. + +- Fixed Issue #38's remaining Scene 2 failure on installations where + ComfyUI retains a compatible H3 payload wrapper after its temporary module + alias is removed. Patch Priority now recovers that wrapper's captured stock + method from the function's own execution globals, allowing the guarded + Guide-audio plus Ref2VA-audio merge to take ownership without requiring the + user to remove a valid node pack. Unknown payload wrappers remain refused. + +- Fixed a selected final-cut ALT incorrectly retargeting later queues back to + its original scene. The server-side editorial record now owns whether an + alternate generation draft is armed; the hidden Plan Studio widget may only + update an already-armed matching draft and cannot resurrect one cleared by + Review. Selecting Original/ALT explicitly disarms that scene's draft, and + Plan Studio synchronizes the one-shot queue widget on every workflow load, + including Plans without chapters. + +- Fixed delayed and inconsistent workflow hydration. Project Asset Carousel + now paints its serialized catalog immediately while refreshing in the + background, and Plan Studio keeps a lightweight serialized presentation + cache so saved thumbnails, placements, and latent-safe trims appear on its + first render instead of snapping into place after the checkpoint scan. + Player transport now advances at the trimmed endpoint instead of continuing + through discarded media. Scene renaming is atomic, rejects duplicate IDs, + and migrates chapters, visual-context links, placements, trims, locks, and + alternate final-cut metadata so an ungenerated rename cannot hide a scene. + +- Plan Studio can now create a prompt-word alternate for an already accepted + scene. Queueing an enabled draft renders only that scene and saves an + immutable `editorial_alternate` revision without changing the active + generation checkpoint. Accepting it selects its picture for preview, + assembly, PNG export, and whole-chain latent finishing, while later scenes + continue to depend on the original take and final audio remains original. + The timeline marks selected clips `ALT`; Checkpoint Manager nests alternates + under their immutable base and distinguishes generation lineage from the + final-cut choice. Selected base/alternate revisions are deletion-protected. + +- Plan Studio can now shorten a rendered scene non-destructively at a + latent-safe endpoint. Its right edge and Scene panel expose only cuts shared + by H3's native video-latent cycle and the delivered 24 fps / 40 Hz audio + clock; the original complete checkpoint and scene movie remain untouched. + Continuation state, generated audio, standard assembly, PNG export, and the + Full-Chain Latent Video adapter use the shortened prefix. If an earlier cut + changes after dependent scenes were generated, those checkpoints are marked + stale and resume requires regeneration from the first affected scene instead + of silently mixing incompatible endpoints. + +- Fixed scene-2 continuation with simultaneous Ref2VA/source audio. On a + partially native ComfyUI runtime that drops Guide audio when reference audio + is also present, Chain now activates its marker-gated payload merge and uses + the retained internal Motion Context engine. The compatibility merge now + preserves keyframe audio followed by reference audio, matching H3 layout + order, instead of accidentally retaining only the reference-audio rows. + +- Scene LoRA routing now grows with the workflow instead of exposing four + fixed branches. A new scheduler shows one empty LoRA A socket; connecting it + reveals B, then C, through Z. Plan Editor and Plan Studio offer only routes + connected to their scheduler plus a scene's already-saved route. Existing + A-D plans and scheduler links remain compatible, and every route stays lazy. + +- Run name now suggests existing live Asset Carousel projects. Choosing a + suggestion switches the Carousel and its connected Plan, while the same + field still accepts a new Run name and remains the only serialized source of + truth. Empty projects are included in the history; output-only H3 backups + remain available through Import instead of appearing as switch targets. + +- Project Asset Carousel can duplicate its complete asset project under a new + Run name. The copy keeps asset order, folders, roles, tags, lyrics, options, + reference slots, and independent project-owned media files plus their asset + recovery mirror; generated clips, checkpoints, assembled renders, previews, + and upload scratch files are deliberately excluded. Existing Run names are + never overwritten, and the source Carousel remains selected. + +- Made both scene prompt editors responsive while typing long prompts. Each + keystroke still updates the connected Plan value immediately, but expensive + Plan-card rebuilding, canvas redraw, companion broadcasting, and strict + schema analysis are now coalesced after a short idle interval and flushed on + blur, navigation, or removal. Consecutive keystrokes also avoid reparsing an + unchanged full Plan JSON. + +- Fixed Tagged Audio `source_timeline` identity validation for the shipped + full-track workflow. Loop Start's route fingerprint and Tagged Audio's + waveform-content fingerprint are now recognized as two identities of the + same Source Timeline audio, while genuinely different tracks remain blocked. + +- Plan Studio Player now uses its preloaded media as a real second playback + buffer. At adjacent saved-scene boundaries the decoded video and separate + generated-audio elements are promoted immediately, the previous elements + become the following preload buffers, and the existing last-frame veil fades + only while the promoted player starts. This removes the redundant same-URL + reload pause without changing clips, editorial timing, or final assembly. + +- Project Asset Carousel can now import from another Run's live Carousel, not + only from recovery backups. The copy preserves the source role, tag, + reference options, and audio lyrics, receives an independent project-owned + media copy and catalog identity, and never modifies the source Run. Selecting + an Unassigned card binds the imported media to that slot instead. + +- Fixed Plan Studio transport synchronization. Ruler ticks, scrubbing, scene + widths, and the red play line now use the same pixels-per-second scale, so + extending the open timeline or changing zoom cannot skew the playhead. + Generated-video and Source Track playback also refresh the visible clock and + line every animation frame; the browser's coarse `timeupdate` event remains + only as a fallback. + +- Updated the retained internal Motion Context engine to current upstream + Guide behavior: arbitrary off-grid visual lengths remain exact, head-mode + Guides can be placed at an interior `target_start`, unrelated anchors are + preserved outside that interval, and decoded source audio is end-aligned on + an exact 40 Hz PCM grid before VAE encoding. Native H3 run lengths still use + one efficient video Guide. Loop-only latent Guide, audio-only carry, + longer-audio windows, fractional audio correction, and the + guarded legacy-core path remain available. + +- Chain Context now transparently delegates compatible Guide scenes to + seitanism's installed **H3 Motion Context** node. Existing workflows and + sockets do not change. The adapter preserves Loop keyframe arbitration, + Guide markers, and exact latent-audio placement; Latent Guide, audio-only or + longer-audio continuity, and legacy ComfyUI + remain on the internal compatibility engine until upstream exposes those + capabilities. + +- Fixed the bundled Tagged Source Audio workflow's `source_timeline` path. + Tagged Audio now receives the same full Load Audio track as Source Timeline, + derives its aligned current-scene slice internally, and returns the complete + static picture-and-audio fingerprint to Plan. The example also serializes + Tagged Ref2VA's current `native_ref2va` widget and `refmod_sources` output so + its controls no longer appear shifted after node updates. + +- Checkpoint Manager can now delete an entire selected + `output/h3_chains/` folder. It previews the file, folder, and byte + impact, requires both an explicit warning confirmation and the exact Run + name, then revalidates the folder snapshot immediately before deletion. + Original assets under `input/h3_projects/` are deliberately kept. + +- Semantic pictures now accept bare `#tag` as an untimed Qwen-only visual; + append `[time]` only when explicit approximate scene placement is wanted. + Prompt completion, reference conversion, rich chips, preflight, native + Ref2VA hybrid conditioning, and external RefMod hybrid conditioning share + the same syntax. `@tag` remains the native Ref2VA/RefMod namespace, and + neither `#` form creates a VAE reference. + +- Added optional **Lip-Sync Options** for Generation Profile's exact-source + audio mode. Scene audio can be encoded with discarded real-song pre-roll and + lookahead instead of artificial hard boundaries. An aligned isolated vocal + stem can drive a conservative 40 Hz voice gate so vocal regions remain exact + while instrumental gaps receive a configurable amount of denoising. The + options and stem fingerprint are stored in generation dependencies; leaving + the node disconnected preserves the previous hard-cut/full-freeze result. + +- Checkpoint Manager now adopts active checkpoints written before immutable + revision sidecars were introduced. It recovers the original transaction id + from the existing versioned MP4 and safetensors filenames, writes only the + missing lightweight JSON revision records, and links the legacy linear + lineage without copying or rewriting media, latents, or active pointers. + +- Added **Generation Profile**, a two-control replacement for the cryptic Chain + Policy switches. Clear scene-continuity and audio choices include Generate + audio, fresh per-scene audio, source-guided generation, source soundtrack, + silence, and exact source-audio lip-sync. The former node remains compatible + as deprecated **Manual Chain Policy (Legacy)**. + +- Plan Studio's horizontal timeline position is now inert during passive + rerenders, workspace growth, and prompt-editor scene synchronization. It + restores the exact pixel position, cancels stale layout callbacks, and only + reveals a scene after an explicit timeline selection; automatic restoration + can no longer recursively grow or throw the scrollbar to either end. + +- Both prompt editors now discover tagged and Project Asset references through + the compact **Current Tagged Ref2VA Scene** node, just as they already did + through the original standalone Tagged Ref2VA wrapper. + +- Added a modern **Current Tagged Ref2VA Scene** composite that replaces the + visible Current Shot plus Tagged Ref2VA pair while reusing both established + execution paths internally. Its public outputs are only state, conditioning, + latent, and typed scene data. A separate versioned options node carries + reference/semantic/backend settings, and **Scene Data Extract** selects former + secondary outputs—including `refmod_sources`—with a concrete UI socket type. + The new route deliberately rejects the legacy 0.4 state contract and exposes + no legacy source-audio or blend socket; both original nodes remain unchanged. + +- Tagged Ref2VA now has an opt-in `external_refmod` conditioning backend for + testing ComfyUI-MiniMaxH3Mod without duplicating native references. It keeps + scene-local `@tag` selection and video slicing, emits text-only H3 + conditioning/latent, and exposes the active pictures/videos as the upstream + `H3_REF_LIST` contract through `refmod_sources`. Native Ref2VA remains the + default. Active semantic `#anchors` now use a hybrid path: ordinary `@visuals` + remain compressed RefMods, while an anchor-only Qwen presentation preserves + each anchor's timestamp and storyboard mode without re-encoding all ordinary + reference media. Active reference audio still fails explicitly because the + external format is visual-only. External Extract/Apply settings remain + outside Plan fingerprinting and native deferred-upscale caching. + +- Plan Studio's generated track is now an editorial timeline rather than a + delayed view of generation order. Absolute scene placements can move any + scene—including the terminal scene—before or after other clips; collisions + resolve as non-overlapping inserts, uncovered time stays black, and raw + placement requests are no longer rewritten during layout. Playback, motion + references, source-audio waveforms, generated scene audio, and final video + assembly share the resolved editorial order. Generation lineage and saved + checkpoints remain unchanged, while boundaries whose generation predecessor + changed assemble as safe hard cuts. + +- Audio assets in the Project Asset Carousel now open a lyrics workspace beside + the audio player. Lyrics can be pasted or edited in place, are persisted in + both the project catalog and its H3-chain backup, and remain presentation-only: + they do not alter prompts, reference fingerprints, or generation behavior. + +- Chapter sections in Checkpoint Manager's **All scenes** view can now be + collapsed from their headers. Expanded/collapsed state is remembered per + run and chapter in workflow presentation state, and collapsed chapters skip + rendering their branch cards until reopened. + +- Checkpoint Manager now treats editorial chapters as independent revision + scopes. **All scenes** renders a separate branch graph per chapter, and + making a branch active rewrites or retires pointers only inside that + chapter. Earlier and later chapters retain their active takes; a selected + manifest combines the selected chapter with the active takes from preceding + chapters without requiring a structural parent edge across the chapter + boundary. Explicit visual/audio context metadata remains intact. + +- Carousel folders now behave like compact Discord folders. Each folder is a + card in the asset strip with a four-item miniature and count; clicking + expands or collapses its assets inline, and dropping an asset onto the card + moves it into that folder. Expansion persists as workflow presentation state + without affecting generation, prompts, or fingerprints. + +- Project Asset previews now resolve correctly in both prompt editors. The + Carousel media URL is retained as a preview record instead of being mistaken + for a preview object, restoring hover players, inline picture thumbnails, + reference-tray thumbnails, and the owning Carousel source label. + +- The Project Asset Carousel is now a direct media drop target. Dropping one + or several image, video, or audio files creates ordered project assets + immediately. External file drops are isolated from internal card dragging, + thumbnails no longer start native browser drags, and the compact drop cue + leaves reorder targets visible. The + source browser now defaults explicitly to ComfyUI input, so existing input + files can be turned into assets through **Import** without uploading them + again. + +- Project Asset image variants now accept exact megapixel targets and presets + without requiring a crop. Output aspect locking couples width and height in + both directions, **Use full image** preserves the megapixel target, and a + connected upscale model reports its exact input and final saved dimensions. + Output snapping now offers Off/8/16/32/64 (default 8), preserves the locked + aspect ratio instead of producing arbitrary odd sizes, and **Reset all** + restores the full editor state. Megapixel and multiple presets use compact + fixed grids so their final choices no longer stretch across wrapped rows. + +- Reference discovery in Plan Studio and both scene prompt editors now crosses + ComfyUI subgraph input/output rails. Tagged references, Semantic Anchor + Bundles, their internal semantic picture anchors, and externally supplied + preview images remain visible when the reference registry is packed into a + subgraph for presentation or reusable storage. + +- Plan editing now exposes only two timing levels: the Plan-wide default + seconds/steps widgets and optional per-scene overrides. The redundant + JSON-level default controls were removed from both Scene Plan and Plan + Studio, and scene placeholders now inherit directly from the Plan widgets. + +- Checkpoint Manager branch rows keep their compact shared-revision colors and + badges without drawing long SVG lineage rails across the branch list. + +- Plan Studio now persists its discovered motion-reference and Source Timeline + audio presentation beside the run, then restores it automatically after a + workflow, browser, or server reload. This UI-only record does not participate + in generation fingerprints, checkpoint branches, or resume validation. + +- Long Plan timelines no longer rebuild one live video element per saved scene + on every checkpoint poll. Generated cards use immutable, lazy, disk-cached + JPEG thumbnails and update in place, substantially reducing browser media + churn and the associated Windows Proactor `WinError 10054` disconnect noise. + +- The two-clip masked AV bridge now accepts silent source videos. Start and end + audio are independent optional inputs: an available endpoint is encoded and + protected, while a missing endpoint remains unmasked so H3 generates audio + there instead of failing or forcing artificial silence. + +- **Use this take & stop batch** now pins the accepted candidate preview across + targeted cancellation and the automatic next-scene queue. Late payloads from + an earlier scene can no longer replace it with the predecessor preview; a new + run of the same scene, the next scene, or an explicit checkpoint choice + releases the pin normally. + +- Review Gate candidate polling no longer reloads an unchanged preview or + jumps back to the newest take when a live candidate batch reaches its final + review token. The selected take, playback position, and playing/paused state + survive progress refreshes and synchronized-audio preview upgrades. + +- Plan Studio's scene lanes now behave as one horizontally zoomable timeline. + **Fit** compresses the complete Plan into the available width; zooming in + expands duration-proportional scene spans beneath a shared ruler and single + scrollbar. Generated clips, motion references, Source Timeline audio, and + the playhead remain aligned while resizing, zooming around the pointer, and + navigating long Plans. + +- Live generation can now route **Current Shot** directly through the four + H3 de-rope adapter nodes, recover the exact AV clock, and save that recovered + latent back into the normal chain. The same nodes still accept deferred + Upscale Loop state. Inline continuity resolves the Plan's actual linear, + non-linear, or composed visual-context source, and a recovered scene tail is + protected only when a later scene really consumes it. + +- Added ordered **Composed visual context** in Plan and Plan Studio. A + continuation can assemble one native H3 context total from two saved scene + tails. The UI exposes both orientations of every valid split—for example + `39 = 17+22` as well as `22+17`, then all splits for `56`, `73`, and the + longer native totals. Native-phase layouts splice latent blocks directly; + inverse layouts are normalized through the connected video VAE only when a + latent continuation consumes them. Plan Studio also remembers whether its + Advanced Boundary controls are open while settings re-render. The complete + generated-audio latent stays + continuous from the immediately previous timeline scene, the two visual + sources are tracked independently by checkpoint preflight, and checkpoint + activation restores the exact source IDs, total, and split. + +- Unified source and deferred-upscale finishing in **H3 Chain Assemble**. + Upscale Loop End now emits the common manifest wire; Assemble dispatches by + document format, keeps HQ finals under the child profile, and exposes the + same optional regular-output copy, filename, audio, and assembly controls. + The former Upscale Merger remains as a deprecated compatibility wrapper. + +- Ported the strict authoring layer from the standalone H3 Prompt IDE into + both scene prompt editors. They now share Auto/T2VA/I2VA/FL2VA/L2VA/Ref2VA + schema selection, ordered-section diagnostics and repair, exact keyframe + alignment helpers, live word/character counts, and mode-aware completion. + Completion and rich presentation now also understand 12 shot markers, + multilingual dialogue markers, stable speaker IDs, ``, and + ``; the Rich Scene Prompt Editor gained the same Plain/Rich source + toggle as the focused editor. + +- Reference insertion from the Scene Prompt Editor's top menu now preserves + the last rich-text or plain-text selection, so a chosen reference replaces + the selection or appears at the requested caret instead of jumping to the + prompt start. `#` autocomplete and the reference tray now also include + dedicated semantic-only picture anchors and select their timestamp for + immediate editing. + +- Added deterministic alternatives in scene prompts with ComfyUI-style + `{first|second}` syntax. Every scene now has a **Prompt alternatives** policy: + derive a stable scene seed, use an exact fixed scene seed, or generate a fresh + choice each time that Plan is queued. The redundant Plan-wide prompt seed was + removed. Sampler seeds remain completely + independent. The authored template, selected text, and exact choice seed are + saved together. Resume treats a new choice or policy from the same template + as neutral for completed predecessors, but still rejects an actual template + edit. + +- Reference chips in both rich scene-prompt editors are now directly + editable. Clicking a chip can replace that exact occurrence with another + compatible connected reference, switch a tagged picture between native + `@tag` and semantic `#tag[time]` syntax, and edit the semantic timestamp in + a dedicated seconds field without rewriting the prompt by hand. + +- Split Qwen-only `#semantic[timestamp]` pictures from native H3 `@reference` + media. New Semantic Picture Anchor nodes feed one Semantic Anchor Bundle + with centralized scale/mode controls; the bundle connects once to Tagged + Ref2VA, Plan Studio, and Run Manager. Semantic pictures no longer consume + native picture/video/audio capacity, while their source loaders remain + recoverable through the saved-run asset manifest and their combined + incremental fingerprint remains resume-safe. + +- Added **MiniMax H3 Scene LoRA Scheduler**, a lazy per-scene MODEL router + that deliberately does not load or patch LoRAs. Plan and Plan Studio expose + Base plus LoRA A-D on every scene; each branch comes from ordinary ComfyUI + LoRA loaders and may contain a stack or strength variant. Only the selected + input is evaluated. Route choices are saved as Plan/revision provenance but + deliberately excluded from checkpoint/resume verification, and Base remains + absent from serialization for compatibility with existing plans. + +- The bundled LBH 3D deferred-upscale workflow now leaves the pass-2 prompt + override blank, preserving the exact compiled scene prompt by default. The + former neutral replacement text remains available in the How To Run note + for explicit copy/paste comparisons. + +- Hid the Upscale Adapter's provenance-only `recipe_json` in the default + presentation. It remains serialized for resume validation and can be edited + through **Show advanced H3 controls**. + +- Fixed Checkpoint Manager branch clicks so the selected lineage is committed + through the hidden Comfy widget callback and immediately available to + `selected_manifest`. Branch headers now select their final revision, and + the UI distinguishes the current selection from the saved active lineage. + +- Added an inline **Upscale Reference + Prompt Override** on the existing + `H3_TAGGED_REFERENCES` line. Connected Tagged refs replace the automatic + cache for pass 2, optional tag filtering can remove unwanted refs, and the + paired prompt output recompiles their native/Qwen conditioning coherently. + Blank reference input keeps automatic cache restore active. +- Fixed deferred H3 conditioning sync enlarging `max` picture-reference + latents with the output canvas. Max refs now retain their Core H3 capped + geometry, while `match` refs remain canvas-aware and cache-v2 masters that + were already rebuilt at pass-2 size are protected from double scaling. + +- Added a guarded compatibility backport for ComfyUI PR #15808. Older core + builds now register MiniMax H3's seven released dialogue, cutoff, lyrics, + and caption tokens on the MiniMax-only Qwen tokenizer; updated ComfyUI + builds are detected and remain fully core-owned. + +- Added an opt-in **Reference Video Fade** MODEL patch for native H3 Ref2VA + video blocks. It keeps the complete 24 fps reference at full early + influence, then applies a full-schedule half-cosine attention-value fade + without touching still refs, Qwen presentation, reference audio, + continuation guides, or target streams. Split samplers can share the + original unsplit sigma schedule, and existing SolAttn/Comfy Kitchen + attention overrides remain chained. This complements rather than replaces + Color-Stable Drift AV: one controls external native video references, while + the other controls the previous-scene continuation prefix. +- Added a whole-branch SeedVR2 route: Checkpoint Manager → Full-Chain Latent + Video Adapter → SeedVR2 Direct. It decodes the immutable H3 video latents, + resolves scene overlap blends before upscaling, and exposes one continuous + native file-backed VIDEO instead of restarting an upscaler per scene. +- Added a disk-backed MiniMax VAE output buffer and content-addressed source + cache under `upscaled/seedvr2/source/`. The decoder retains its native + temporal chunks while ordinary RAM holds only the boundary window; saved + source/generated audio is embedded automatically for the SeedVR2 pass. +- Added the standalone whole-chain SeedVR2 workflow and the LBH 3D H3 latent + workflow with video-only learned upscale, locked source audio, and a + conservative two-step 0.24 refinement pass. +- Added a backend-neutral recursive upscale child run: Checkpoint Manager + selected manifest → Upscale Adapter → Current Scene → H3/LTX/custom backend → + Segment Save → Loop End → Merger. Each profile is isolated under the parent + run's `upscaled/` folder with verified resume metadata. +- Upscale Current Scene prefers an explicitly saved denoised H3 x0 and exposes + joint AV plus split video/audio latent routes for combined and video-only + learned H3 upscalers. Older terminal-latent checkpoints remain supported, + and decoded-video LTX 2.5 passes use the same orchestration. +- Made persistence of the large HQ latent optional and off by default. A small + self-contained assembly/audio checkpoint is still written for reliable + resume and final merge. +- Checkpoint Manager now serializes its selected immutable lineage and emits a + verified generated-tip manifest, including partial runs whose later planned + scenes do not exist yet. The standalone upscale workflow therefore needs + no source Plan, Chain Policy, or live Source Timeline connection. +- Added cache-v2 pass-2 conditioning: original picture masters are retained so + `match` image refs and their Qwen presentation can be rebuilt at the exact + LBH target canvas. V1 caches remain readable; max/video/audio refs preserve + their native geometry instead of being blindly scaled. + +## v0.5.5 — Modern editable-install metadata + +- Added an explicit setuptools build backend and disabled accidental discovery + of asset and workflow folders as Python packages, so `pip install -e .` + succeeds with current setuptools releases. +- Replaced deprecated license metadata with its SPDX form while leaving the + repository's GPL v3 license text unchanged. Thanks to @ed45626 in PR #27. + +## v0.5.4 — Cleaner shared-checkpoint links + +- Moved shared-revision connectors into a dedicated side gutter with thin + solid rails and short taps to each matching card, keeping lineage marks away + from branch names, revision text, and status labels. + +## v0.5.3 — Review candidate batches and checkpoint refresh + +- Review Gate can now generate 1–20 different-seed takes for each scene, + present them together, and continue from the exact saved video/audio + checkpoint selected by the user. The default remains one take. +- Selecting an earlier take atomically promotes its checkpoint and recovery + Plan before the loop continues, so later scenes and interrupted-run recovery + follow the chosen branch rather than the last generated take. +- Fixed overlapping checkpoint refresh requests adding duplicate choices after + workflow reload, and clarified that rejected, rerolled, and candidate takes + remain as intentional immutable recovery revisions until explicitly deleted. + +## v0.5.2 — Shared checkpoint lineage visibility + +- Repeated checkpoint revisions now keep the existing branch layout while + receiving a consistent color label and a vertical connector between every + branch line that shares the same clip. +- Loop Trim now resolves `video_blend_frames` from Current Shot state. This + removes the ambiguous Plan-default versus per-scene integer wiring that could + discard the requested overlap and fail Segment Save only after sampling. + Legacy integer sockets remain compatible, while maintained 0.5 workflows and + the migration tool use the authoritative state route. + +## v0.5.1 — Checkpoint Manager and workflow clarity + +- Added experimental **Drift-Control AV** for recursive same-shot chains. It + keeps predecessor checkpoints clean, but at every sampler evaluation moves + the disposable 39-frame video prefix to the next scheduler sigma using the + sampler's existing noise field. Eight video-latent steps receive the full + matched ratio and the final four taper `.75/.50/.25/.00` to an exact seam. + Chain Context now exposes an optional MODEL passthrough so the sampler blend + and H3 per-row timestep labels receive the same live mask. The 20-step path + is the initial validated baseline; existing continuation modes are unchanged. + +- Corrected the scheduled Guide 5/6 spatial proxy to reproduce the observed + mixed-resolution chain operation: reduce the complete saved predecessor + video latent, VAE-decode it on the 5/6 grid, select the delivered RGB tail, + and only then restore it through Motion Context. The UI now calls this + **Low-grid 5/6 · Guide** instead of implying a simple RGB resize. Existing + AV latent-prefix proxy behavior is unchanged. + +- Added a Plan-passthrough Checkpoint Manager that browses every saved run by + scene and inferred revision branch, previews saved video/audio, and exposes + prompts, seeds, frame counts, compatibility data, storage, lineage, and the + exact incoming video/audio context for each revision. +- Added dependency-aware cleanup. Active revisions and revisions used by later + scenes are protected; the manager identifies every dependent scene and lets + users work backward from a leaf one revision at a time. +- Added a two-step deletion contract shared with Review Gate. The server + previews every owned/shared file and preserved archive category, then rejects + confirmation if files, active pointers, or descendants changed in between. +- New checkpoints persist creation time, effective continuation context, and a + stable branch identity so future runs need less lineage inference while old + checkpoint folders remain fully discoverable. + +- Made titles, active controls, and rich reference tags derive their semantic + colors from the active ComfyUI foreground. Both scene prompt editors retain + their pastel dark-theme palette while gaining readable contrast in light + themes. + +- Added shared text-level Ctrl/Cmd+Z and redo history to both dedicated scene + prompt editors. Undo now survives rich-tag DOM decoration, plain-text paste, + toolbar insertion, Plan synchronization, and switching between rich and + plain presentation. + +- Added a maintained two-scene Ref2V masked-inpaint demo that uses the bundled + CC0 crab picture as replacement appearance while keeping the source movie as + the authoritative joint AV target. Documented its exact mask-contract + compatibility with Ablejones/droz's v3.1 MaskVidExperiments workflow and the + separate, optional roles of crop/uncrop, tracking, and mask growth. +- Reworked the README as a task-oriented quick start and workflow chooser, + moving implementation detail into focused guides. Added a feature + traceability matrix that distinguishes original, adapted, inspired, + integrated, and compatibility work with upstream, code, and commit links. +- Added exact H3 causal/token mask conversion to Apply Target Mask. Static or + correctly sliced tracked masks now max-reduce through the VAE's repeating + `1,4,4,4,4` source-frame groups and the model's 2×2 latent-token cells, + avoiding temporal interpolation drift and loss of thin moving regions. The + bundled inpaint workflow uses the exact mode; legacy trilinear conversion + remains selectable for controlled compatibility comparisons. Ordinary AV + extension remains unchanged and needs no user-supplied mask. +- Revised experimental Detail AV to a clean-boundary v2 taper. Video-latent + noise now starts at 0.30 and falls through 0.225, 0.15, and 0.075 to an exact + zero on the boundary-adjacent step, reducing seam displacement while keeping + the predecessor, carried audio, denoise masks, and final overlap clean. +- Recognized the final merged ComfyUI PR #15375 helper-based mask API and left + it fully native. The old-build fallback now mirrors merge-time commit + `c676536`, including pooled token-grid masks and ceil-quantized 8-bit mask + strengths, and removes obsolete pre-merge wrappers before capability checks. +- Restored saved prompts, Plan widgets, and connected 0.5 audio/transition + policy nodes together when loading a run or checkpoint revision. Revision + recovery now uses the selected checkpoint chain's policy metadata instead of + silently retaining newer controls from the active workflow. +- Disabled the legacy Review Gate prompt textarea by default and added an + Interface setting to restore it. While disabled, Retry and Reroll use the + active Plan prompt authored in Scene Prompt Editor or Rich Scene Prompt + Editor. +- Added the typed Source Timeline contract so path-backed picture and audio are + registered once, remain lazy, and are sliced per scene without full-track + AUDIO fan-out. +- Split audio intent into final soundtrack, source-reference, and generated- + continuity axes while preserving the exact behavior of saved 0.4 modes. +- Added Cut, Guide, Latent Guide, Detail Guide, Hard AV, and Soft AV incoming- + transition policies with advanced access to the existing low-level controls. +- Aligned Soft AV with the upstream tested recipe: an exact 39-frame picture + prefix plus a half-cosine audio release. The older dual-stream + `feathered_av` implementation remains available through Expert override for + compatibility, and the former Audio Feather AV preset remains as an alias. +- AV continuation now validates the shared 24 fps picture / 40 Hz audio clock + before model loading. Only 39, 90, 141, 192, or 243 context frames are + accepted, eliminating silently rounded prefixes such as 22 or 56 frames. +- Preserved masked-AV decoded overlap audio through Loop Trim and Segment Save + without adding a public socket. Generated-audio assembly now gives the + incoming AV scene ownership of that overlap at both generated-scene and + external-prelude boundaries, so Soft AV's audio feather reaches the final + track; older checkpoints retain delivered-only fallback behavior. +- Updated both maintained soldier-crab extension workflows to the 0.5 Soft AV + policy with a full 39-frame visual seam blend, matching the tested upstream + extension topology while retaining recursive Plan/Run Manager operation. +- Added opt-in Latent Guide continuation. Generated boundaries reuse the + phase-aligned tail of the accepted predecessor's sampled video latent as + persistent Guide conditioning without an RGB/VAE round trip; imported or + incompatible context retains the original Guide fallback. +- Added opt-in Detail Guide continuation, adapting MacroSony's deterministic + tapered chroma-noise context recipe. The 22-frame preset uses 19 frames at + 0.45 and a three-frame taper to 0.10; expert mode supports other Guide + lengths without modifying the accepted predecessor checkpoint. +- Added experimental Detail AV continuation, adapting beijinren's latent + context-noise recipe to the recursive hard-AV path. It treats a disposable + copy of the 39-frame / 12-step video prefix with matched-variance Gaussian + noise using a boundary-clean taper, leaves audio and masks unchanged, trims + the complete treated overlap, and fingerprints the exact recipe for resume. +- Added model-free Chain Preflight and shared Plan Studio validation for source + duration, scene windows, references, runtime compatibility, and resume + eligibility. +- Added a second Plan Studio track for the exact active motion-reference + windows. Selected scenes are transcoded lazily to cached low-resolution + previews, and the player provides synchronized generated/reference wipe + comparison with incoming-context offsets applied automatically. +- Replaced opaque whole-Plan resume hashes with structured scene dependencies + and actionable diffs. Future-scene, incoming-boundary, and assembly-only + changes no longer force regeneration of an accepted predecessor. +- Simplified conditional socket presentation, clarified active Plan versus + selected Run Manager archive state, and made prompt-history activation + explicit. +- Migrated every maintained workflow to explicit policies and preflight. The + source-audio demo now uses canonical Source Timeline wiring and Current + Shot's scene-local reference slice. +- Added an idempotent workflow migration tool, frozen 0.4 positional fixtures, + and backend/frontend release validation. Existing nodes, workflow JSON, + manifests, and checkpoints remain supported. +- Completed input and output tooltips across the 0.5 policy, Source Timeline, + prompt-driven reference, semantic-anchor, masking, and bridge nodes. The + integration smoke fixture now follows the real Current Shot state wire so + strict per-scene source-window provenance is exercised during recovery. + +## v0.4.9 — Run Manager active asset target + +- Made the Run Manager show the connected Plan `run_name` beside Reference + assets so the destination of **Save/update assets** is explicit. +- After a manual asset save, the saved-run browser now selects the actual + destination run instead of remaining on a previously browsed run. +- Kept asset-only run folders selectable for inspection and opening while + leaving **Load into Plan** disabled until a restorable Plan archive exists. + +## v0.4.8 — Feathered AV continuation + +- Added `feathered_av` as a third continuation mode. It uses the same aligned + video/audio target prefix as `masked_av`, but ramps the end of that prefix + from preservation toward generation to soften the temporal handoff. +- For the recommended 39-frame prefix, the first 8 video latent steps and 42 + audio steps remain fully protected. The final 4 video steps and 23 audio + steps use monotonic denoise ramps; all future rows remain fully denoisable. +- Added the mode to Plan, per-scene overrides, Plan Studio, timing validation, + resume provenance, and the native-first PR #15375 compatibility path. +- Added Loop Start `verify_resume_history`, enabled by default. Disabling it + explicitly permits reuse of a saved predecessor after intentional Plan + changes while retaining file, SHA-256, tensor-shape, and internal metadata + integrity checks. +- Corrected sequential Tagged Motion Ref timing under masked AV continuation. + Scene 2+ now excludes the repeated prefix from the unpositioned native video + bank and applies the identical delivered-frame window to paired audio, + removing the context-length motion delay without changing generic video refs. +- Added path-backed Tagged Motion Ref for long CFR control videos. It keeps + compressed media on disk and decodes/resizes only the active scene, converts + that window to 24 fps, and extracts its exact embedded-audio time range. A + separate Plan-aware scene-counter preview blocks media output when no Plan is + connected or the tag is inactive. A native-frame start offset seeks near the + requested source point and shifts video and audio together without building + tensors for the skipped prefix. It also accepts native file-backed `VIDEO` + from core Load Video, allowing that loader to fan out normally to both the + tagged reference and Run Manager asset registration. A dedicated Lazy + Motion AV Loader now exposes that same disk-backed native VIDEO plus the + complete post-skip AUDIO track without decoding any video frames. The tagged + node accepts and passes through that full track, while retaining direct-path + audio extraction for compatibility. + +## v0.4.7 — General masked targets + +- Updated the vendored PR #15375 fallback through upstream commit `989e7a9`. + Arbitrary masks now retain their original per-pixel sampler blend while H3 + pools only its internal video/audio timestep labels to the token grid. Older + ComfyUI builds receive a scoped per-step sampler bridge; post-PR builds keep + their native implementation untouched. +- Made Plan-wide continuation mode and context length next-scene choices for + resume validation. Switching either after a completed scene now reuses that + verified predecessor instead of demanding a pointless regeneration. When a + longer tail was not cached, it is recovered by re-decoding the saved full + video latent. Explicit per-scene overrides remain generation-significant, + and new segment records retain their effective values for provenance. +- Fixed master-audio encoding when H3's rounded 40 Hz target requires one + latent step beyond a floor-style VAE encode of the exact picture duration. + The node uses real timeline-audio lookahead, crops to the authoritative + target length, and keeps `clip_audio` at exact picture duration. +- Added an exact master-audio target composer for timeline-driven FL2VA. It + VAE-encodes the current interval from music, dialogue, narration, or effects + into the complete H3 audio target, protects every audio row, and optionally + protects a native previous-video prefix while future video rows remain + denoisable. +- Added public source-AV trim, 32px mask-grid preview, and arbitrary H3 masked + target nodes for static or tracked video inpainting. +- Added preserve, generate, follow-video, and custom audio-mask modes. New + masks intersect existing nested masks, allowing spatial edits to compose + with the chain's protected `masked_av` prefix. +- Adapted the complete masked-video inpaint workflow to the existing + native-first PR #15375 compatibility. The old per-row MODEL patch is not + required, and distinct public IDs allow both packs to remain installed. +- Documented how the same mask contract extends to prepared outpaint canvases, + temporal repairs, and two-ended clip-bridge targets. + +## v0.4.10 — Final-output publishing + +- Fixed scene and final MP4 publication in ComfyUI's global Media Assets panel + by using the native animated-video output descriptor recognized by job + history. +- Added optional Final Assemble controls to copy the completed MP4 into the + regular ComfyUI output tree. The relative subfolder supports nested folders + and date tokens, an empty value targets the output root, and collisions are + versioned without replacing the canonical chain final. + +## v0.4.9 — Defensive Sol-Attn observer detection + +- Fixed folder-independent Sol-Attn recognition for the defensive + `getattr(self, "segments", ...)` observer used by the Kitchen PR helper, + while continuing to require the complete `_video_span`, `_SPANS`, + `position_ids`, and `segments` fingerprint. Thanks to @tsolful in PR #16 + for identifying the bytecode lookup difference. + +## v0.4.8 — Renamed Sol-Attn observer compatibility + +- Made Sol-Attn H3 layout-observer compatibility independent of the custom + node's install-folder name. Renamed PR helpers such as + `sol_attn_minimax_v2`, lazy installation between scene 1 and scene 2, and + nested read-only observer copies now preserve native Add Guide detection; + unrelated layout-mutating wrappers remain refused. + +## v0.4.7 — Review/editor synchronization and compatibility + +- Synchronized Review Gate with prompt editors bound to the same Plan. A new + review activates its scene in the connected editor, live editor changes are + reflected in the Gate, and retry/reroll reads the current Plan prompt unless + the Gate field was explicitly edited as a fallback. +- Removed the core Ref2VA right-click conversion into Scheduled Ref2VA and its + graph-rewriting implementation. Scheduled and Tagged Ref2VA remain available + as explicit nodes. +- Recognized the audited path-valued H3 layout observer installed by the + `ComfyUI-SolAttn-CUDA-PR117` development checkout, while continuing to reject + unknown wrappers. +- Rotated every browser helper-module cache token with the release so the new + Review Gate/core export contract cannot be mixed with cached v0.4.6 modules. + +## v0.4.6 — Asset publishing and media fallbacks + +- Scene Segment Save and Final Assemble now publish their MP4 paths through + ComfyUI's standard output descriptor contract, so newly produced scene clips + and final videos appear promptly in the global Assets sidebar when enabled. +- FFmpeg executables found on `PATH` are now launch-tested once before use. A + broken Windows build (including `0xC0000139` DLL entry-point failures) is + treated as unavailable so review muxing and final assembly use PyAV instead. +- Versioned every production `.mjs` import with the package release and added + a consistency regression check, preventing stale browser helper modules from + disabling the Plan DOM editor after an update. + +## v0.4.5 — Scene context and checkpoint Plan recovery + +- Added per-scene context-length overrides to the Plan's existing Advanced + controls and Plan Studio. Blank inherits the Plan default; `0` creates a + visually independent scene. +- Added an independent per-scene generated-audio context override. A guide + scene can now use zero video context while retaining preceding dialogue, + ambience, or music; explicit audio `0` disables the carry, while masked AV + remains locked to one synchronized prefix. +- Made timing, masked/guide behavior, imported-video scene 1 handling, resume + hashes, checkpoint tail storage, Run Manager recovery, and checkpoint + revision recovery preserve the effective per-scene context. + +- Made Review Gate's ordinary **Load checkpoint** action restore the saved + run's complete Plan before arming Loop Start. Prompts and Plan settings no + longer remain from whichever workflow happened to be open. +- Reapplied the exact selected checkpoint metadata for every saved predecessor + scene, including active revisions, while keeping plan-only recovery free of + archived-asset materialization side effects. + +## v0.4.4 — Review retry persistence + +- Kept each Review Gate retry's edited scene prompt, seed, and length bound to + the same submitted scene while the server request is in flight. +- Made the server return the accepted prompt and synchronized it into the Plan + and any open prompt companion editor, preventing stale UI state from + replacing the retry prompt. + +## v0.4.3 — Per-scene continuation modes + +- Added per-scene `continuation_mode` overrides in Plan JSON, the compact Plan + editor advanced controls, and Plan Studio. The Plan node setting remains the + inherited default, so one chain can use flexible `guide` transitions for new + shots and exact `masked_av` transitions for continued shots. +- Fixed ComfyUI Stop/Cancel while execution is waiting indefinitely at Review + Gate; the gate heartbeat now observes the processing-interrupted flag and + resolves its browser controls before propagating the normal interruption. +- Added experimental Plan `continuation_mode=masked_av`. Chain Context + VAE-encodes the preceding scene's decoded tail into the next target video + latent, copies the matching sampled audio-latent tail, and emits nested + per-stream masks where `0` preserves the prefix and `1` generates the future. +- Appended a sampler-ready LATENT output to Chain Context without changing its + existing output indices; guide mode and scene 1 pass the original latent + through unchanged. +- Added lazy native-first PR #15375 compatibility for H3 mask payloads, + preprocessing, inpaint scaling, and per-row diffusion timesteps. +- Converted Studio Tagged into the wired 39-frame / 65-audio-step masked AV + example while retaining Tagged Ref2VA and Plan Studio authoring. + +## v0.4.2 — Checkpoint revision recovery + +- Extended the existing Review Gate checkpoint browser to discover every + retained scene revision, preview it, and restore a selected predecessor + chain before resuming the next scene. +- Restoring revisions updates the editable Plan's scene prompts, seeds, + lengths, steps, identifiers, and shared prompt before Loop Start is armed. +- Added guarded cleanup for inactive revisions. Review Gate shows each + revision's estimated storage and requires an explicit permanent-delete + confirmation; active pointers and unrelated run files cannot be removed. + +## v0.4.1 — Tagged source audio and UI fixes + +- Added `source_timeline` playback to Tagged Audio Ref. It fingerprints the full + Loop source track while Tagged Ref2VA derives each exact scene slice from + Current Shot state, avoiding the circular dependency caused by returning a + dynamically sliced audio fingerprint to Plan. +- Corrected every maintained Ref2V example to load the Ref2VA diffusion model + instead of the FL2VA checkpoint inherited from the workflow template. +- Kept the Run Manager's serialized asset-binding state hidden across legacy + and current canvas renderers so its internal JSON field cannot leak into the + visible node layout. +- Constrained the main Plan editor to its assigned DOM-widget bounds and fully + suppressed its internal `plan_json` canvas widget, preventing an intermittent + invisible hit layer from blocking the native Plan settings. + +## v0.4.0 — Prompt-driven Ref2VA and Studio authoring + +- Added Tagged Picture, Video, and Audio references. Register stable aliases + such as `@hero`, `@motion`, and `@voice`; only tags present in the resolved + scene prompt are sent to H3 and compacted to native media labels. +- Retained numeric-range Scheduled Ref2VA under the legacy-schedule category + for workflows that need explicit scene selectors. +- Added optional Plan Studio and Rich Scene Prompt Editor authoring, including + synchronized scene selection, rich reference chips and previews, prompt + revisions, and configurable Direct API or MCP prompt optimization. +- Added maintained T2V and I2V Normal/Studio pairs, indexed A→B→A FL2V, Basic / + Tagged / Studio Tagged Ref2V, and an experimental advancing motion-reference + workflow. Previous examples remain archived rather than deleted. +- Added cumulative disk-backed visual blending, final-assembly playback in + Review Gate, editable retry duration, and exact scene retiming. +- Added native first/last-frame reference previews that follow the active frame + index, plus prompt-driven image, video, and audio miniatures. +- Added portable Run Manager asset restoration to the Studio Tagged example. +- Updated compatibility for merged ComfyUI PR #15439: current ComfyUI owns H3 + guide placement and payload merging; older builds receive one warning before + the guarded fallback is used. +- Added an optional external Plan JSON STRING input for provider-independent + story-director and LLM workflows. + +Credit: native H3 guide support is by **drozbay**; cumulative audio budgeting +was inspired by **seitanism**; the editor interaction pattern was inspired by +**nkxx188's ComfyUI-MiniMaxH3-Easy**. See +[THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md) for the complete attribution. + +## v0.3.28 — PyAV audio rounding tolerance + +Final PyAV muxing tolerates and zero-pads a single missing sample caused by +frame-to-sample rounding while continuing to reject larger audio deficits. + +## v0.3.27 — True disabled scheduler compliance + +Disabled policy reaches upstream Schedule nodes, converts scheduler-owned +validation into warnings, and omits unusable media. An empty +`source_audio_slice` left wired in `generated_audio` mode no longer stops a +render. + +## v0.3.26 — Three-level prompt compliance + +Scheduled Ref2VA offers strict, soft, and disabled policy. Strict blocks +scheduler mistakes; soft relaxes prompt-alias failures; disabled passes prompt +text through unchanged and makes scheduler checks non-blocking. + +## v0.3.25 — Portable run assets and optional tag warnings + +Run Manager accepts dynamic loader-asset connections, records persistent +binding identities and original input paths, and can retain content-addressed +image/audio/video fallbacks under the run folder. Restore prefers the original +input file and materializes an archived fallback only when needed. Scheduled +Ref2VA can downgrade unresolved prompt-tag failures to visible log warnings. + +## v0.3.24 — Saved Run Manager + +A companion node browses projects under `output/h3_chains`, reports scene and +checkpoint details, and restores archived prompts and Plan settings after +confirmation. Exact API/workflow inputs are preferred, with `plan.json` as the +older-run fallback. + +## v0.3.23 — Branching scene-prompt history + +The Scene Prompt Editor keeps lazy per-scene revisions outside workflow and +Plan JSON. Its compact `‹ 2 / 5 ›` control navigates versions, shows execution +state and timestamp, and creates a child branch when an executed revision is +edited. + +## v0.3.22 — Optional floating reroll control + +A ComfyUI setting under **MiniMax H3 Context Loop → Interface → Cancel & +reroll** can hide the floating in-progress action. Review Gate controls remain +available. + +## v0.3.21 — Upstream continuity update and exact assembly + +Motion Context preserves a stock H3 `last_frame` target while replacing a +conflicting first-frame anchor with its carried head. Added 56-frame context, +the in-graph Seam Probe, cumulative generated-audio sample budgeting, and +stitcher-ready retained visual overlap. The cumulative-audio approach was +inspired by **seitanism's** +[MultiRef implementation](https://github.com/seitanism/ComfyUI-H3-Motion-Context-MultiRef). + +## v0.3.20 — Cancel and reroll the active scene + +During generation, a guarded floating action can cancel only the active prompt, +assign a new explicit scene seed, preserve the selected range end, and requeue +through ComfyUI's normal queue. + +## v0.3.19 — Plan and review UX pass + +Plan controls retain pointer input, editor and preview sizes persist, scene +seeds remain visible, and reference menus show only sources active in the +selected scene. Documentation clarifies that `@aliases` are optional. + +## v0.3.14 — Explicit compatible patch priority + +The optional wired **MiniMax H3 Patch Priority** pass-through can promote this +pack over an older compatible Motion Context copy while retaining recognized +H3-Multishot and SolAttn behavior. + +## v0.3.13 — Open a Plan's output folder + +A compact **Output** action creates and opens +`output/h3_chains/` on the ComfyUI host. Headless hosts fall back to +copying the host path into the browser clipboard. + +## v0.3.12 — Clearer Plan guidance and looping I2VA + +Expanded Plan tooltips, clarified audio modes and seed rerolls, and added a +single-image I2VA example plus First-Scene Image Gate. + +## v0.3.11 — Invisible legacy widget-width repair + +While a Context Loop node is on the canvas, the pack repairs the LiteGraph +widget-width regression across all nodes. Regenerated scenes retain previous +segment and checkpoint revisions instead of deleting the superseded take. + +## v0.3.10 — Scene-scheduled Ref2VA + +Added chained picture, video, paired-video-audio, and standalone-audio +references under stable `@tags`, with per-scene activation and compact native +label numbering. A right-click converter migrates an already-wired core Ref2VA +node. + +## v0.3.8 — One-pass performance re-filming + +Reference Video Prep converts native VIDEO or decoded IMAGE/AUDIO to exact +24 fps Ref2VA input, copies its soundtrack without padding or time-stretching, +and powers the experimental three-angle guitar workflow. + +## v0.3.7 — Flexible video loaders + +Existing Video Context accepts either native ComfyUI VIDEO or separate +IMAGE + AUDIO + FPS outputs. + +## v0.3.6 — Extend an existing video + +A typed adapter turns decoded video and optional audio into scene 1 context, +with optional normalized-source prepend for partial and final output. + +## v0.3.5 — Native guides and portable assembly + +Added automatic support for ComfyUI's native arbitrary-position AV guides, +retained the guarded legacy path, and added PyAV fallback when `ffmpeg` is not +available. + +## v0.3.4 — Scene Prompt Editor + +Added the synchronized large-format scene editor with navigation, reference and +dialogue shortcuts, and adjustable type size. + +## v0.3.3 — Reliable preview resizing + +Review video sizing remains stable when the ComfyUI canvas is zoomed. + +## v0.3.2 — Resizable review video + +The bar beneath Review Gate's player adjusts preview height. + +## v0.3.1 — Friendlier JSON defaults + +Top-level `duration_seconds` and `steps` shorthand populate visual Plan defaults +correctly. + +## v0.3.0 — Archival PNG export + +Saved scene checkpoints can be re-decoded into a continuous lossless PNG +sequence without holding the complete production in RAM. + +## v0.2.0 — Recovery, metadata, and compatibility + +- Persisted each scene prompt, effective plan, workflow, and API prompt beside + the rendered chain. +- Added scene-range rendering, resumable review checkpoints, partial assembly, + notification/timeout controls, and Firefox-safe Review Gate recovery. +- Added guarded compatibility with H3-Multishot, SolAttn, Ref2VA, and upstream + H3 Motion Context. +- Added Comfy Registry publishing and a shorter project-focused README. + +## v0.1.0 — The production loop takes shape + +- Introduced the visual scene-plan editor, multiline prompts, automatic scene + colors, responsive layout, and collapsible raw JSON. +- Added the recursive one-body chain, frame-locked audio trimming, per-scene + checkpoints, interactive review/retry, and looping Ref2VA example. +- Renamed the expanded project **MiniMax H3 Context Loop** so it could coexist + clearly with NikoDemon80's manual Motion Context tools. + +## Origins — Motion Context and Ref2VA continuation + +The project began with MiniMax H3 clip chaining and generated-audio +continuation, then added Ref2VA Motion Context, opt-in compatibility patches, +and the resumable disk-backed production loop. diff --git a/ComfyUI-MiniMaxH3-Context-Loop/CONTRIBUTING.md b/ComfyUI-MiniMaxH3-Context-Loop/CONTRIBUTING.md new file mode 100644 index 0000000000000000000000000000000000000000..633a7d7a5aab4c30cdd892432e72b2d5607351c1 --- /dev/null +++ b/ComfyUI-MiniMaxH3-Context-Loop/CONTRIBUTING.md @@ -0,0 +1,75 @@ +# Contributing + +Focused fixes, workflow improvements, compatibility updates, and documentation +corrections are welcome. Open an issue before a large redesign so its runtime +and saved-workflow compatibility can be discussed first. + +## Keep version 0.5 compatible + +Version 0.5 preserves saved 0.4 workflows and checkpoints. Unless a change is +explicitly planned as a breaking release: + +- do not reuse or rename an existing public node class ID; +- do not reorder existing positional inputs or outputs; +- append new optional inputs and outputs instead of inserting them; +- retain readable legacy widget values and checkpoint formats; +- keep compatible H3-Multishot, SolAttn, and shared patch markers intact. + +The frozen rules are documented in +[Version 0.5 architecture](docs/V0_5_ARCHITECTURE.md) and enforced by +`tests/fixtures/v0_4_public_contract.json`. + +## Document behavior from evidence + +Use the implementation, tests, maintained workflows, and upstream source as +the authority. A user-facing claim should point to a working example or a +specific implementation path. Mark experiments as experimental and describe +their fallback or compatibility behavior. + +When a change is derived from another project, update +[Feature traceability](docs/FEATURE_TRACEABILITY.md) and +[Third-party notices](THIRD_PARTY_NOTICES.md) together. Record: + +1. the upstream repository and author; +2. the revision or pull request used; +3. the upstream license; +4. the local files that implement the feature; +5. whether the relationship is **adapted**, **inspired**, **integrated**, or + **compatibility-only**. + +Do not describe an integration with an upstream API as copied code, and do not +describe an adaptation as an original implementation. + +## Validate a change + +Run the focused test for the area you changed. Before release or a broad pull +request, run at least: + +```bash +python tests/_node_smoke_test.py +python tests/_chain_smoke_test.py +python tests/_workflow_catalog_unit_test.py +python tests/_v05_contract_unit_test.py +``` + +Masking, source-timeline, frontend, and migration changes have additional +targeted scripts under `tests/`. JavaScript tests use Node directly, for +example: + +```bash +node tests/_plan_editor_js_test.mjs +``` + +Tests intentionally use mock ComfyUI modules where possible. Real generation +still needs a current ComfyUI installation, H3 models, and appropriate media. + +## Keep the README approachable + +The README is a workflow chooser and quick start. Put algorithms, complete +node settings, and recovery internals in the focused guides under `docs/`. +Prefer short tables, task-based headings, and links to deeper explanations. + +When adding or retiring a maintained workflow, update +`example_workflows/README.md` and `tests/_workflow_catalog_unit_test.py` in the +same change. Keep prompt and media attribution beside the workflow that uses +it. diff --git a/ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/.github/FUNDING.yml b/ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/.github/FUNDING.yml new file mode 100644 index 0000000000000000000000000000000000000000..d786d7ac1cb85900e976ca85cfe989714674e442 --- /dev/null +++ b/ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/.github/FUNDING.yml @@ -0,0 +1 @@ +ko_fi: matlowai diff --git a/ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/.github/workflows/nightly-publish.yml b/ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/.github/workflows/nightly-publish.yml new file mode 100644 index 0000000000000000000000000000000000000000..b5a74f540b07221698387c1cdf155accca51941c --- /dev/null +++ b/ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/.github/workflows/nightly-publish.yml @@ -0,0 +1,97 @@ +name: Nightly Registry Publish + +# Batches a day's commits into ONE registry version. Registry versions are +# immutable and permanent, so publishing per-push would leave users scrolling +# through a version per commit. +# +# Self-correcting: it asks the registry what is already published rather than +# assuming. If the version in pyproject.toml was never published, it ships that +# as-is (covers a hand-made release). If it was, and main has moved since, it +# bumps the patch and ships that. If main has not moved, it does nothing. +on: + schedule: + - cron: "0 9 * * *" # 09:00 UTC daily + workflow_dispatch: + inputs: + force: + description: "Publish even if main has not moved" + type: boolean + default: false + +permissions: + contents: write + +concurrency: + group: registry-publish + cancel-in-progress: false + +jobs: + publish: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: { fetch-depth: 0 } + + - name: Decide whether to publish, and at what version + id: decide + run: | + set -euo pipefail + CUR=$(python3 -c "import tomllib;print(tomllib.load(open('pyproject.toml','rb'))['project']['version'])") + NAME=$(python3 -c "import tomllib;print(tomllib.load(open('pyproject.toml','rb'))['project']['name'])") + echo "pyproject version: $CUR" + + PUBLISHED=$(curl -sf "https://api.comfy.org/nodes/$NAME/versions" \ + | python3 -c "import json,sys;d=json.load(sys.stdin);v=d if isinstance(d,list) else d.get('versions',[]);print(' '.join(x.get('version','') for x in v))" || echo "") + echo "already published: [$PUBLISHED]" + + LAST_TAG=$(git tag --list 'published-*' --sort=-v:refname | head -1) + MOVED=1 + if [ -n "$LAST_TAG" ] && [ "$(git rev-list -n1 "$LAST_TAG")" = "$(git rev-parse HEAD)" ]; then + MOVED=0 + fi + echo "last published tag: ${LAST_TAG:-none} | main moved: $MOVED" + + if ! echo " $PUBLISHED " | grep -q " $CUR "; then + echo "version=$CUR" >> "$GITHUB_OUTPUT"; echo "bump=no" >> "$GITHUB_OUTPUT" + echo "go=yes" >> "$GITHUB_OUTPUT" + echo "-> $CUR is not on the registry yet; publishing it as-is" + elif [ "$MOVED" = "1" ] || [ "${{ inputs.force }}" = "true" ]; then + NEXT=$(python3 -c "p='$CUR'.split('.');p[-1]=str(int(p[-1])+1);print('.'.join(p))") + echo "version=$NEXT" >> "$GITHUB_OUTPUT"; echo "bump=yes" >> "$GITHUB_OUTPUT" + echo "go=yes" >> "$GITHUB_OUTPUT" + echo "-> main moved since ${LAST_TAG:-the last publish}; bumping $CUR -> $NEXT" + else + echo "go=no" >> "$GITHUB_OUTPUT" + echo "-> nothing to do: $CUR is published and main has not moved" + fi + + - name: Bump the patch version + if: steps.decide.outputs.go == 'yes' && steps.decide.outputs.bump == 'yes' + run: | + set -euo pipefail + python3 - <<'PY' + import re, os + v = os.environ["V"] + s = open("pyproject.toml").read() + s = re.sub(r'(?m)^version\s*=\s*".*"$', f'version = "{v}"', s, count=1) + open("pyproject.toml", "w").write(s) + PY + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git commit -qam "release: v${{ steps.decide.outputs.version }}" + git push -q origin HEAD:main + env: + V: ${{ steps.decide.outputs.version }} + + - name: Publish + if: steps.decide.outputs.go == 'yes' + uses: Comfy-Org/publish-node-action@main + with: + personal_access_token: ${{ secrets.COMFY_REGISTRY }} + skip_checkout: 'true' + + - name: Mark what was published + if: steps.decide.outputs.go == 'yes' + run: | + git tag -f "published-${{ steps.decide.outputs.version }}" + git push -qf origin "published-${{ steps.decide.outputs.version }}" diff --git a/ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/.github/workflows/publish-node.yml b/ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/.github/workflows/publish-node.yml new file mode 100644 index 0000000000000000000000000000000000000000..8a1f6828a10ef5a68fe189ca819c6b9430d67748 --- /dev/null +++ b/ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/.github/workflows/publish-node.yml @@ -0,0 +1,22 @@ +name: Publish to Comfy Registry + +# Publishes when pyproject.toml changes on main (i.e. a version bump), and on +# demand. The registry rejects a re-publish of an existing version, so the +# version field is the release switch. +on: + push: + branches: [main] + paths: ["pyproject.toml"] + workflow_dispatch: + +permissions: + contents: read + +jobs: + publish: + runs-on: ubuntu-latest + steps: + - name: Publish custom node # the action checks out for itself + uses: Comfy-Org/publish-node-action@main + with: + personal_access_token: ${{ secrets.COMFY_REGISTRY }} diff --git a/ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/.gitignore b/ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..7a60b85e148f80966a550e5ab6a762a907c69ca6 --- /dev/null +++ b/ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/.gitignore @@ -0,0 +1,2 @@ +__pycache__/ +*.pyc diff --git a/ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/ALPHA.md b/ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/ALPHA.md new file mode 100644 index 0000000000000000000000000000000000000000..d32f68eb28efcad56eac923de5fe11af7257c626 --- /dev/null +++ b/ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/ALPHA.md @@ -0,0 +1,294 @@ +# What is alpha here, and how alpha is it + +This pack ships finished work and unfinished work in the same install. The +finished work is the Motion Lab de-rope pipeline and the contact sheet; it +has been measured, it has example graphs, and its dials have numbers behind +them in TUNING.md. Everything on this page is the other kind. + +Alpha here means one or more of: it has run on one machine and no others, +the interesting half of it is not built, its interface will change, or it +is a real capability that simply has not been tested on enough material to +know where it stops working. Each entry below says which. + +Nothing on this page changes existing behaviour or defaults. Alpha nodes +carry `(alpha)` in the name you see in the ComfyUI menu, and the subsystems +load behind a guarded loader, so a broken alpha module cannot take the rest +of the pack down with it. + +If you find something wrong, an issue with the symptom and the graph is +worth more than a fix. Symptom-and-dial pairs belong in TUNING.md. + +--- + +## Concept Lab + +`concept_lab/`, and the nodes `MAI Concept Capture Arm / Flush` and +`MAI Concept Inject Delta`. + +A research subsystem on the bet that a reusable concept does not have to +live in trained weights and can instead live in a measured functional +delta: measure what a piece of conditioning actually does to the model, +factor that into reusable components, compile them back through the model's +own conditioning channels. + +**State: the interesting half is not built.** What exists is the data +layer (contracts, workspace, verbs, three surfaces over them) and an H3 +capture tap that rides along on a render. What does not exist is anything +that turns a capture into a factor, or a factor into conditioning. Unbuilt +verbs raise and name the task that blocks them rather than returning an +empty result, because in a subsystem whose output is evidence a quiet +nothing is worse than a refusal. + +Full status table, the layering rules, and a Contributing section naming +the four things most worth receiving: **`concept_lab/README.md`**. The +design decisions and their reasoning are in `concept_lab/DECISIONS.md`. + +## Extension (long clips from short renders) + +`h3_extend.py`: `H3 Extension Plan`, `H3 Tail Context`, `H3 Protect Prefix`, +`H3 Prefix Freeze Mask`, `H3 Trim`, `H3 Seam Normalize`; the shared types +in `capsule_types.py`; the graph `examples/motion_pipeline_extend_api.json`; +edge-protection dials on `H3 Jerk Oracle` (`protect_tail`) and +`H3 Window Plan` (`edge_protect`). + +Short segments generated and de-roped one at a time, the last 39 frames +carried into the next segment, the overlap trimmed at assembly. Integer +time throughout: the 141/39 atom adds exactly 102 frames and 170 audio +ticks per segment. On a core with per-token masks (#15375) the handle is +WRITTEN INTO the next segment's own pass-1 latent under a time-varying +mask, with the audio handle on an audio-only `MiniMaxH3AddGuide`; on older +cores the whole handle rides the guide. The de-rope holds the prefix at 1 +AND freezes it in pass 2; a non-final segment's last 17 frames are also +held at 1, because a gesture that runs into the cut has no "after" to slow +into and comes back fast otherwise. `H3 Seam Normalize` fits per-channel +linear-light gains on the hidden prefix (each VAE round trip darkens it +~2.4%) and applies them to the new material; its audio rms gain measured +NEGATIVE and defaults off. + +**State: measured on two content sets, one machine, two segments.** The +masked path beats the image guide everywhere we measured: join jerk 0.86x +to 1.1x the clip's ordinary frame-to-frame motion vs 5x to 6.5x for the +guide, camera velocity continuous through the join instead of reversing, +handle within 2.2 to 3.3/255 of the carried tail, ~20% less wall (no +guide rows in every block). The closing-gesture fix measured 1.55x -> 1.06x. +Unmeasured: more than two segments (the drift curve), the 192/90 atom, +lower inject on continuation segments, dialogue across a join, and the +audio ambience bed, which still steps at the cut (a per-tick audio mask +is the planned fix). The API graph is the only form shipped so far. + +## The timeline surface + +Nodes: `H3 Drawn Plan`, `H3 Plan Settings`, `H3 Plan Estimate`, +`H3 Timeline Analyze`, `H3 Timeline Render`, `H3 Flight Recorder Start` and +`Stop`. + +A plan document as the single source of truth: something proposes a plan, +a human edits it, a compiler turns it into a legal graph. The node surface +reaches parity with the compiler route, and the splice is proven on tensors. + +**State: real but young.** The interface is expected to move, and the +editing experience around it is not built. If you are looking for the +production route, use the ordinary de-rope graphs. + +## The audio init for dialogue + +`H3 Audio Smear`, plus `audio_latent` / `audio_mode` on `H3 V2V Init` and +`audio_source` on `H3 Audio Recover`. + +Fixes a real defect: a de-rope breaks speech, because the picture gets an +init and obeys it while the audio starts from zeros, so pass 2 writes a +fresh performance at natural rate and moves the mouth to that. Seeding the +audio rows with the baseline performance stretched onto the same dilated +clock makes pass 2 render a genuinely slowed take. The README's +"Dialogue through a de-rope" section has the adoption steps. + +**State: it works, on material we have not varied enough.** The geometry +is solid: the smear/recover round trip is sample-exact in both directions +with envelope correlation 0.975, and the init costs nothing measurable in +picture quality. But it has been heard on a handful of clips, all +two-speaker sword-fight material at hold factors around 4 and dilations +between 2.4x and 2.7x. A single speaker, speech over music, non-anime +footage, and other hold factors are all unmeasured. If you try one of +those, that result is worth reporting whichever way it goes. + +## The motion adapter (pilot) + +A rank-16 LoRA trained on the de-rope task itself, applied to the de-rope +pass only. Documented with its measured settings and its known costs in the +README's "The motion adapter (pilot)" section, and released as an +intermediate option rather than a finished one. A more ambitious all-in-one +adapter is in progress and may not work. + +## Manual mask paths + +The `(alpha)`-tagged inputs on `H3 V2V Init` and `H3 Motion Composite`: +manual region masks, final-alpha masks, and the time-varying mask path. +These are exercised by the checklist in **`TESTING_ALPHA.md`**, which +covers the 2026-08-09 node batch and still wants human passes on the +interactive widget and the drag-in workflows. + +--- + +## VRAM Lab + +`H3 Streamed Blocks`, `H3 Memory Probe`, `H3 Free Cache`, `H3 Evict Text +Encoder` (`vram_lab.py`, 2026-08-18). Alpha because it has run on one +machine (RTX PRO 6000 Blackwell, 188 SMs) and its exactness is a kernel +property, not a code property: query chunking is bit-equal only while every +chunk keeps PyTorch's flash kernel off its split-KV path (measured boundary +`heads x ceil(L/64) >= 0.8 x 2 x SMs`; the node sizes chunks from the SM +count with a 2.6x margin and carries a `self_check` that compares stock and +streamed on the first block's real input). int8 and W4A8 checkpoints are +bit-equal by mechanism (row-wise activation scales, int32 accumulate); +NVFP4/FP8 would need one shared activation scale and are untested; bf16 is +numerically equivalent, not identical. `kv_block` is experimental and as +built does not lower memory (leave it at 0). The output head has an exact +mode (default) and a chunked-GEMM mode that changes the clip after 25 steps +by ~1e-6 per step of fp32 difference; that mode is labelled and off. + +What was measured, one graph (294 f -> 702 f de-rope at 1376x768, ~217k +tokens): torch activations peak +11.9 GiB over the weight floor at any +card; a 16 GB card in a 32 GB machine renders it with ComfyUI's dynamic VRAM +and `--fast-disk` at 316 s/step; a 96 GB card resident is 311 s/step. RAM is +the small-machine ceiling in normal mode (CPU copies of the models without +`--fast-disk`, and CPU-side IMAGE intermediates); the text encoder costs +1 to 2.5 GiB of peak on a 16 GB card and about 3 s per new prompt, and +either eviction or the conditioning bank removes it. Untested: other GPUs, +Windows, ROCm, non-flash attention backends (cuDNN and mem-efficient are +chunk-invariant at every length here but 1.1 to 2x slower; no two backends +are bit-equal to each other). + +The `kv_store` options (`kvi8r`, `kvi8s`) are the approximation tier of the +same node: half the K/V bytes (kvi8r measured +9.5 GiB forward peak against +the exact +11.9 at 217k tokens; kvi8s attends on int8/fp8 tensor cores +straight from the store, ~1.6x faster attention standalone), same-seed +renders are sibling takes, and only kvi8r's first cut has been in front of +eyes ("almost perfect" on the de-rope side by side, one clip, one viewer). +The node defaults to the exact store; the low-VRAM example graph turns kvi8r +on (operator's call for that graph); the table with the numbers and what is +still owed is in LOWVRAM.md. The int8_convrot video VAE now in the example graph is also an +approximation (60 dB PSNR against the fp16 decoder on the same latent). + + +## Time burst (examples/experimental/time_burst_api.json) + +Alpha because: one clip, one seed, one machine, and the effect is a defect +worn as a feature. The windowed insert with noise-born in-betweens and no +guide has no clock inside the window, so it rushes the span (about 2.7x the +source speed on the shipped clip) and invents flares. The graph is the exact +one that made `assets/time_burst_result.mp4` from `assets/time_burst_plate.mp4`, +so the first run is a reproduction, not an experiment. What is not built: +any control over how hard it rushes beyond the hold map and inject; a +second clip; a null pair. If you want the ordinary insert, start from the +motion pipeline graphs instead. + +## Where to look next + +| | | +|---|---| +| `concept_lab/README.md` | Concept Lab status, layering, contributing | +| `TESTING_ALPHA.md` | hands-on checklist for the manual mask and editor batch | +| `TUNING.md` | dials with measured numbers, for the finished pipeline | +| `ROADMAP.md` | where the unfinished parts are meant to go | + +--- + +## Repair verb + +`h3_repair.py`, nodes `H3 Repair Plan (alpha)` and `H3 Repair Splice (alpha)`. + +Type a bad frame range; the plan snaps it outward to whole tokens, runs the +regeneration through the nearest shot cut, and the splice puts every +untouched pixel back bit-exact, printing its seam numbers. Validated on one +cell and one in-graph rerun (entry seam 0.26x the clip's median frame delta, +exit ON the source's own cut within 1.8%). Alpha because: one scene family +so far, and AUDIO IS STILL A WORK IN PROGRESS: the splice passes audio +through untouched, which is only right when the repair changed no performance. + +## DyRoPE + +`motion.py`, node `H3 DyRoPE (alpha)`. + +An instrument that hands the de-rope's two clock geometries (true world time +vs the trained grid) to different transformer blocks or different denoise +steps. The dose map is measured and in TUNING.md: two settings keep the +world-time correction, everything below them loses it, everything above adds +shimmer. Alpha because: one scene measured deeply, everything else untested. + +## Audio prefix freeze + +`motion.py`, inputs `audio_prefix_ticks` and `audio_prefix_release_ticks` on +`H3 V2V Init`. + +The audio twin of the video prefix freeze, with a half-cosine release. +Bench-tested on chained music (overlap correlation ~0.92 in the full +chain, 0.98 on the pass-1-only control; beat phase 0.0 ms). It carries local continuity (level, timbre, beat), +not a track's global phrase structure. Alpha because: the caveat list in the +README section is load-bearing; read it before wiring. + +## Drift Control + +`h3_drift.py`, node `H3 Drift Control (alpha)`. + +Schedule-matched noise on a carried video prefix so a chain's later joins +stop drifting. Second-join delta 0.680 to 0.860 with the first join +unchanged; replicated across two chains and new seeds; joins hold 0.85-0.89 through link 4 (the earlier chain sat in the 0.65 class at its second +join before the recipe; cross-chain comparison, not a paired arm). Refuses to stack with +any other dynamic denoise-mask patch; sigma-split samplers unsupported. + +## Color Carry + +`h3_color_carry.py`, nodes `H3 Delta Color Carry (alpha)` and +`H3 Scene Color Stats (alpha)`. + +Cancels the VAE round-trip color bias on a carried prefix by adding only +E(corrected) minus E(original) to the latent, so the encode bias cancels and +the weak scene-one grade survives. Active path exercised on a real 4-link render 2026-08-24: it fires, corrects in the anchor direction, and stays sub-visible under its clamps on mildly-drifted content; on the deepest tested link it fires on both channels at or near its clamp. A strong-drift bench is still owed. + +## Video Compare viewer (upgraded player) + +`video_compare.py` + `web/video_compare.js`. The review player grew a +timeline, loop brackets, waveform, blips and a frame-exact export this +release. KNOWN ISSUES, alpha honesty: multi-video playback inside the +ComfyUI node surface does not hold sync reliably (browser video elements +each run their own clock; every correction strategy trades stutter for +offset), and the transport can wedge after scrubbing during playback - +re-queue or reload the page to recover. The standalone deck pages built +by `tools/compare_deck/` do not share these problems. Two more, both about +audio: in clock sync mode audio follows only the clock-owning side, so +locking audio to the other pane is silent until sync mode is flipped; and +the realtime export records audio from the locked side even when it is not +one of the two playing panes, so prefer the precise export. Planned fix, +next iteration: the node bakes each pair into ONE combined preview stream +and every view mode becomes a crop of it - one decoder, one clock, sync by +construction. Deferred with it: the player is duplicated (~330 lines) +between `web/video_compare.js` and the deck template, and a single-source +refactor is the next iteration's job (the deck's export bitrate selector +having been honored on only one of the two export paths was the first bite +of that divergence). + +## Mid-denoise insert + +`motion.py`, node `H3 MidInsert (alpha)`. + +Inserts time-dilation tokens into a still-noisy latent at a handoff sigma +instead of between passes, with a measured variance top-up. Kept for +research honesty: at its one tested operating point (handoff sigma 0.53, +four dense steps) it breaks clip continuity in playback, and it is +documented as that negative rather than removed. Do not reach for it in +production; the two-pass insertion path is the shipped construction. + +## VRAM lab instruments + +`vram_lab.py`, node `H3 FakeQuant (alpha)`. `H3 Sol Attention` is in the +code but NOT registered this release. + +Measurement instruments from the quantization review work: FakeQuant +fake-quantizes a chosen region of the model's activations so a precision +regime can be auditioned without real kernels; Sol Attention switches the +attention path for the same kind of audition. Instruments, not +accelerators: they exist to make honest comparison pages, and their +numbers only mean something next to a reference arm. FakeQuant ships; +Sol Attention stays unregistered until it gets the DyRoPE arm/disarm +pattern, because it rebinds attention process-globally with no restore +path. diff --git a/ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/DEROPE_ANY_MODEL.md b/ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/DEROPE_ANY_MODEL.md new file mode 100644 index 0000000000000000000000000000000000000000..7e13d8b7b87c2a7d92a00309ffaf88c56994cfd6 --- /dev/null +++ b/ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/DEROPE_ANY_MODEL.md @@ -0,0 +1,156 @@ +# De-rope for any model (branch `generic-derope`, not shipped) + +This branch carries two things: the LTX-2.5 graphs and tools behind the public +de-rope deck (https://matlowai.github.io/flipbook/derope.html), and the +any-model layer that lets one hold map drive any regenerating model through +per-model presets. It is a branch on purpose: what ships on `main` is the H3 +Motion Lab; this merges once the oracle-shaped LTX arm has been measured. + +## What it does today: a FLAT clock + +An H3 de-rope (`H3JerkOracle` -> `H3TimeSmear` -> regenerate -> `H3ExactRecover`) +slows each frame by its own hold (1 to 4, with ramps and bridges), which is what +makes the regenerated motion land on the right frames. The LTX-2.5 graphs here +use the H3 oracle only to choose WHERE the window sits (its hot span), and inside +the window every frame is held exactly d times (`ImageBatchRepeatInterleaving`, +d = 8 or 16), padded to LTX's legal length (8k+1), regenerated from a given +starting sigma, and recovered by taking every d-th frame. + +Why flat: LTX compresses time by 8, so a held frame only owns its own latent +block when its hold is a multiple of 8 frames. Holds of 1 to 4 share blocks, and +measured on two scenes that is exactly where d=8 barely responds to the denoise +dial (0.94 to 0.90 across 0.1 to 0.9) while d=16 moves it (0.90 to 0.28). + +Per-pass cap: 57 source frames at d=16 (`positional_embedding_max_pos[0] = 20` +with time in absolute seconds). Full coverage of a longer clip is several +overlapping windows joined by `tools/ltx25/splice_windows.py`, which measures +PSNR across each overlap before it blends. + +## The any-model layer (new nodes) + +The smear, recover and audio nodes were already pixel-level and model-agnostic; +what was H3-specific was the grid law (17k+5 lengths, holds in H3 frames). That +law is now data, `model_profiles.py`, and one node applies it: + +- **H3 Clock Remap (any model, presets)** - wire any hold map (H3 Jerk Oracle, + H3 Manual Hold Map, H3 Drawn Plan), pick the model that will regenerate the + frames. Holds of 2+ are scaled by the profile's `hold_scale` and quantised + to whole latent time blocks; holds of 1 stay 1 (plain video anywhere). The + output map carries the target's legal grid, so **H3 Time Smear pads to that + grid** (LTX-2.5: 8k+1, not 17k+5) and H3 Exact Recover / H3 Audio Recover + invert it unchanged. `minimax-h3` is the identity: existing graphs do not + change by construction (tests assert it). The report is the price tag: frames, + seconds at the model's fps, windows needed under its cap, and a loud + UNMEASURED line for any profile whose numbers did not come from a ladder. +- **H3 Save Hold Map / H3 Load Hold Map (sidecar)** - write `.holdmap.json` + beside the render; read it back by prefix (newest wins) in another graph, so + the H3 pass decides the clock and an LTX-2.5 or Wan 2.2 graph regenerates on + it without both models loaded at once. Load hands back the ORIGINAL clock + (`source_holds`), never a previous target's grid. Without it a render's clock is lost when the graph closes; with it the + staircase ruler can read H3 arms and a later remap can retime the same plan. +- **H3 Jerk Oracle `profile_mode`: "value |d3| camera-compensated"** - aligns + each latent frame to its predecessor by the best small integer shift before + differencing, so a pan or scroll stops scoring as jerk (the documented cause + of panrun dilating 124 -> 345 frames). Same compiler, different signal. + +- **H3 Jerk Oracle `model_profile`** - the oracle can read ANOTHER model's + video latent: pick the preset whose latent is wired in (LTX-2.5: 128 + channels on a 1+8k token clock; Wan 2.2: 16 channels, 1+4k). Same planner, + that model's frame<->token mapping, no H3 phase normalisation, holds per + source frame as before. Wrong channel counts and wrong lengths are refused + with a message that says what was expected. `minimax-h3` is the shipped + path, bit-identical (tested). An independent port of the three motion nodes + onto LTX-2.3/2.5 latents appeared publicly in August 2026 and confirmed this + is the right seam: the oracle, the smear and the recover carried over with + only the grid law changed, which is exactly what the profile holds. + +### Profiles + +| id | block | hold_scale | legal | fps | cap | latent (channels, clock) | measured | +|---|---|---|---|---|---|---|---| +| `minimax-h3` | 1 | 1 | 17k+5 | 24 | VRAM | 24, (1,4,4,4,4) per 17 (H3 code path) | yes | +| `ltx-2.5` | 8 | 4 | 8k+1 | 48 (the conditioning frame_rate) | 20 s / pass = 960 frames | 128, 1+8k | yes (2026-08-21 ladder) | +| `wan-2.2 (unmeasured)` | 4 | 4 | 4k+1 | 16 | none | 16, 1+4k | NO - placeholder | + +`hold_scale` is measured, never derived: LTX-2.5 needed two 8-frame blocks per +hot hold (d=16) before the dial responded at all, which its compression ratio +alone would not have told you. + +### Adding a model without touching code + +Pick `custom (use the fields below)` on the node and type the five numbers; the +report stamps the result unmeasured. When a row works, save it as a preset: +create `/mainodes_models.json` (or point +`$MAINODES_MODELS_JSON` at a file) with + +```json +{"my-model": {"name": "My Model", "block": 4, "hold_scale": 4, + "legal": [4, 1], "fps": 16, "cap_seconds": null, "measured": false, + "latent": {"channels": 16, "first": 1, "block": 4}}} +``` + +and restart: it appears in the dropdown, and a row with a preset's id +overrides that preset. Send us the row and the ladder behind it. + +### First measurements (2026-08-21, one pass on two lab instances) + +- H3 two-stage graph with the identity remap in the chain: **bit-identical** + to the production render (PSNR inf on baseline, dilated and recovered). +- LTX-2.5 on the camera-compensated H3 clock at x4: panrun needs a window + (the live clock is 1201 dilated frames at x4, over the 960 cap; a 98-frame + window fits at 951), swordspin fits whole (866). Hold-map staircase 0.864 + (panrun) / 0.818 (swordspin) at starting sigma 0.4, against 0.80 / 0.78 for + the uniform d=16 windows: **the oracle-shaped clock does not fix LTX's weak + response at that denoise; the denoise is the limiter, not the clock.** + 298 s / 247 s, peak 59-60 GiB. +- Wan 2.2, first ladder cell (x1, 21-source-frame window on the densest + hold-4 run, low-noise 14B expert, denoise 0.4, 640^2): staircase **0.693** + on swordspin (the lowest of the set), 0.877 on panrun's window; 119-126 s + including the model load, peak 33-52 GiB. The `wan-2.2` preset stays + unmeasured until the x1/x2 ladder settles its hold_scale; x4 cannot fit + Wan's 81-frame training length. +- Camera-compensated oracle: identical to the default on the static swordspin + shot; trims panrun's held span 80 -> 76 frames. + +### Sizing the oracle-shaped LTX arm + +On the saved oracle profiles the x4 rule gives panrun 712 / swordspin 816 +dilated frames over the hot span, under the 960-frame cap (913 was the largest legal length used), so it fits one +pass at the same cost as the uniform d=16 window with the time budget spent +where the oracle put it. That arm is the one measurement left before this +merges. The x8 rule (hold 4 -> 32x) needs two windows per scene. + +## Files + +- `examples/ltx25/derope_any_model_ltx25_api.json` - the any-model path on + LTX-2.5: H3 Manual Hold Map (or an oracle) -> H3 Clock Remap (`ltx-2.5`) -> + H3 Time Smear -> the LTX-2.5 pass -> H3 Exact Recover, with H3 Save Hold Map + beside the render. API JSON (drag onto the canvas); the UI twin lands once + an instance with these nodes can convert it. +- `examples/ltx25/derope_any_model_h3_oracles_api.json` - the H3 base pass with + both oracle modes (default, camera-compensated), each saved as a sidecar, plus + the identity remap saved beside them for a bit-exact check. +- `examples/ltx25/derope_any_model_ltx25_fromsidecar_api.json` - the whole clip + on LTX-2.5 in ONE pass from the camera-compensated sidecar (panrun: 124 frames + -> ~785 dilated under the 960-frame cap, quiet frames at native rate). +- `examples/wan22/derope_any_model_wan22_api.json` - the same clock on Wan 2.2 + (low-noise 14B expert, v2v from the smeared frames at denoise 0.4, 640^2, + 16 fps, 4k+1 grid from the `wan-2.2 (unmeasured)` preset): the first ladder + cell that turns that preset's numbers into measured ones. +- `examples/ltx25/` - four graphs as run for the deck, API JSON (`*_api.json`, + what actually executed) and UI JSON (paste on the canvas): + `panrun_or_d16_d040` (uniform d=16 de-rope of the oracle window), + `swordspin_or_d8_d050` (d=8), `swordspin_or_x2_d8_d050_d030` (one-pass x2 + latent upsample of a d=8 pass), `panrun_ltx_d040_full` (first of the three + windows behind the spliced full-length clip). + Source clips are referenced by basename: put yours in ComfyUI `input/`. +- `tools/ltx25/mint_ltx25_derope.py` - mints a uniform de-rope graph from the + stock LTX-2.5 T2V template (`--frames --fps --dilation --seed ...`). +- `tools/ltx25/mint_ltx25.py` - the plain LTX-2.5 graph minter the ladder used. +- `tools/ltx25/ltx25_oracle_window.py` - reads a saved H3 oracle profile and + returns the legal LTX window over its hot span. +- `tools/ltx25/splice_windows.py` - joins window renders, checking alignment. +- `tools/ltx25/ui2api.py` - the UI -> API converter the minters depend on. + +Model files are the stock Comfy-Org LTX-2.5 set (22B transformer, its VAE and +audio VAE, the x2 latent upsampler) plus the MiniMax-H3 set for the H3 arms. diff --git a/ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/FASTER.md b/ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/FASTER.md new file mode 100644 index 0000000000000000000000000000000000000000..254e41e15fe59eaae16c04f158208e5bcc2230f2 --- /dev/null +++ b/ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/FASTER.md @@ -0,0 +1,49 @@ +# FASTER.md, or: how to make it less awesome but still better than nothing + +The Motion Lab defaults are tuned for quality. Every dial below trades some of +that quality for wall-clock time, in descending order of how much time it buys. +Numbers come from measured runs on the example scenes; your content will move +them, the ordering should hold. The plan report prices most of these before you +spend a second of GPU: queue the windowed graph with `window: 0`, read the +report, then decide. + +## Where the time actually goes + +A de-rope render is pass 1 (generate) plus pass 2 (regenerate the dilated +timeline at higher effective resolution). Pass 2 dominates, and its cost is +roughly quadratic in token count: tokens = frames x pixels. So the dials that +remove frames or pixels beat the dials that make steps cheaper. + +## The dials, best value first + +| dial | where | default | cheaper setting | what you give up | +|---|---|---|---|---| +| `dilation` / `d_max` | H3 Time Smear / H3 Jerk Oracle | 4 | 3 or 2 | the slow-motion budget on bursts; 2 still beats no de-rope by a wide margin | +| `q` | H3 Jerk Oracle | 0.75 | 0.85 | fewer frames count as bursts, so borderline motion stays baseline | +| `expand_to_end` | H3 Time Smear | on in some graphs | off | the span after the last burst stays baseline; fine when the tail is calm | +| `inject` | H3 Inject Schedule | 0.48 | keep 0.48 | it is already the cheap setting: only the steps below the inject point run. 0.7 is the deeper, slower variant | +| pass 2 resolution | the second ResolutionSelector | 1.5 MP | 1.0 MP | the upscale half of upscale-de-rope; tokens scale with pixels | +| `coverage` | H3 Window Plan | full clip | burst only | on NON-upscale graphs only: calm spans keep their baseline render. On upscale graphs leave it on full clip or calm spans stay low-res | +| `kv_store` | H3 Streamed Blocks | kvi8r | kvi8s | needs the sageattention package; measured 219 vs 318 s/step at long context, judged side by side as a keeper | +| `handle_frames` | H3 Window Plan | 12 | 8 | less duplicated context at window seams; the edge pins carry more of the tracking load | +| `steps` (pass 1) | BasicScheduler | 12 (fast flow) | 12 | going below 12 shows; save elsewhere first | + +## What not to touch + +- The window edge pins (`MiniMax H3 Add Guide` at the first and last frame). + They cost nothing measurable and they are what holds the regenerated windows + on the baseline's motion and look. +- The audio seed (`H3 Audio Smear` into `H3 V2V Init`). Also near-free, and + pass 2's foley tracks the original performance because of it. +- `max_dilated_frames` does not buy total time. Smaller windows lower the PEAK + cost so a smaller card can run at all; the total goes slightly up from + duplicated handles. + +## A worked example + +The rolling-window example scene (107 frames, 4.5 s) plans 243 dilated frames +at the defaults: 2.27x the frames and 4.0x the time per step of a plain pass. +Dropping `d_max` to 3 and `q` to 0.85 with `expand_to_end` off re-plans the +same clip in the low 100s of dilated frames; the burst keeps its slow-motion +budget and the calm frames stop paying for it. Queue with `window: 0` and the +report will show you the exact count for your clip before you commit. diff --git a/ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/HARDWARE.md b/ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/HARDWARE.md new file mode 100644 index 0000000000000000000000000000000000000000..7f9391c85d9159b0b2427d65be37b2d5a17c9242 --- /dev/null +++ b/ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/HARDWARE.md @@ -0,0 +1,102 @@ +# Hardware vs settings + +Which graph and which dials for the machine you have. Two numbers matter +and they are not the same number: **VRAM** decides whether the dilated +pass fits, **system RAM** decides whether the whole pipeline fits, because +the decoded frames of pass 1, the smeared frames and the recovered frames +all live on the host as float images. People with a 24 GB card and 32 GB +of RAM hit the RAM wall first. + +Everything here was measured on one box (RTX PRO 6000 Blackwell 96 GB, +91 GB RAM) with the smaller cards simulated by fencing VRAM and RAM to a +hard budget, so a "16 GB" row means a real 16 GiB ceiling, desktop +included. Cells marked *extrapolated* come from the fitted line in +[`LOWVRAM.md`](LOWVRAM.md#how-far-you-can-go-extrapolated-from-the-lines-above) +and have not been rendered. If you run one of those, your seconds per step +is the most useful thing you can send back. + +## Pick a row + +| VRAM | RAM | start from | checkpoint | what to expect | +|---|---|---|---|---| +| 96 GB | 64 GB+ | [`examples/motion_pipeline_ref2va_audioinit.json`](examples/motion_pipeline_ref2va_audioinit.json) | int8 | 192 frames at 1 MP in ~12 min; a 702-frame de-rope at 1376x768 renders with everything resident | +| 32 GB | 64 GB | the same, or [`motion_pipeline_lowvram.json`](examples/motion_pipeline_lowvram.json) past ~10 s | int8 or W4A8 | the 702-frame de-rope at 25 GiB peak, 318 s/step, same speed as the 96 GB card (the step is attention-bound at that length) | +| 24 GB | 32 GB | [`motion_pipeline_lowvram.json`](examples/motion_pipeline_lowvram.json) | W4A8 | 702 frames at 23.5 GiB peak, 25.8 GB RSS; 906 frames renders at 515 s/step with RAM at the edge (29.8 GB) | +| 16 GB | 32 GB | [`motion_pipeline_lowvram.json`](examples/motion_pipeline_lowvram.json) | W4A8 + NVFP4 text encoder | 702 frames at 15.5 GiB peak, 27.4 GB RSS, 316 s/step; 906 frames does not fit | +| 15 GiB (a 16 GB card with its desktop up) | 48 GB | the same with `kv_store` = `kvi8s` | W4A8 | the exact K/V store runs out of memory at the second forward; `kvi8r` renders (+9.5 GiB, 374 s/step), `kvi8s` renders (219 s/step), `kvi8s` + `trim_forward` renders with zero allocator trims | +| 12 GB | any | not measured | | the line says ~150k packed tokens, roughly a 5 s clip de-roped at 1 MP. [`motion_pipeline_rolling_window_lowvram.json`](examples/motion_pipeline_rolling_window_lowvram.json) makes peak memory follow the window, not the clip, and is the graph to try; reports wanted | + +The ComfyUI flags the small-card rows were measured with: dynamic VRAM on +(the default since 0.33), `--fast-disk`, and nothing else. `--reserve-vram` +is a global hammer and was not needed on any row. + +## How long a clip fits + +Packed tokens is the unit the card cares about, not seconds. A frame at +1376x768 is about 310 tokens after dilation, and a de-rope at `d_max` 4 +on a bursty clip roughly doubles to triples the frame count, so the +dilated pass is what you are sizing for, not the clip you typed. + +| VRAM | max packed tokens | dilated frames at 1376x768, one pass | RAM at that length, single pass / full pipeline | +|---|---|---|---| +| 16 GB | ~230k | ~740 (measured: 702 renders, 906 does not) | ~28 / ~40 GB | +| 24 GB | ~380k | ~1230 (measured: 906 renders) | ~33 / ~45 GB | +| 32 GB | ~530k | ~1720 *extrapolated* | ~39 / ~51 GB *extrapolated* | + +Beyond the row you are on, the answers in order of cheapness: lower +`d_max` (3 instead of 4 is a third fewer dilated frames), raise `q` (0.85 +dilates only the hottest spans), drop the resolution of pass 1 and let +[`motion_pipeline_upscale_derope.json`](examples/motion_pipeline_upscale_derope.json) +do the de-rope at the size you want, then the rolling window. + +## Seconds per step + +The only per-step number we can give you is ours, and it scales +superlinearly with tokens (exponent ~1.7), so double the frames costs +more than double the time: + +| clip | card | s/step | +|---|---|---| +| 5 s at 1024x1024, plain pipeline | RTX PRO 6000 | ~11.5 | +| 702 dilated frames at 1376x768 (~217k tokens), pass 2 | RTX PRO 6000, or a fenced 16 to 32 GB budget of it | 311 to 318 | + +A 5090 user reported the VAE encode of 120 frames at ~1 MP at 20.5 s +(fp16) and 0.41 s with the TAE encoder; our own encoder line is 0.35 s per +dilated frame at 1.2 MP, flat 5 GiB, and the int8 VAE is no faster at +encoding (it only halves the weights). The encode is the stage that hurts +most on a small card, which is why the TAE matters: it needs a ComfyUI +newer than 2026-08-17 (core PR #15695). + +## Quality tiers on the same hardware + +Every row above also has a time dial that is not hardware at all: + +| want | pass 1 | pass 2 | cost vs one baseline | +|---|---|---|---| +| scout a prompt | 0.2 MP, 12 steps | turbo, 0.4 MP | ~1x, 95 s on our card | +| the normal final | 12 steps, base model | turbo, 6-step `beta`, inject 0.70 | ~1.3x | +| the slow final | 25 steps | base model, inject 0.70 | ~3.5x | + +The middle row is the August 19 recipe and it wants the whole recipe +(`linear_quadratic` + `gradient_estimation` on pass 1, `beta` on pass 2, +seeded audio): the turbo LoRA dropped into the 25-step graph on its own +renders jerky. [`examples/README.md`](examples/README.md) has the two +recipes side by side. + +## System RAM, specifically + +Measured on the 702-frame de-rope: 25.8 to 27.4 GB RSS on the small-card +rows, with the text encoder's CPU mirror the avoidable part. What helps, +in order: `H3 Evict Text Encoder` after each prompt encode (1 to 2.5 GiB +of VRAM peak back on a 16 GB card, and the mirror goes with it), keeping +pass 1 at the resolution you need and no higher, and not running two +ComfyUI instances that each hold a copy of the weights on the host. A +`--gpu-only` instance removes the host mirror entirely but makes unload a +no-op, so it only suits a card that holds everything. + +## Send numbers back + +An issue with your card, RAM, ComfyUI version, the graph, the packed token +count from the `H3 Jerk Oracle` cost readout, and your seconds per step +fills in a row of this page for everyone after you. Failures on content +unlike ours are worth more than successes on content like ours. diff --git a/ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/LICENSE b/ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..f70b88953360374a66e36316c2221509255b1958 --- /dev/null +++ b/ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/LICENSE @@ -0,0 +1,679 @@ +ComfyUI-MAINodes +Copyright (C) 2026 MATLOWAI + +This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. See below for the full text. + + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/LOWVRAM.md b/ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/LOWVRAM.md new file mode 100644 index 0000000000000000000000000000000000000000..5e2f68adf2a37b7f211d77b72143bb4576d18c8d --- /dev/null +++ b/ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/LOWVRAM.md @@ -0,0 +1,323 @@ +# Low VRAM, low RAM: the de-rope on a 16 GB card + +Status 2026-08-18: alpha. Measured on one machine fenced down to a 16 GB +card / 32 GB box (how, and how the fence was read, at the bottom); not yet +run on a physically different 16 GB card, which is the next thing. + +**Get started** (16 GB card, 32 GB machine; measured, alpha): + +1. Start ComfyUI **without** `--gpu-only` and **with** + `--fast-disk --fp16-intermediates --disable-pinned-memory` (and + `--cache-none` if RAM is tight; it re-runs every node on each queue). + What each does, measured on the 702-frame de-rope (RSS peak, same VRAM and + speed in every case): fp32 IMAGEs and a pinned DiT = 41.9 GB; `--fp16-intermediates` + halves every held IMAGE = 31.8; `--disable-pinned-memory` drops the DiT's + ~10 GB pinned staging copy = 21.6; `--cache-none` frees node outputs after + their consumers = 24.2 alone, **14.6 GB with all four**. `--fast-disk` reads + the weights from the NVMe page cache instead of RAM copies. Speed did not + move (369-374 s/step throughout). +2. Load `examples/motion_pipeline_lowvram.json` (API twin alongside), point + the LoadImage at your reference, set the prompt and canvas. +3. Queue. The 124-frame reference clip takes about 7 minutes end to end on + the fenced 15 GiB card (RSS 25 GB). + +If `H3 Streamed Blocks` is not in the node search (category `MAINodes/VRAM +Lab`, display name "H3 Streamed Blocks (exact low-VRAM, alpha)"), look at +the ComfyUI console for one line at startup: `[MAINodes] vram_lab not +loaded: ...`. The module needs a recent ComfyUI (developed on 0.33.0; it +imports `comfy.ldm.minimax.model` and comfy_kitchen's native rope op via +`comfy.quant_ops.ck`) and PyTorch flash attention; the pack loads the rest +of its nodes without it and prints why. Paste that line in an issue. + +**What the graph does to make a small card happy:** + +- the DiT at 4-bit weights / 8-bit activations (`minimax_h3_ref2va_pruned_w4a8_mixed`, 11 GB), the text encoder in NVFP4, the video VAE as int8_convrot (2.2 GiB less than fp16, decode 1.5x faster, 60 dB PSNR against it); +- `H3 Streamed Blocks` runs every DiT block in 16k-token chunks so the whole-sequence QKV and SwiGLU tensors (8.6 and 15.4 GiB at 217k tokens) never exist, and streams the output head; same math as stock (bit-equal on int8 / W4A8 with the exact K/V store); +- **`kv_store` = kvi8r**: the K/V of the whole sequence held as rotated int8, forward peak +9.5 GiB at 217k tokens instead of +11.9 (with `trim_forward`, on by default, another 2.3 GiB comes off); a sibling take of the exact result that passed the operator's eyes on the de-rope ("perfect for both"); flip it to `bf16 (exact)` for the bit-equal path; +- `H3 Evict Text Encoder` after each prompt encode, `H3 Free Cache` before the pass-2 decode: the 15 GB TE and the allocator pool leave the card before the VAE needs it; +- the turbo LoRA with a 12-step base pass and a 6-step / inject 0.7 de-rope pass, so the long pass is a handful of forwards. + +Everything below is the why and the numbers. + +## The workflow that ships: `examples/motion_pipeline_lowvram.json` + +On a Blackwell card there is a free speed lever on top of all of this: swap +the example's W4A8 UNET for the NVFP4 build +([MATLOWAI/minimax-h3-nvfp4](https://huggingface.co/MATLOWAI/minimax-h3-nvfp4)). +Same file size, measured 0.84 to 0.91x wall on 25-step graphs and 0.88x with +the turbo LoRA stacked, stock ComfyUI. A same-seed render is a sibling take; +judge it on your own content. Non-Blackwell cards should not use it. + +Two things the example already includes that are easy to miss: the AUDIO INIT +(`H3 V2V Init` takes the source performance's audio latent at strength 0.5, so +pass 2 follows the original delivery) and the smear-aware audio recover. For +clips whose dilated pass does not fit your card in one piece, the same stack is +wired into the windowed graph: +[`examples/motion_pipeline_rolling_window_lowvram.json`](examples/motion_pipeline_rolling_window_lowvram.json) +(API twin alongside; plan report first, then queue per window; inject 0.48). Each +window pins its first and last frame to the baseline via `MiniMax H3 Add Guide`, +which holds the regenerated windows on the baseline's motion and look so the +splice seams carry no state jumps; the pin frames come straight from +`H3 Window Plan`'s first/last frame outputs. + +One graph, the whole motion pipeline for a small card, with the rotated int8 +K/V store on. What is in it and why, in the order it runs (2026-08-18): + +| node | setting | what it buys | +|---|---|---| +| `UNETLoader` | `minimax_h3_ref2va_pruned_w4a8_mixed` (11 GB) | the DiT at 4-bit weights / 8-bit activations, exact under chunking (int32 accumulate) | +| `CLIPLoader` | `qwen3vl_32b_minimax_h3_nvfp4_awq` | the text encoder in NVFP4 (~15 GB file) | +| `VAELoader` (video) | `minimax_h3_video_vae_int8_convrot` | 2.2 GiB less on the card than fp16, decode 1.5x faster, 60 dB PSNR against the fp16 decoder on the same latent | +| `VAELoader` (audio) | `minimax_h3_audio_vae_fp32` | unchanged, 0.6 GB | +| `LoraLoaderModelOnly` | lightx2v turbo 4-step v1.0 768p, strength 1.0 | pass 1 at 12 steps (`linear_quadratic`), pass 2 on a 6-step `beta` schedule with `inject 0.7` (the "faithful detail" preset), so the long de-rope pass costs a handful of forwards | +| **`H3 Streamed Blocks`** | q/kv/mlp chunks 16384, `min_tokens` 32768, `final_layer_chunk` 16384, `final_layer_gemm` exact, **`kv_store` = kvi8r** | every DiT block in token chunks (never the whole-sequence QKV or SwiGLU), the output head streamed, and the K/V of the whole sequence held as rotated int8: forward peak +9.5 GiB at 217k tokens instead of +11.9 (exact store) or +21 (stock). Bit-equal to stock with `kv_store` = bf16; with kvi8r a sibling take that the operator judged "perfect for both" on the de-rope side by side | +| `H3 Evict Text Encoder` (x2) | after each prompt encode | the 15 GB TE leaves the card as soon as its conditioning exists (1 to 2.5 GiB of peak on a 16 GB card, ~3 s per new prompt to bring back) | +| `H3 Jerk Oracle`, `H3 Time Smear`, `H3 Audio Smear`, `H3 V2V Init` | `d_max 4`, dilation 4, audio 0.5 | the de-rope itself (see README) | +| `H3 Free Cache` | between the pass-2 sampler and its decodes | returns the allocator pool before the VAE runs (17 GiB on the long pass under `--gpu-only`; the small-card win is that decode never competes with a stale pool) | +| `H3 Exact Recover`, `H3 Audio Recover` | | back to real time, frame-exact | + +Measured as it ships (kvi8r + int8 VAE) at the 15.0 GiB fence / 48 GB +cgroup: the 124-frame reference clip end to end in **6:56**, VRAM 15.4 (the +fence, filled during the TE load), torch reserved max 6.2 GiB, RSS 25.2 GB, +zero allocator trims; pass 1 14.2 s/step, the de-rope pass 56 s/step. (With +the exact store and the fp16 VAE at the earlier 15.4 fence: 6:14, RSS 24.8.) +On the 702-frame de-rope, a bigger graph than this example, the exact store +no longer fits at 15.0 GiB while kvi8r (374 s/step) and kvi8s (219) render. + +The KJNodes sage-attention patches and FFN chunker from the parent graph +are not in it: sage attention is an approximation and the exactness gates +here were run on PyTorch's flash attention. +3. Set your prompt, reference image and canvas as usual. + +## What to expect + +**VRAM.** The activation peak inside a forward is card-independent: +`0.3 GiB + ~53 KB per packed token` (K/V buffers 28.7 KB/token, the residual +10.8, chunk transients and two tensors ComfyUI's forward keeps alive). +At 702 frames / 217k tokens that is +11.9 GiB. Dynamic VRAM fills whatever is +left with resident weights, so the process peak reads close to the card size +on every card; what decides whether a length fits is `weights it must keep + +activations + ~1 GB context`. Measured: 702 frames fits a 16 GB card, 906 does +not (275k tokens: +14.9 GiB of activations plus the minimum resident weights). +Frames here are 1376x768; other canvases scale by tokens +(`latent_frames x (W/32) x (H/32)`). + +**RAM. This is the tight budget, not VRAM.** With `--fast-disk`, process RSS +was 27.4 GB on the 16 GB card and 25.8 GB on the 24 GB card for a single +702-frame pass, 36 to 40 GB for the full de-rope pipeline (it holds the pass-1 +decodes, the smear IMAGE, the heat map: a 702-frame fp32 IMAGE is 8.9 GB), and +59 GB without `--fast-disk`. Add your own headroom: an idle Ubuntu desktop is +~2 GB, an idle Windows 11 desktop 4 to 8 GB, ComfyUI itself 3 to 5 GB before +any model. So, measured: a single 702-frame pass and the 124-frame example +graph fit a 16 GB card + 32 GB RAM (lean Linux; already paging on Windows); +**the full 702-frame de-rope pipeline does not fit 32 GB** (it was OOM-killed at +the smear under a 32 GB fence, 2026-08-18 19:00) and needs ~48 GB today, 64 GB +to be comfortable. Holding intermediates as fp16/uint8 by consumer type is +the next change and should bring the full pipeline back under 32 GB. Under our 64 GB fence +the kernel reclaimed page cache before killing anything; a Windows box would +pagefile instead, which is slower but alive. + +**Time.** 316 to 318 s per pass-2 step at 217k tokens on the fenced 16, 24 and +32 GB cards versus 311 resident on 96 GB. On the 90-frame clip the 16 GB card +did 8.2 s/step. The text encoder costs 3 to 4.5 s per new prompt from a warm +page cache (a cold read of the 15 GB file is longer), and 1 to 2.5 GiB of +VRAM peak on a 16 GB card, which the evict node removes. + +**The text encoder on tiny cards**, measured on the fenced 16 GB card, 90 frames: + +| arm | wall | encode | VRAM peak | RSS | +|---|---|---|---|---| +| stock CLIPLoader | 221 s | 3.0 s | 15.7 | 14.3 | +| second prompt in the same process | 218 s | 1.7 s | 16.6 | 15.5 | +| `H3 Evict Text Encoder` after the encode | 221 s | 3.1 s | 13.9 | 14.7 | +| `CLIPLoader device=cpu` | 272 s | 55 s | 14.0 | 26.9 | +| conditioning bank hit (encoder never runs) | 218 s | none | 14.7 | 12.4 | + +Nothing thrashed. Evict is the default in the example graph because a normal +run types a new prompt; `H3 Conditioning Bank` is for repeated prompts (seed +hunts, windows, extension chains) and needs the sampler's latent to come from +somewhere other than the encode node (`EmptyMiniMaxH3LatentAV` for T2VA, the +latent bank for a banked pass 1), or the encode node runs anyway for its +latent output. + +## The numbers + +The de-rope pass at `d_max 4` on an 8 to 12 second clip is ~200k packed tokens. +The stock H3 block builds its fused QKV and SwiGLU tensors for the whole +sequence at once, 8.6 and 15.4 GiB at that length, and that is what OOMs a +24 GB card, and at 1376x768 a 96 GB one. `H3 Streamed Blocks` runs every DiT +block in token chunks with the same math. Together with two things ComfyUI +already ships (dynamic VRAM, `--fast-disk`) it changes the small-card story +from "OOM" to "same speed": + +| card | machine | 294 f -> 702 f de-rope at 1376x768 (~217k tokens) | s/step (pass 2) | +|---|---|---|---| +| 96 GB, everything resident (`--gpu-only`) | 91 GB | renders | 311 | +| 32 GB (fenced), normal mode, `--fast-disk` | 64 GB (cgroup) | renders, 25 GiB VRAM peak | 318 | +| 24 GB (fenced) | 32 GB (cgroup) | renders, 23.5 GiB VRAM peak, 25.8 GB RSS | 318 | +| **16 GB (fenced)** | **32 GB (cgroup)** | **renders, 15.5 GiB VRAM peak, 27.4 GB RSS** | **316** | +| **15.0 GiB fence (a 5070 Ti with its desktop up)** | 48 GB (cgroup) | exact store: **out of memory** at the second forward (+12.1 GiB needed above the resident weights, 1990 allocator trims first); **kvi8r: renders** (+9.5 GiB, 22:33); **kvi8s: renders** (+9.5 GiB, 14:50); **kvi8s + `trim_forward`: renders with zero allocator trims (+7.2 GiB, 14:51)** | exact - / kvi8r 374 / kvi8s 219 | +| 16 GB (fenced) | 32 or 64 GB | 906 f (~275k tokens): out of memory | | +| 24 GB (fenced) | 32 GB | 906 f: renders, RSS 29.8 GB (RAM at the edge) | 515 | + +Same seed, the streamed result is bit-equal to the stock result on the int8 +and W4A8 checkpoints (video and audio latents compared tensor by tensor). It +is not a quality dial. It is also not slower: at these lengths the step is +attention-bound and the weight traffic hides under it (see "Why no speed +penalty"). + +## How far you can go (extrapolated from the lines above) + +The activation line predicted the 906-frame point on the 24 GB card before it +was measured (14.9 GiB both ways), so the table below is the line, not a +guess; treat it as +-1 frame-block. "Max tokens" assumes dynamic VRAM keeps +the minimum of resident weights (2 to 3 GB measured) and ~1 GB of context. + +| card | max packed tokens | frames at 1376x768, single de-rope pass | RAM at that length, single pass / full pipeline | +|---|---|---|---| +| 16 GB | ~230k | ~740 (measured: 702 renders, 906 does not) | ~28 / ~40 GB | +| 24 GB | ~380k | ~1230 (measured: 906 renders at 515 s/step) | ~33 / ~45 GB | +| 32 GB | ~530k | ~1720 | ~39 / ~51 GB | + +RAM per frame is ~12 MB (one fp32 IMAGE at 1376x768) on top of a ~19 GB base +for a single pass with `--fast-disk`; the full pipeline holds two to three +more IMAGEs of the clip. Past ~1100 frames the step time (attention grows with +the square of the sequence: 316 s at 702 frames, 515 at 906, ~650 at 1110) +is the practical limit before memory is. Other canvases: convert to tokens +with `latent_frames x (W/32) x (H/32)`, where `latent_frames = (frames-5)/17*5+2`. + +**The example graph itself, end to end on the fenced 16 GB card in a 32 GB +machine** (2026-08-18 18:25): rendered in 6:14 wall. Pass 1 (Ref2VA, 12 base +steps, 124 frames) 147 s, oracle + smear + audio smear + VAE encode 30 s, +pass 2 (6 turbo steps) 150 s, decode 21 s, recover and three saves. Process +VRAM peak 16.1 GiB (dynamic VRAM sized itself to the card), RSS peak 24.8 GB, +cgroup peak 30.9 GB (RSS plus the reclaimable page cache of the weight files: +that is how little air a 32 GB box has even at 124 frames). The text encoder +held 13 GB of the card until `H3 Evict Text Encoder` freed it +(`device free 1.3 -> 14.6 GiB`). + +## Why no speed penalty + +At 217k tokens about 250 of the ~315 seconds per forward are attention, which +grows with the square of the sequence. Streaming the whole 11 to 12.5 GB DiT +once per forward is ~0.5 s over PCIe from RAM and ~2 s from an NVMe page +cache, and dynamic VRAM prefetches the next layers while the current ones +compute. Weight traffic is a fixed cost per forward; attention is quadratic; +the long clip hides the traffic completely, and on the short one prefetch +did the same (8.2 s/step on 16 GB versus ~9 resident on 96 GB). This box has +PCIe 5 x16 and a fast NVMe; a PCIe 4 desktop halves the bandwidth, which is +still nothing against a 300 s step. A machine whose RAM cannot hold the +weight file's page cache and whose SSD is slow could show it on short clips. + +## The K/V store options (approximation tier, default off) + +At 217k tokens the exact block's forward peak is +11.9 GiB above the resident +weights, and 5.8 GiB of that is the K/V of the whole sequence held in bf16 +while the query chunks attend against it. `H3 Streamed Blocks` has a +`kv_store` option with two ways of halving those bytes. Neither is bit-equal +to stock: a same-seed render is a sibling take. The node's default is the +exact store; the low-VRAM example graph ships with kvi8r on (operator's +call); kvi8s has now been rendered and seen ("looks perfect", 219 s/step +against kvi8r's 374) and is the faster option for anyone with the +`sageattention` package installed; the example keeps kvi8r because it needs +no extra package. + +| `kv_store` | what it is | forward peak at 217k tokens | s/step (pass 2, 702 f de-rope) | quality so far | +|---|---|---|---|---| +| `bf16 (exact)` | stock math, chunked | +11.9 GiB | 318 | bit-equal | +| `kvi8r: rotated int8 K/V` | K and V int8 with one fp16 scale per (token, head) row, in a fixed Hadamard-rotated basis of the head dim; the query chunk is rotated to match and the output un-rotated once, so a K/V block dequant is one int8->fp16 cast times a scale, no GEMM; attention in fp16 blockwise (`kv_block`, default 16384) with an online-softmax combine | **+9.5 GiB** (second cut, measured live 2026-08-18 evening; the first cut was +12.5) | **374** (first cut 400) | first cut: operator's eyes "almost perfect" on the de-rope side by side, "looks fine" on a 90 f T2VA; second cut: side by side rendered, verdict pending; sensor bank over seeds owed | +| `kvi8s: Sage int8/fp8 K/V, rotated` | the same bytes kept in SageAttention's kernel layout (int8 K with one scale per 64-token block after mean smoothing, fp8 e4m3 V per channel), Q and K Hadamard-rotated first, attended on int8/fp8 tensor cores straight from the store, no dequant; needs the `sageattention` package (2.x, sm120 works) | **+9.5 GiB** (measured live 2026-08-18 evening) | **219** (31% faster than the exact store, 42% faster than kvi8r) | one rung more approximate than kvi8r on a synthetic proxy (rel-rms 3.1e-2 vs 1.3e-2; the shipped `sageattn()` scores 5.5e-2 on the same inputs, so the rotation is worth 1.8x to Sage); operator's eyes on the de-rope side by side: "looks perfect" (one clip, one viewer; sensor bank over seeds owed) | + +Why the rotation: the fixed orthonormal Hadamard spreads the outlier channels +of K and V over all 128 dims before rounding, so a per-row int8 scale wastes +less range; scores are invariant (q.k = (qH).(kH)) and P.V comes back through +H^T once on the output. Why fp16 and not bf16 inside kvi8r: in the rotated +basis every value has the same magnitude and bf16's 8-bit mantissa alone costs +a 4.8e-3 rel-rms floor; fp16's 11 bits cost 1.7e-3 (measured on random data). + +## What is exact, and what is not + +- `H3 Streamed Blocks` on int8 and W4A8 checkpoints: bit-equal to stock. The + mechanism is that comfy_kitchen quantises activations per row and the int8 + GEMM accumulates in int32, which is associative, so chunking rows cannot + change the sum. NVFP4/FP8 would need one shared activation scale and are + untested; bf16 checkpoints are numerically equivalent (fp accumulation + order), not identical. +- Query chunking is exact only while every chunk keeps PyTorch's flash + kernel off its split-KV path (measured boundary `heads x ceil(L/64) >= + 0.8 x 2 x SMs`; a 259-token tail once made a different clip). The node sizes + chunks from the SM count with a 2.6x margin and has a `self_check` that + compares stock and streamed on the first block's real input. +- The output head has an exact mode (default) and a chunked-GEMM mode that + differs by ~1e-6 per step in fp32 and produced a different clip after 25 + steps. It is labelled and off. `kv_block` on the exact store is experimental + and as built does not lower memory; leave it at 0 (it is the block size for + the kvi8r store). +- `H3 Free Cache` and `H3 Evict Text Encoder` change no math. +- `trim_forward` (default on) runs a copy of the stock model forward that + releases the patch-embed buffers once the packed sequence is assembled + (stock holds them for the whole forward: 2.3 GiB at 217k tokens, measured + live). Same math, bit-equal on the patcher gate; it checks the installed + ComfyUI's forward against the copy by source hash and switches itself off + with a log line if ComfyUI has changed. With kvi8s it takes the forward + peak to +7.2 GiB (the streamed output head is now the peak, not attention). +- The int8_convrot video VAE is an approximation by construction (60 dB PSNR + against the fp16 decoder on the same latent, encoder identical); the fp16 + VAE is what the exactness gates were run with. + +## What is next (the roadmap, in the order it will be tested) + +1. **Host RAM was the binding limit on the small machine; four flags moved it.** + Every held IMAGE is 8.9 GB per 702 frames at 1376x768 in fp32, ComfyUI pins + a ~10 GB staging copy of the DiT, and the execution cache holds every + output until the prompt ends: 41.9 GB. With `--fp16-intermediates + --disable-pinned-memory --cache-none` (all measured one at a time and + together) the same pipeline peaks at 14.6 GB. Note the fp16 IMAGE is + normalised in fp16 before the encoder, so the pass-2 result is a sibling + take of the fp32 run (28 dB between them, judged equal by eye). What is + left for code: streaming the smear straight into the encoder (never + holding the dilated IMAGE), uint8 for view-only outputs, and an fp32 + normalise on the encode input if anyone wants the fp32 sibling back. VAE + activations themselves are not the problem (0.6 GiB decode / 2.2 GiB + encode transient at the 256 px tiles). +2. **kvi8s live**, then the sensor bank over seeds for both stores; a per-32-value + scale variant of kvi8r (finer than per row); fp8 K/V if a kernel takes it + without dequant; int4/nvfp4 K/V behind the same gate. +3. **The weight side**: where the streamed block forces extra weight decode + per token chunk (W4A8's int4->int8 decode is repeated per chunk: measured + +25% wall at 29k tokens, +6% at 217k); decode once per block and reuse, + larger chunks where the flash split-KV rule allows, kitchen's fused paths + (SwiGLU fold, `convrot_w4a4` for the MLP). +4. **A real 16 GB card**, someone else's, end to end on the example graph. +5. Later, after the static rungs: dynamic precision routing (per block, per + step, FP4 vs FP8 by measured reconstruction error; the first experiment is + a heatmap on real activations, no kernels), and the ViT VAE decoder's own + low-bit rungs (already on int8 tensor cores in the int8_convrot file; the + remaining case is speed, ~40 s per 702 f decode). + +## The environment this was measured in + +Everything below was measured on one +machine, fenced down to look like small ones (real renders on the real GPU with +the VRAM held by a balloon and the RAM capped by a cgroup). **How the fence +was read:** the first day's "16 GB" rows ran with 15.4 GiB device-free as +`torch.cuda.mem_get_info` sees it (a headless 5070 Ti reports 15.92 GiB total +and about 15.5 free); the evening's kvi8r run used a stricter 15.0 GiB fence, +which is a 5070 Ti with its desktop attached. Dynamic VRAM fills whatever the +card has, so process peaks always read as the fence; the numbers that carry a +memory claim are the in-process forward peaks from `H3 Memory Probe`. Nothing +has been run on a physically different 16 GB card yet; that is the next thing, +and it is a dogfood ask, not a research question. + +One workstation: two RTX PRO 6000 Blackwell (96 GB, 188 SMs), EPYC 9554, +91 GB RAM, NVMe, Ubuntu, ComfyUI 0.33.0, PyTorch 2.14 nightly cu132, +comfy_kitchen native ops, PyTorch flash attention (comfy default), MiniMax-H3 +W4A8 and int8 checkpoints. Small cards were simulated by holding VRAM with a +balloon process so ComfyUI, dynamic VRAM and torch all saw a real 16 / 24 / +32 GB card; small machines by running ComfyUI in a cgroup with a hard memory +limit and swap off. Only ComfyUI ran during the measurements. Not measured: +Windows, other GPUs, ROCm, non-flash attention backends, real PCIe 4 boxes. + +The graph of the lines (VRAM activation line with per-card ceilings, RSS by +graph type) is `LOWVRAM_lines.html` next to this file; it grows as the sweep +does. diff --git a/ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/LOWVRAM_lines.html b/ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/LOWVRAM_lines.html new file mode 100644 index 0000000000000000000000000000000000000000..2055a36a45c0a9ea0c8126bf17de9ece7423687f --- /dev/null +++ b/ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/LOWVRAM_lines.html @@ -0,0 +1,53 @@ +H3 De-Rope Memory Lines + +

How long can a de-rope go on your card

+

Measured 2026-08-18 on one machine (RTX PRO 6000 Blackwell fenced to smaller cards with a VRAM balloon, RAM fenced with cgroups), MiniMax-H3 W4A8 DiT, MAINodes H3 Streamed Blocks (exact), ComfyUI dynamic VRAM, --fast-disk, PyTorch flash attention. Hover a point. Frames are at 1376x768; other canvases scale by tokens.

+VRAM: activations are card-independent; the card only sets the ceiling06121824303600k29490k702214k906276k1110339k1416432k1722525kframes at 1376x768 (packed tokens below)GiB16 GB24 GB32 GBtorch activation peak (in-forward, any card) +90 f / 28k tokens: torch peak +1.8 GiB (TE matrix A, 25 steps)torch activation peak (in-forward, any card) +90 f / 28k tokens: torch peak +1.8 GiB (TE matrix A, 25 steps)torch activation peak (in-forward, any card) +702 f / 214k tokens: torch peak +11.9 GiB (v014: bank, fast-disk, balloon 63)torch activation peak (in-forward, any card) +702 f / 214k tokens: torch peak +11.9 GiB (v012: planner+cap card)torch activation peak (in-forward, any card) +702 f / 214k tokens: torch peak +11.9 GiB (v011: normal mode, no fast-disk)torch activation peak (in-forward, any card) +702 f / 214k tokens: torch peak +11.9 GiB (line sweep, 2 steps)torch activation peak (in-forward, any card) +702 f / 214k tokens: torch peak +11.9 GiB (line sweep, 2 steps)torch activation peak (in-forward, any card) +702 f / 214k tokens: torch peak +11.9 GiB (line sweep, 2 steps)torch activation peak (in-forward, any card) +702 f / 214k tokens: torch peak +11.9 GiB (line sweep, 2 steps)torch activation peak (in-forward, any card) +906 f / 276k tokens: torch peak +14.9 GiB (line sweep, 2 steps)fit +fit: 0.34 + 53 KB/tokenfit +fit: 0.34 + 53 KB/tokenfit +fit: 0.34 + 53 KB/tokenfit +fit: 0.34 + 53 KB/tokenfit +fit: 0.34 + 53 KB/tokenfit +fit: 0.34 + 53 KB/tokenfit +fit: 0.34 + 53 KB/token16 GB card, process VRAM peak +90 f: process VRAM peak 15.7 GiB on a 16 GB card (TE matrix A, 25 steps)16 GB card, process VRAM peak +702 f: process VRAM peak 15.5 GiB on a 16 GB card (line sweep, 2 steps)16 GB card, process VRAM peak +702 f: process VRAM peak 15.5 GiB on a 16 GB card (line sweep, 2 steps)24 GB card, process VRAM peak +90 f: process VRAM peak 23.0 GiB on a 24 GB card (TE matrix A, 25 steps)24 GB card, process VRAM peak +702 f: process VRAM peak 23.5 GiB on a 24 GB card (line sweep, 2 steps)24 GB card, process VRAM peak +702 f: process VRAM peak 23.4 GiB on a 24 GB card (line sweep, 2 steps)24 GB card, process VRAM peak +906 f: process VRAM peak 23.4 GiB on a 24 GB card (line sweep, 2 steps)31 GB card, process VRAM peak +702 f: process VRAM peak 25.2 GiB on a 31 GB card (v014: bank, fast-disk, balloon 63)32 GB card, process VRAM peak +702 f: process VRAM peak 33.9 GiB on a 32 GB card (v012: planner+cap card)32 GB card, process VRAM peak +702 f: process VRAM peak 34.0 GiB on a 32 GB card (v011: normal mode, no fast-disk)torch activation peak (in-forward, any card)fit16 GB card, process VRAM peak24 GB card, process VRAM peak31 GB card, process VRAM peak32 GB card, process VRAM peakfit: torch peak = 0.34 GiB + 53 KB per packed token (K/V 28.7 + x 10.8 + residents/chunks). Points not rendered are listed in the table.Host RAM (process RSS peak): add your own OS + ComfyUI headroom011223344556600k29490k702214k906276k1110339k1416432k1722525kframes at 1376x768 (packed tokens below)GB32 GB64 GBsingle T2VA pass, --fast-disk +90 f: RSS 14.3 GB, single pass, 16 GB card, 64 GB machine (TE matrix A, 25 steps)single T2VA pass, --fast-disk +90 f: RSS 9.4 GB, single pass, 24 GB card, 64 GB machine (TE matrix A, 25 steps)single T2VA pass, --fast-disk +702 f: RSS 27.4 GB, single pass, 16 GB card, 32 GB machine (line sweep, 2 steps)single T2VA pass, --fast-disk +702 f: RSS 27.4 GB, single pass, 16 GB card, 64 GB machine (line sweep, 2 steps)single T2VA pass, --fast-disk +702 f: RSS 25.8 GB, single pass, 24 GB card, 32 GB machine (line sweep, 2 steps)single T2VA pass, --fast-disk +702 f: RSS 25.8 GB, single pass, 24 GB card, 64 GB machine (line sweep, 2 steps)single T2VA pass, --fast-disk +906 f: RSS 29.8 GB, single pass, 24 GB card, 32 GB machine (line sweep, 2 steps)full de-rope pipeline, --fast-disk +702 f: RSS 40.2 GB, de-rope pipeline, 31 GB card (v014: bank, fast-disk, balloon 63)full de-rope pipeline, --fast-disk +702 f: RSS 36.4 GB, de-rope pipeline, 32 GB card (v012: planner+cap card)de-rope pipeline, no --fast-disk +702 f: RSS 59.4 GB WITHOUT --fast-disk (v011: normal mode, no fast-disk)single T2VA pass, --fast-diskfull de-rope pipeline, --fast-diskde-rope pipeline, no --fast-diskRSS with --fast-disk = ComfyUI base + CPU-side intermediates (a 702-frame fp32 IMAGE is 8.9 GB); without it, add every model's CPU copy (~33 GB here). +

Points

framestokenscardmachinegraphtorch peakVRAM peakRSSnote
9028k16 GB64 GBsingle pass1.815.714.3TE matrix A, 25 steps
9028k24 GB64 GBsingle pass1.823.09.4TE matrix A, 25 steps
702214k16 GB32 GBsingle pass11.915.527.4line sweep, 2 steps
702214k16 GB64 GBsingle pass11.915.527.4line sweep, 2 steps
702214k24 GB32 GBsingle pass11.923.525.8line sweep, 2 steps
702214k24 GB64 GBsingle pass11.923.425.8line sweep, 2 steps
702214k31 GB64 GBde-rope pipeline11.925.240.2v014: bank, fast-disk, balloon 63
702214k32 GB64 GBde-rope pipeline11.933.936.4v012: planner+cap card
702214k32 GB96 GBde-rope pipeline (no fast-disk)11.934.059.4v011: normal mode, no fast-disk
906276k16 GB32 GBsingle pass---OOM
906276k16 GB64 GBsingle pass---OOM
906276k24 GB32 GBsingle pass14.923.429.8line sweep, 2 steps
+

Reading it: VRAM needed = resident weights (dynamic VRAM shrinks these to a few GB when it must) + the blue line + ~1 GB context; a card fits while that stays under it. RAM needed = the RSS series for your graph type + your OS and ComfyUI headroom, which you know and we do not.

diff --git a/ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/README.md b/ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/README.md new file mode 100644 index 0000000000000000000000000000000000000000..7d72bf6ae7c6f2517856fcffcd371d62254b3695 --- /dev/null +++ b/ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/README.md @@ -0,0 +1,1119 @@ +# ComfyUI-MAINodes + +Custom nodes for MiniMax-H3. Two groups: **Motion Lab** (a test-time fix +for fast-motion smearing) and **Contact-Sheet diffusion** (five views of +one subject from one reference image). + +Like it? A star helps. Want to feed the GPU? [Sponsor the experiments](#support-mainodes). + +## Start here + +- **Which graph:** [`examples/README.md`](examples/README.md). Four + starting points, the essential node chain as a diagram, and what each + specialised graph adds to it. +- **Which settings for your card:** [`HARDWARE.md`](HARDWARE.md). VRAM and + system RAM rows, measured. +- **Which dial for which symptom:** [`TUNING.md`](TUNING.md). +- **What is still alpha:** [`ALPHA.md`](ALPHA.md). + +The short version: start from +[`examples/motion_pipeline_ref2va_audioinit.json`](examples/motion_pipeline_ref2va_audioinit.json), +keep pass 1 at 12 steps on the base model, let the turbo LoRA do pass 2, +and reach for `inject` (0.50 sharper, 0.70 safer) before any other dial. + +## What's new + +Cloned before 2026-08-19 and `git pull` errors? Run +`git fetch origin && git reset --hard origin/main`, or re-clone. + +**Repair, a per-block clock, and the chaining nodes** (2026-08-24, alpha). +Five additions, all opt-in and all alpha. `H3 Repair Plan` / `H3 Repair +Splice` re-render a few bad frames of a finished clip and hand back the same +clip with only those frames different ([below](#repairing-a-few-bad-frames)). +`H3 DyRoPE` gives the true-duration RoPE clock to SOME blocks or SOME steps +instead of all of them, which is what separates the timing correction from +the flash and jitter it used to cost +([below](#dyrope-who-gets-the-true-clock)). `H3 V2V Init` grew +`audio_prefix_ticks`, the audio twin of the video prefix freeze, so a +continuation can carry the previous segment's sound across the join +([below](#anchoring-audio-across-a-join-alpha)). `H3 Drift Control` and +`H3 Delta Color Carry` attack the two things that decay down a chain of +segments, clean-conditioning error and VAE round-trip colour +([below](#chained-segments-drift-and-colour-alpha)). And window mode, the +excerpt-shaped graph where only part of a long clip is retimed, finally has +a page: [docs/WINDOW_MODE.md](docs/WINDOW_MODE.md). + +**Long de-ropes on small cards** (2026-08-18, alpha). A de-rope pass at +d_max 4 on an 8 to 12 second clip is ~200k packed tokens, and the stock H3 +block materialises its fused QKV and SwiGLU tensors for the whole sequence +(8.6 and 15.4 GiB at that length), which is what OOMs 24 GB cards and, at +1376x768, a 96 GB one. `H3 Streamed Blocks` runs every DiT block in token +chunks with the same math (int8 and W4A8 activations quantise per row and +accumulate in int32, so the result is bit-equal to stock; measured on +same-seed renders, video and audio) and streams the output head the same +way. With ComfyUI's dynamic VRAM and `--fast-disk`, the same 702-frame pass +that OOMed a 96 GB card renders on a 16 GB card in a 32 GB machine at the +same seconds per step (316 vs 311), because the step is attention-bound at +that length and the weight traffic hides under it. Alongside it: `H3 Memory +Probe` (per-block, per-phase VRAM and RSS ledger with a hoverable timeline, +plus an optional allocator trace), `H3 Free Cache` (return the allocator +pool before VAE decode; 17 GiB back on the long pass), `H3 Evict Text +Encoder`. All opt-in, nothing changes unless the node is in the graph. The +memory numbers behind them are in the docstrings of `vram_lab.py`; the +small-card recipe, what to expect and the environment it was measured in are +in [LOWVRAM.md](LOWVRAM.md), with the example graph +`examples/motion_pipeline_lowvram.json`; the alpha status is in +[ALPHA.md](ALPHA.md#vram-lab). Evening additions: two opt-in K/V store +options in the same node (`kvi8r`, rotated int8 K/V, forward peak +9.5 GiB +instead of +11.9; `kvi8s`, the same bytes in SageAttention's layout attended +on int8/fp8 tensor cores with no dequant), both approximation tier with the +measurements and what is still owed in LOWVRAM.md, kvi8r on in the low-VRAM +example graph; the example graph moves to +the int8_convrot video VAE (2.2 GiB less, decode 1.5x faster, 60 dB PSNR +against fp16 on the same latent); and a fix for the `H3 Audio Smear` / +`H3 Audio Recover` istft crash on short stretched tails (user report). + +**Dialogue survives a de-rope now** (2026-08-17). A de-rope used to break +speech, and the way it broke was confusing: the body came back at the right +speed and the mouth did not, so held regions sounded rushed while the tail +sounded fine. The cause is that the picture gets an init and obeys it while +the audio starts from zeros, so pass 2 writes a fresh performance at natural +rate and moves the mouth to that. Recovery then compresses something that was +never slow. New node `H3 Audio Smear` stretches the baseline track onto the +same dilated clock so pass 2 renders a genuinely slowed take instead. See +[Dialogue through a de-rope](#dialogue-through-a-de-rope) for the three nodes +to add to a graph you already have. + +**The graph to start from** is +[`motion_pipeline_ref2va_audioinit.json`](examples/motion_pipeline_ref2va_audioinit.json): +full-reference mode with the audio init wired, 12 steps on the base model for +pass 1 and the turbo LoRA at 6 steps for the de-rope. On 192 frames at 1 MP +that is **12 minutes end to end**, against 36 for the same graph at 25 steps +both passes without turbo. The audio init itself is free in both currencies, +costing no measurable time and no measurable sharpness. + +## What is stable, and what is not + +**Stable:** the Motion Lab de-rope pipeline and Contact-Sheet diffusion, both +described below. Their dials have measured numbers behind them in +[TUNING.md](TUNING.md), and their example graphs run out of the box. + +**Not stable:** Concept Lab, the timeline surface, the motion adapter pilot, +the manual mask paths, and the audio init above, which works but has only +been heard on a narrow slice of material. [ALPHA.md](ALPHA.md) says which is +which and where each has and has not been tested. Alpha nodes carry +`(alpha)` in the ComfyUI menu and load behind a guarded loader, so a broken +one cannot take the pack down. + +## Motion Lab + +H3 smears bursty motion: backflips, fast sword arcs, whip-fast reversals. +The cause is structural. One latent token spans four pixel frames, and at +high motion speed those four frames need four distinct poses that a single +token can't hold. Re-denoising the affected region doesn't help, because +the missing poses were never generated in the first place. + +This pipeline works around that at inference time. It re-generates the +clip as a slowed-down version of itself, seeded from the original. Frames +where motion is too fast get held (repeated) so the model has more +temporal room, the result is generated video-to-video from that retimed +init at partial denoise, and the original frame rate is recovered +afterward by dropping the held frames. The oracle that decides where to +slow down reads the clip's own latent. No extra model, no training. + +![baseline vs inject 0.70 vs inject 0.50](assets/kitsune_threeway.gif) + +Baseline on the left smears the aerial spin into a blob; the two +regenerated settings render it clean and keep the choreography. New scene, +default knobs, no per-clip tuning +([view](https://matlowai.github.io/ComfyUI-MAINodes/#kitsune) / +[download](https://github.com/matlowai/ComfyUI-MAINodes/raw/main/assets/kitsune_threeway_sbs.mp4)). + +All demos play on one page: **https://matlowai.github.io/ComfyUI-MAINodes/** + +Demo clips: +- baseline vs regenerated, same seed, real time: left smears through the + backflip, right doesn't + ([view](https://matlowai.github.io/ComfyUI-MAINodes/#derope) / + [download](https://github.com/matlowai/ComfyUI-MAINodes/raw/main/assets/baseline_vs_regenerated_sbs.mp4)) +- uniform vs adaptive hold maps, the bridge trade-off described below + ([view](https://matlowai.github.io/ComfyUI-MAINodes/#adaptive) / + [download](https://github.com/matlowai/ComfyUI-MAINodes/raw/main/assets/uniform_vs_adaptive_sbs.mp4)) +- the oracle, watching: heat pools where motion runs too hot, and the + strip lights up as the burst arrives + ([view](https://matlowai.github.io/ComfyUI-MAINodes/#oracle) / + [download](https://github.com/matlowai/ComfyUI-MAINodes/raw/main/assets/oracle_map.mp4)) +- fast motion under a panning camera: parasol burst mid-pan + ([view](https://matlowai.github.io/ComfyUI-MAINodes/#panrun) / + [download](https://github.com/matlowai/ComfyUI-MAINodes/raw/main/assets/panrun_sbs.mp4)) +- nine tiers, one seed: every quality/speed rung with render times in the + header + ([view](https://matlowai.github.io/ComfyUI-MAINodes/#ladder) / + [download](https://github.com/matlowai/ComfyUI-MAINodes/raw/main/assets/preview_ladder_grid.mp4)) +- the featherweight stack on 24-32 GB cards, with a Ref2VA subject drop-in + ([view](https://matlowai.github.io/ComfyUI-MAINodes/#featherweight) / + [download](https://github.com/matlowai/ComfyUI-MAINodes/raw/main/assets/featherweight_ref_triptych.mp4)) + +| baseline vs regenerated | the oracle, watching | +|---|---| +| ![baseline vs regenerated](assets/derope_sbs.gif) | ![the oracle, watching](assets/oracle_map.gif) | + +Already good, and slightly better: uniform dilation, then the adaptive +map without and with `bridge`. Same seed all three. + +![uniform vs adaptive, without and with bridge](assets/uniform_vs_adaptive.gif) + +``` +(baseline video) -> VAEDecode frames (baseline latent) + | | + v v + H3TimeSmear <-- hold_map ------------- H3JerkOracle + | (integer holds) | + v | + VAEEncode -> H3V2VInit -> SamplerCustomAdvanced + ^ + H3InjectSchedule ---/ + | + VAEDecode -> H3ExactRecover -> original fps +``` + +Three ready-made graphs live in [`examples/`](examples/): +[`motion_pipeline.json`](examples/motion_pipeline.json) drags straight +onto the ComfyUI canvas; +[`motion_pipeline_api.json`](examples/motion_pipeline_api.json) is the +same graph in API format for scripted use; and +Three flows cover almost every job, and the examples keep one graph per job: +the full-quality pipeline (25-step pass 1, 25-step pass 2, no turbo), the fast +flow (12-step turbo pass 1, 6-step turbo pass 2, inject 0.48 or 0.7), and the +low-VRAM stack in [LOWVRAM.md](LOWVRAM.md). Inject 0.48 replaced 0.50 as the +shipped default: at 0.50 and above some scenes measurably loosen their hold on +the reference. Historical dial studies and superseded variants live in +[`examples/archive/`](examples/archive/), still runnable as committed. When the +defaults are too slow for your card or your patience, [FASTER.md](FASTER.md) +prices every speed dial from measured runs. + +[`motion_pipeline_turbo.json`](examples/archive/motion_pipeline_turbo.json) is the +same pipeline with the regeneration pass running on the LightX2V 4-step +turbo LoRA (Kijai's ComfyUI conversion, strength 0.8, er_sde with a beta +schedule, 3 of 4 steps after injection). Point the LoRA loader at +wherever you saved the conversion; community strength range is 0.65 to +0.8, and v0.1 of that LoRA is a preview, so judge results accordingly. + +How we actually use this after trying every combination: **turbo is for +getting your prompt right, the pipeline is for the keeper, and mixing +them is a waste of time.** Iterate prompts and seeds on plain turbo +generations to learn what you will get globally, then run the winner +through the base pipeline. Putting the turbo LoRA inside the +regeneration pass saves a few minutes on a clip you have already decided +deserves the full treatment, and it costs quality on exactly that clip; +we do not recommend it. The turbo-inside graphs remain for people with +different budgets. One wrinkle that did earn its keep: starting the +turbo PREVIEW on the base model for the first couple of steps before +handing off to turbo (H3 Expert Schedule with inject 1.0) may buy +preview fidelity cheaply; we are still testing it. A unified workflow +with a preview/final toggle (H3 Mode Switch, lazy: only the chosen path +executes) is the intended end state. + +A fourth graph, +[`examples/archive/motion_pipeline_probe_expert.json`](examples/archive/motion_pipeline_probe_expert.json), +is the fast path: instead of finishing the baseline it runs only the +first 6 steps (H3 Probe Schedule, configurable) and reads the oracle and +the init from the early x0 estimate, then regenerates with a base-model +head and a turbo tail (H3 Expert Schedule). Cheapest of the set; no +full-speed audio track to blend, and the saved preview is intentionally +rough. + +There is also [`examples/archive/motion_pipeline_i50.json`](examples/archive/motion_pipeline_i50.json), +the same finals graph with the inject 0.50 preset selected, for people who +prefer the sharper flavor without touching a dropdown. + +For 24 to 32 GB cards there is +[`examples/archive/motion_pipeline_featherweight.json`](examples/archive/motion_pipeline_featherweight.json): +the same finals graph pointed at the smallest community-published models +(w4a8 DiT, int8_convrot VAE, nvfp4 text encoder). Needs ComfyUI 0.31+. +Measured numbers and the honest caveats live in +[TUNING.md](TUNING.md#featherweight-stack-measured-comfyui-031). + +Everything from here through the editor and segment graphs is new +(2026-08-09) and marked **alpha**: the node interfaces may still move, +and the interactive widget is young. The classic pipeline nodes above +are untouched and differentially regression-tested against the +previous release (same inputs, identical outputs). + +And for the "the oracle is overzealous, I know exactly where the +problem is" crowd: +[`motion_pipeline_targeted.json`](examples/motion_pipeline_targeted.json) +(API twin alongside) puts a human in the loop. The oracle still +proposes, but its hold map passes through **H3 Manual Hold Map**, which +keeps holds only inside the time ranges you type (`36-60, 1.5s-2.4s:3`, +frames or seconds, optional per-range hold count; leave the oracle +unwired to author holds directly). Queue once and watch the saved +oraclemap video to see where the heat pools; type your ranges; queue +again. The node's report output prices the pass before you pay for it: +world length in, effective regeneration length out, with an optional +minutes estimate from your measured s/step. Since cost scales with the +held spans, targeting one burst in a long clip is also the biggest +speed lever this pack has. The drag-in graph additionally carries a +muted spatial branch: export a frame, paint a mask, load it, unmute, +and H3 Motion Composite returns your masked region to baseline timing +with a feathered seam (see below). + +The full editing experience is +[`motion_pipeline_editor.json`](examples/motion_pipeline_editor.json) +(API twin alongside): the **H3 Motion Editor** node puts a DAW-style +editor right on the canvas. Queue once to load the filmstrip, then +work on the node: drag bracket blocks on the timeline (multiple +blocks, snapped to the model's token grid, jerk profile drawn +underneath so you can see what the oracle sees), click a block and +step frame by frame painting the problem areas with brush and eraser +(onion skin included), set per-block dials for hold, feather size, +feather profile and direction, edge grow, and temporal fade, and +toggle `A` on hold, feather, or strength to draw an automation +envelope with draggable breakpoints, exactly like an automation lane +in a DAW. A block with no strokes regenerates its whole time span; +strokes narrow it to the painted region. Queue again and only the +regeneration side re-runs; the baseline stays cached. The node's +outputs are ordinary `hold_map` and MASK wires, the mask arriving +pre-feathered and envelope-scaled (`mask_is_soft` on the composite), +so everything downstream is the same pipeline. Agents skip the GUI +and write the same `editor_state` JSON directly; the contract is in +the node's docstring. + +And the compute payoff of targeting: +[`motion_pipeline_editor_segment.json`](examples/motion_pipeline_editor_segment.json) +(API twin alongside) adds **H3 Segment Crop** and **H3 Segment Splice** +around the editor. The regeneration chain runs only on the editor's +held window plus a few real-time handle frames, then the recovered +segment splices back into the baseline with video and sample-accurate +audio crossfades inside the handles. Cost scales with dilated frame +count, so a one-burst window in a longer clip regenerates severalfold +faster than the whole world; the crop node's report output states the +exact ratio for your selection. On FL2VA checkpoints, wire the crop's +first/last frame outputs into the regeneration conditioning to pin the +seam poses. + +Four shorter paths, each measured on one prompt and seed: + +[`examples/archive/motion_pipeline_split_lora.json`](examples/archive/motion_pipeline_split_lora.json) +splits pass 1 mid-trajectory. The bare model runs the early, high-sigma +steps -- where the motion is actually decided -- and a turbo LoRA takes +over for the low-sigma steps, off one schedule with no re-noising +between them (`SplitSigmas` + `DisableNoise`). Running a turbo LoRA +across the whole of pass 1 cost about 22% of mean subject motion and 30% +of the peak in our measurements, and the second pass never gave it back; +splitting recovered 99% of it, and still finished faster than a plain +12-step pass 1. + +[`motion_pipeline_upscale_derope.json`](examples/motion_pipeline_upscale_derope.json) +does the de-rope and a spatial upscale in the same second pass: pass 1 +renders at 0.4 MP, the smeared frames are resampled to the target size, +and the regeneration runs there. The second pass rebuilds detail rather +than interpolating it -- measured 89% of a native 1.5 MP render's +high-frequency detail for 83% of the wall time. Most of what the cheap +pass 1 saves, the larger second pass gives back: pass 1 drops from 179 s +to 31 s, and pass 2 rises from 305 s to 372 s. The cost is jerk +removal: a soft pass 1 gives the oracle blurrier evidence, so it cuts +less of it. + +[`motion_pipeline_rolling_window.json`](examples/motion_pipeline_rolling_window.json) +(alpha) is the upscale de-rope split into budgeted windows, for cards +that cannot hold the whole dilated pass at once. **H3 Window Plan** +divides the clip into as many windows as your `max_dilated_frames` +budget requires and emits one per queue item: queue once, read the plan +report (wired to a preview node; it prices every window and names each +cut cold or hot before anything runs), then set the queue batch count +to the window count and queue once more -- the `window` widget +increments itself per batch item, seed-widget style, so the whole set +renders from one click. **H3 Window Collect** banks each rendered window to disk +(`output/h3_windows`, so a crash or reboot costs one window, not the +run) and splices the full set into the baseline once the last one +lands. On our test clip the peak window was 62 latent tokens against +77 for the one-pass version, paid for as 1.47x the one-pass total in +generated frames at the budget that forced the split. `coverage` +defaults to `full clip` so calm spans get the same second-pass repaint +as the action; `held span` is cheaper but leaves everything outside the +held span at baseline resolution, which on this graph means visibly +soft the moment motion calms. + +**H3 Conditioning Bank** (alpha) keeps the text encoder out of the +window items. Wire it between the encode node and the guider: the first +item encodes and banks the conditioning to disk, and every later item +reads the tensors back. Its `conditioning` input is lazy, so on a bank +hit ComfyUI never executes the encode node or the CLIP loader behind +it, and the encoder (14.96 GB resident on the int8 ref2va stack, 21.2 +GB peak on a 16 GB-simulated card) is never loaded for that item. To be +exact about what it buys: requeueing the same graph with only the +`window` widget changed already hits ComfyUI's own node cache, so +nothing is re-encoded there. What loses that cache is queueing any +other workflow in between, restarting ComfyUI, or editing anything +upstream of the encode, and the bank survives all three. It is not +window-specific: a seed hunt and an extension chain on the same prompt +encode once between them too. + +**H3 Latent Bank** (alpha) is the same trick one stage later, and on +this graph it is worth more. The pass-1 baseline render is cached +exactly like the conditioning is, and lost exactly as easily, so an +interleaved workflow makes window item 2 re-render the whole baseline +before it starts its own window. Bank the pass-1 LATENT and every +consumer is served from it: the video decode, the audio decode, and H3 +Jerk Oracle, which reads the latent directly. Latents are the cheap +thing to keep: the AV latent of a 107-frame 480x832 clip is 4.8 MB, +against 513 MB for the same clip as float32 frames. The staleness +contract is stated plainly on the node: `bank_key` plus a hash of +`seed` and `fingerprint`, and nothing else is fingerprinted for you. + +Measured on a simulated 32 GB card (a large card fenced down with +`--reserve-vram`; int8 stack, 0.4 to 1.5 MP, 107 frames): the one-pass +de-rope peaked at 30.7 GB, touched the ceiling, and streamed the DiT +layer by layer (208 lowvram patches). Split into two windows the peaks +were 22.5 and 24.6 GB and the DiT stayed resident, so the two windows +together (440 s) matched the one-pass wall time (460 s) while +generating 1.4x the frames. The lower peak is what buys the extra work +back: on a card at the offload cliff, not streaming beats not +splitting. + +[`motion_pipeline_fast_iterate.json`](examples/motion_pipeline_fast_iterate.json) +is the same idea sized for iteration: 0.2 MP in, 0.4 MP out, about 95 +seconds end to end. Use it to find out whether the choreography lands +before paying for a final. + +[`motion_pipeline_ref2va_audioinit.json`](examples/motion_pipeline_ref2va_audioinit.json) +runs the pipeline in full-reference mode, with the six-section prompt +contract and a reference image (wired to ComfyUI's stock `example.png` +so it runs out of the box -- swap in your own). It also seeds pass 2's +AUDIO rows with the baseline performance, which is what keeps dialogue +intact through a de-rope: without a seed, pass 2 writes fresh speech at +natural rate and drags the mouth to match it, and recovery then +compresses those lips by the hold factor, so held regions come back +rushed while the unheld tail sounds fine. `H3 Audio Smear` stretches the +baseline track onto the dilated clock, `VAEEncodeAudio` encodes it, and +`H3 V2V Init`'s `audio_latent` seeds it at `follow the original +performance (0.5)`. + +**This is the balanced setting, and it is the one to start from.** Pass 1 +runs 12 steps on the base model, pass 2 runs the turbo LoRA at +`total_steps 6` with inject 0.50, so about three steps actually execute on +the de-rope. On 192 frames at 1 MP on an RTX PRO 6000 Blackwell that is +**12 minutes end to end**. The same graph without turbo, at 25 steps for +both passes, took 36 minutes on the Max-Q card, which runs roughly 13% +slower on sustained 1 MP work, so call it 32 minutes equivalent. Nearly +three times the wall time, and the turbo arm was the one that got the +playback verdict. + +**The audio init itself is free.** Pass 2 measured 6:06 with the seed +against about 7:20 without it on the same card, which is inside run to run +variation. It also costs nothing in picture quality: 91.8 against 91.3 on +laplacian variance, inside the noise floor of the video encoder itself. +And because the seed only touches pass 2, re-running a graph after wiring +it serves pass 1 from cache. + +It writes two finals so you can hear the difference the seed makes: +`_recovered` keeps the original performance (the safe route, and the one +we ship as the default), and `_seededfoley` takes pass 2's own foley +retimed to the world clock -- legitimate ONLY because the rows were +seeded. Alpha: measured on a handful of clips, all sword-fight material +with two speakers. Speech over music, a single speaker and hold factors +other than 4 are untested. + +[`motion_pipeline_ref2va.json`](examples/motion_pipeline_ref2va.json) +is the same graph WITHOUT the audio init, kept as the archived version. +Reach for it only if you want the older behaviour; on any clip with +dialogue, prefer the audioinit graph above. + +**There is a resolution floor.** Below roughly 0.4 MP the subject smears +regardless of configuration, and every quality judgement we took from a +448x448 render turned out to be worthless. The small-canvas paths are for +iteration, not finals. Separately, a distilled LoRA wants the size it was +trained at: ours was mush at 448x448 and clean at its native 768x768. + +**Do not run a turbo LoRA at its distilled step count in pass 2.** A +distilled LoRA's step budget is sized for a full denoise from noise; +pass 2 is a partial re-denoise from a v2v init, so those steps land far +too finely and the subject dissolves into a coarse mosaic. Running an +8-step LoRA for 8 steps of a 0.50 injection failed at both 0.2 and +1.0 MP and with either v1.0 file; 4 steps of the same schedule was +clean. Budget pass-2 steps against the fraction of the schedule you are +actually running, not against the LoRA's name. + +All of them generate or probe a baseline, read its oracle, regenerate, +and recover, in one queue item. The oracle's length and the regeneration +length are wired dynamically, so changing the clip duration needs no +other edits. Each node's info button documents its inputs. + +### Nodes + +| node | knob | default | notes | +|---|---|---|---| +| H3 Jerk Oracle | `q` | 0.75 | jerk quantile treated as "hot"; higher = tighter span, lower cost | +| | `d_max` | 4 | peak hold count; below 4, smearing starts returning in our tests | +| | `ramp` | on | smooth shoulders on the hold curve; hard steps caused visible stutter | +| | `bridge` | 8 | fill dips between peaks of the same burst (see below); 0 = off | +| | `preset` | balanced | balanced / max quality / economy; `custom` uses the knobs | +| H3 Time Smear | `dilation` | 4 | uniform hold count, used when no hold_map is wired | +| H3 Inject Schedule | `inject` | 0.70 | fraction of the denoise schedule that runs. Lower keeps more of the init (including its artifacts); higher lets the model drift from the source choreography. 0.5 to 0.8 is the useful range | +| | `preset` | 0.70 | 0.70 / 0.50 / 0.80; `custom` uses the knob | +| H3 V2V Init | `length` | 0 (auto) | wraps the encoded init as H3's joint AV latent; audio regenerates with the video | +| H3 Exact Recover | | | drops held frames per the hold map; recovery is frame selection, not resampling | +| H3 Audio Recover | `fps` | 24 | retimes the regenerated audio to the original clock with the same hold map, pitch preserved, so the recovered video keeps its own foley | +| | `reference_mix` | 1 | whose track survives: 1 = the pass-1 baseline audio intact (default; regenerated audio quality varies, especially off turbo passes), 0 = the regenerated foley (leaner, one performance). The two performances are different takes, so mid values blend them; the dial is happiest near its ends | +| H3 Jerk Heatmap | `alpha`, `strip_height` | 0.55, 96 | the oracle-watching overlay from the demo clip, as a node | +| H3 Probe Schedule | `probe_steps` | 6 | run only the head of the baseline; the early x0 feeds the oracle and the init. Raise it if the init loses choreography | +| H3 Expert Schedule | `base_head` | 2 | split the injected schedule: base-model head for structure, turbo tail for refinement (tail defaults to turbo's native 4 steps) | +| H3 Trajectory Bank | `every_n` | 1 | wraps a sampler and checkpoints the trajectory latent each step (~7 MB per step for a 5 s clip) | +| H3 Trajectory Load | `step` | 5 | resume a banked run from any step with its remaining schedule; swap the model, LoRA, or guider and continue without recomputing the head | + +#### Alpha nodes + +Added 2026-08-09 and after. These are the research surface: they +work and are documented, but their names, defaults and outputs may +change, and they have had far less playback mileage than the nodes +above. `TESTING_ALPHA.md` is the manual checklist; `ROADMAP.md` and +`RESEARCH_NOTES_ATOS.md` carry the open questions and what we +rejected. If you want the settled pipeline, everything above this +line is it. + +| node | knob | default | notes | +|---|---|---|---| +| H3 Motion Editor | timeline, brushes, lanes | | the GUI: time blocks with bracket handles, per-frame mask painting, per-block dials, automation envelopes for hold/feather/strength. Compiles to a hold map and a soft mask; state is plain JSON that agents can author without the GUI | +| H3 Segment Crop | `handle_frames` | 12 | cut the world to the held window plus context handles; the regen chain then pays only for the window. Report output states the speedup | +| H3 Segment Splice | `feather_frames` | 6 | reassemble after recovery: baseline outside, segment inside, video + audio crossfades inside the handles | +| H3 Window Plan (alpha) | `max_dilated_frames` | 209 | per-window budget in smeared frames, the number that sets cost and peak memory; read your card's ceiling off a run that survived | +| | `coverage` | full clip | `full clip` tiles windows over every frame so calm spans are repainted too (they cost 1 dilated frame each and cut cold); `held span` regenerates only where the hold map fires, cheaper, but passed-through frames keep baseline resolution on upscale graphs | +| | `window` | 0 | which window this queue item renders; 0, queue, then 1, queue. The report output is the interface: read it | +| H3 Window Collect (alpha) | `store_dir` | output/h3_windows | windows bank here between queue items and survive a reboot; avoid /tmp, it is a RAM disk on most Linux installs | +| | `run_name` | window_run | keys the banked set; change it whenever the plan changes | +| H3 Conditioning Bank (alpha) | `bank_key` | run | banks the encoded prompt to disk between queue items. Its `conditioning` input is lazy, so on a hit the encode node and the ~15 GB text encoder are never executed. One key per (prompt, reference, canvas, length): only the prompt is fingerprinted for you, and only if you wire it | +| | `mode` | use bank if present | `refresh` re-encodes and overwrites, which is what you press after changing anything the key does not cover | +| H3 Latent Bank (alpha) | `bank_key` | pass1 | same idea one stage later: banks a sampled LATENT so the pass is not re-rendered. Seat it after the pass-1 sampler, where the video decode, the audio decode and the jerk oracle all read from it. Lazy input, so a hit never stages the sampler | +| | `seed`, `fingerprint` | unwired | the ONLY things folded into the filename beyond `bank_key`. Wire the noise seed; put steps, scheduler, LoRA strength and resolution into `fingerprint` yourself | +| | `store_dtype` | float32 (exact) | float16 halves the file and sits below a VAE decode's noise, but it is not bit-identical: keep float32 while you are comparing takes | +| H3 Manual Hold Map | `ranges` | | manual time targeting: `start-end[:hold]` pairs, frames or seconds. Wire the oracle's hold_map in and its holds survive only inside your ranges (gate mode); leave it unwired to author holds directly. The report output prices the regeneration before you run it | +| H3 V2V Init | `freeze_threshold` | 0 (off) | automatic background freeze, not recommended: it fixes background timing but degraded other artifacts in our playback tests. Kept for content where the trade goes the other way | +| | `mask`, `mask_feather` | off, 0 | manual freeze region: you paint what regenerates (`invert_mask` to paint the frozen background instead). Static union over time, so the boundary never moves. Default is hard latent cells (each ~16 px cell fully frozen or fully live; the decode smooths the edge); raise `mask_feather` for a pixel-space ramp pooled to fractional cells if a seam shows | +| H3 Motion Composite | `mask` | oracle heat | spatial recovery: regenerated pixels inside the mask, baseline outside. The automatic oracle-heat mode stays deprecated for moving background objects (they pop at its boundary); with a hand-drawn mask the seam goes where you hide it, along a real edge | +| H3 Indecision Oracle (experimental) | `mode` | indecision | which signal drives the hold map: `indecision`, `jerk passthrough`, `blend max`, `blend weighted w`. Outputs mirror H3 Jerk Oracle and compile through the same threshold/bridge/ramp code, so the switch changes the signal and nothing else. See below | +| | `step_a`, `step_b` | 6, 12 | which two X0 Tap dumps to difference. 6 to 12 on a 25-step run is the validated pair; 0 to 1 is degenerate | +| | `blend_w` | 0.5 | weight on indecision in `blend weighted w`; blending happens after per-source rank normalization | +| H3 Timeline Analyze (alpha) | `auto` | True | oracle profiles in, a PLAN DOCUMENT out: a per-clip JSON saying in generation densities over time how the shot should be retimed. `auto` compiles the proposal straight to a minted graph; off stops at the plan so you can edit it | +| H3 Timeline Render (alpha) | `plan_path` | | a plan in, a legal graph minted and priced. It emits the graph path and the launch line rather than executing: launching stays with your own queue script | +| H3 Drawn Plan (alpha) | `plan_path`, `plan_json` | | load a plan and get its compiled geometry as wireable outputs: `hold_map` (the compiler's map verbatim, for H3 Temporal Insert), `ranges` (the same map in H3 Manual Hold Map's language, which re-shapes it through that node's own snapping), window start/len, dilated length, guide frame, and a `splice_map` for H3 Segment Splice at feather 0 | +| | `ignore_uncompiled_lanes` | False | a plan may carry lanes this backend cannot compile yet. Off refuses the plan so nothing is dropped silently; on compiles the density lane and names every lane it skipped | +| H3 Plan Settings (alpha) | `plan_path`, `plan_json` | | the same plan's execution knobs as typed outputs: inject, steps, seed, prompt, width, height, output prefix. Wire these instead of retyping them and the graph cannot drift from the plan. `expand_to_end` is reported for reading only: the compiler already baked it into the map, so H3 Temporal Insert stays False | +| H3 Plan Estimate (alpha) | `recorder_path` | flight recorder | what the plan costs before it runs: equivalent clip time (exact from the plan), work units, VRAM band. `seconds` comes back -1 when your box has no recorded runs, because an uncalibrated guess is worse than no answer | +| H3 Repair Plan (alpha) | `bad_start`, `bad_end` | 0, 0 | 0-based inclusive frame range that is wrong. The node snaps it OUTWARD to whole latent time tokens and emits the hold map, the time-varying regenerate mask and the splice bounds | +| | `hold` | 3 | dilation on the repaired span only; set H3 Time Smear's `dilation` to the same number, and its `expand_to_end` off | +| | `shot_cuts`, `cut_reach` | "", 8 | 0-based first frame of each new shot. A cut inside the span, or within `cut_reach` of its end, becomes the exit: the splice hands back to the original AT the cut | +| H3 Repair Splice (alpha) | `plan` | | frame selection, nothing resampled or blended. Asserts that every frame outside the splice is bit-identical to the original, and prints entry/exit seam deltas next to the original's own delta at the same frames | +| H3 DyRoPE (experimental) | `mode` | physical_blocks | which blocks or steps see the physical (true-duration) grid instead of the stock uniform one. `physical_all` reproduces H3 True Clock, `compact_all` reproduces having no node at all | +| | `block_lo`, `block_hi` | 0, 24 | the block range for the `*_blocks` modes. Two recommended doses, neither a default: 30-49 (timing-fidelity, slight flicker in the span) and 40-49 (minimal shimmer, can read over-smooth on some content) | +| | `fade_end` | 0.5 | for the `fade_*` modes: the sigma at which the interpolation completes. 0.7 is the recommended fade dose; 0.8 is already past the benefit boundary | +| H3 V2V Init | `audio_prefix_ticks` | 0 (off) | (alpha) freeze the first n audio-latent ticks to the seeded `audio_latent`. A 39-frame carried handle is exactly 65 ticks. Needs `audio_latent` wired | +| | `audio_prefix_release_ticks` | 0 | (alpha) half-cosine release over the last n ticks of the frozen prefix instead of a hard edge; 8 ticks (0.2 s) is the upstream lineage's tested recipe | +| H3 Drift Control (alpha) | `prefix_frames` | 39 | schedule-matched noise on a chained segment's carried VIDEO prefix, tapering to exact at the seam end. 39 frames = 12 latent steps = `matched_steps` 8 + `taper_steps` 4, and those two must sum to the prefix's step count | +| H3 Delta Color Carry (alpha) | `strength` | 0.50 | adds only E(corrected) - E(original) to the carried prefix, so the encode bias cancels and only the grade survives. Inert until the two stats inputs differ | +| H3 Scene Color Stats (alpha) | | | centre-weighted luma/saturation percentiles of a frame batch as JSON, for the node above | + +#### The indecision oracle (experimental, 2026-08-14) + +A second, independent oracle. The jerk oracle reads a clip's motion out +of a finished latent; this one reads the model's own uncertainty out of +two mid-schedule x0 predictions: + + J[token] = avgpool2x2( mean over the 24 latent channels of |x0_b - x0_a| ) + +High J means tokens whose predicted clean latent is still moving between +denoise steps, i.e. where the model has not made up its mind. A desk +study over 7 scenes found it carries genuinely independent signal: +controlling for pixel motion it still correlates +0.41 with static +detail energy, and on the quietest third of token-times (where +frame-diff has nothing to say) +0.51. It also misses things the jerk +oracle catches: one fast swinging prop read motion rank 0.97 and jitter +rank 0.04. The two disagree in both directions, so `blend max` is the +recommended experiment rather than a straight substitution. + +**Nothing else in the pack changed its defaults.** This node exists so +the comparison can be made on real renders first. + +Wiring the A/B: + +1. Pass 1 goes through `X0 Tap (SAMPLER wrapper)` from `h3-motion-lab` + with `dump_steps` including both steps you want (`6,12` at minimum). +2. Wire the pass-1 latent into `samples` and the tap's `dump_dir` into + `dump_dir`, and set `length`/`width`/`height` to the tapped clip. +3. Wire `hold_map` where you would have wired the jerk oracle's, and + flip `mode` to compare. `jerk passthrough` reproduces H3 Jerk Oracle + exactly (unit-tested for byte-identical output), so the A/B is one + widget and not two graphs. +4. Read the `comparison` output for the overlap and divergence numbers, + and preview `heat` for the side-by-side map (indecision left, jerk + right; wire `images` to get it overlaid on frames instead of tiles). + +Two traps the node shouts about in its report: + +- **The cheap pair is the useless one.** Step 0 to 1 is dominated by the + (1,4,4,4,4) chunk-phase ramp, not by content, and correlated at or + below zero with the picture on 6 of 7 test scenes. +- **Masked, pinned and repaint runs give you a picture of the mask.** + Composited token rows read as exactly zero jitter. If more than 30% of + token rows are exactly zero the report says so in capitals; believe it + and do not drive a hold map off that map. + +Some graphs tap `0,1,12,24` rather than including 6. There 12 to 24 is +the usable pair. With `auto_fallback` on (default) the node picks the +closest available pair and puts what it did in the report; turn it off +to hard-fail on a mis-tapped graph instead. +| | `feather_profile`, `feather_direction` | linear, centered | seam control: linear/smoothstep/gaussian falloff; centered straddles the boundary, inward eats into the masked side, outward into the kept side | + +### What to expect, time-wise + +Measured on a 5 second 1024x1024 clip at about 11.5 s/step (RTX PRO 6000); +scale to your card and clip: + +| path | time | what you get | +|---|---|---| +| starting point, turbo pass 2 (`examples/motion_pipeline_ref2va_audioinit.json`) | ~12 min for 192 frames at 1 MP; the same graph at 25 steps both passes without turbo is ~36 | the normal finals since 2026-08-19 | +| pipeline, inject 0.70 (`examples/motion_pipeline.json`) | ~19 min incl. its own baseline | the slow finals: 25 steps both passes, base model throughout | +| pipeline, inject 0.50 (`examples/archive/motion_pipeline_i50.json`) | ~15 min incl. baseline | sharper, tracks the source motion closer; try both | +| probe + expert turbo (`examples/archive/motion_pipeline_probe_expert.json`) | ~8.5 min, no full baseline | the fast full de-rope; preview output is intentionally rough | +| featherweight (`examples/archive/motion_pipeline_featherweight.json`, ComfyUI 0.31+) | 4-6 min for 3 s clips; ~29 min for 5 s at 1.0 MP | the 24-32 GB card path; fits where int8 thrashes. See TUNING for measured peaks | +| split LoRA pass 1 (`examples/archive/motion_pipeline_split_lora.json`) | ~7.5 min at 1.5 MP | most motion retained of the pass-1 recipes we measured | +| upscale de-rope (`examples/motion_pipeline_upscale_derope.json`) | ~6.75 min at 0.4 -> 1.5 MP | 89% of native detail, 83% of the time | +| fast iterate (`examples/motion_pipeline_fast_iterate.json`) | ~95 s at 0.2 -> 0.4 MP | prompt and choreography loop, not a final | + +The rows pointing into `examples/archive/` are earlier recipes, kept so +these numbers still resolve; start from the live graphs. + +Start with a short clip, 2 to 3 seconds, and scale up once you like what +you see. Durations snap to the model's legal frame counts automatically +(the closest ones are 1.6 s, 2.3 s, and 3.0 s at 24fps), a short clip +keeps VRAM and wait times friendly, and how far you scale is really a +question of how much fast action the clip contains: cost follows the +burst spans, not the runtime. + +A tuning guide for all of this, written for humans and for AI assistants +working on a user's behalf, is in [`TUNING.md`](TUNING.md). + +Where the method is honestly weak, and what we are doing about it, is split +across two documents: [`RESEARCH_NOTES_ATOS.md`](RESEARCH_NOTES_ATOS.md) for +what has been measured (including the finding that the oracle can rank but +cannot abstain), and [`ROADMAP.md`](ROADMAP.md) for the methods under +investigation, what would count as success for each, and the approaches we +tried and rejected. + +### bridge and inject + +Both settings change the output in ways that are a preference, not a +ranking. From same-seed comparisons on our test clips: + +- `bridge: 8` (default): the hold plateau covers each burst fully. + Sharpest output, motion tracking equal to uniform dilation, about 2.9x + frame budget. Poses can drift slightly from the baseline (a head angle + on a landing, that kind of thing). +- `bridge: 0`: holds follow the raw oracle curve. Closest to the + baseline's poses; a few soft frames can remain where the curve dips + inside a burst. +- no hold_map (uniform `dilation: 4`): most conservative, highest cost. +- `inject 0.70` vs `0.50`: 0.50 measured sharper with closer motion + tracking on our clips; 0.70 has been the safer default in playback. + Try both on your content. + +### Manual spatial masks, or: the birds + +Time warping overcranks steady background movers (birds, crowds, +traffic) inside dilated spans, and both automatic remedies failed our +playback bar: compositing on the oracle's own heat mask popped at the +boundary, and the latent freeze degraded other artifacts. The +mechanisms were fine; the mask author wasn't. The oracle cannot hide a +seam. You can, by lassoing the sky down to a rooftop line and letting +the feather blend along an edge where nothing moves. + +So both mechanisms now take a hand-drawn MASK. On the demo clip, whose +regeneration invented an extra flock and a small pagoda, a two-box +keep-baseline mask (`invert_mask` on) returned both regions to the +baseline take and kept the regenerated subject, seam along the cloud +deck. Prefer the composite (pixel space, fine feather control) unless +background and subject share lighting or contact, then use the V2V +Init freeze (latent space, coarser feather, but the model renders the +interaction). A single mask is a static boundary and cannot pop by +construction; mask batches are supported for per-frame control but +bring the moving-boundary risk back, so feather harder and judge in +playback. + +### Notes on the approach + +- A reference conditions every step at full strength and will copy the + source's artifacts. An init decays with noise: at `inject 0.70` the + baseline's smear detail is destroyed while its coarse motion survives. +- The model's clock stays uniform. The slowdown exists only in the + content, as a speed ramp, so there is no boundary where the DiT and the + VAE disagree about time. (Warping the RoPE time axis directly was + tried; it produced boundary stutter.) +- Holds are integer, so recovering the original frame rate is exact frame + selection. + +### Dialogue through a de-rope + +If your clip has speech in it, the de-rope will break it, and the way it +breaks is not obvious from the output. + +Here is what happens. The de-rope stretches time, regenerates, then +compresses back. The picture goes along with that: the smeared init tells +pass 2 to move slowly, and it does. The audio has no init. It starts from +zeros, so pass 2 writes a fresh performance at natural speaking rate and +moves the mouth to match that. Recovery then compresses the whole clip by +the hold factor. The body comes back at the right speed because it really +was slowed. The mouth does not, because it never was. On a clip that +dilated 2.4x, held regions come back sounding rushed while the tail sounds +fine, which is a confusing symptom because half the clip is correct. + +The fix is to give the audio an init too. `H3 Audio Smear` stretches the +baseline track onto the same dilated clock the video init lives on, using +the same hold map. Encode that with `VAEEncodeAudio`, wire it into +`H3 V2V Init`'s `audio_latent`, and set `audio_mode` to +`follow the original performance (0.5)`. Pass 2 now renders a genuinely +slowed take, so compressing it afterwards is a valid thing to do. + +Two graphs ship with this, both full-reference mode: +[`motion_pipeline_ref2va_audioinit.json`](examples/motion_pipeline_ref2va_audioinit.json) +has the seed wired and writes both audio routes as separate finals, and +[`motion_pipeline_ref2va.json`](examples/motion_pipeline_ref2va.json) is the +same graph without it, kept as the archived version. Diff the two if you +would rather read the change than follow the steps below. + +**To adopt it in a graph you already have, add three things:** + +1. `H3 Audio Smear` -- `audio` from the VAEDecodeAudio of your FIRST pass + (the baseline performance, not pass 2's), `hold_map` from the same + `H3 Time Smear` output you already feed to `H3 Audio Recover`, `fps` 24. +2. `VAEEncodeAudio` -- audio from the smear, vae is your audio VAE. +3. On `H3 V2V Init`, wire `audio_latent` from that encode and set + `audio_mode` to `follow the original performance (0.5)`. + +Nothing else changes. Both new inputs are optional and default to the old +behaviour, so a graph without them behaves exactly as it did before. + +**Which audio to ship.** `H3 Audio Recover` now takes plain-language +options instead of a bare 0 to 1 dial, because the two ends mean different +things depending on whether you seeded the rows: + +- `keep the original performance (safe default)` is the one to use. Your + first pass's audio is already on the world clock and has never been + through a vocoder, so it is the best-sounding track you have. The seed's + job is to make the picture agree with it. +- `use pass 2's foley - ONLY IF the audio rows were seeded` gives you + foley scored for the new motion. Without a seed this is the rushed + defect described above. With one it is a real option, though it comes + back thinner: two phase-vocoder passes and a VAE round trip cost about a + third of the presence band between 3.4 and 8 kHz. + +**What it costs the picture: nothing measurable.** Same graph with and +without the seed, everything else held, came out 91.8 against 91.3 on +laplacian variance, which is inside the noise floor of the video encoder +itself. It moves most pixels, because it is steering a joint audio-video +latent and the two halves are denoised together, but it does not soften. + +**Where this has and has not been tested.** It has been run on a handful +of clips, all sword-fight material with two speakers trading lines over +fast motion, at hold factors around 4 and dilations from 2.4x to 2.7x. +It has not been tried on a single speaker, on speech over music, on +non-anime footage, or at other hold factors. Treat it as alpha, and +listen to the tail of a clip as well as the start, because the tail is +where an unheld region will sound normal whether or not anything is wrong. + +### The motion adapter (pilot) + +A rank-16 LoRA trained on the de-rope task itself: frames inside a motion +burst held out, the rest kept as clean context, the model asked to fill +the burst back in. Applied to the de-rope pass only, it teaches the base +model to spend the stretched clock on smoothness instead of invention. +Weights and the measurement write-up: +[huggingface.co/matlowai/MiniMax-H3-Motion-Adapter](https://huggingface.co/matlowai/MiniMax-H3-Motion-Adapter). +Graphs: [`examples/experimental/motion_pipeline_adapter_api.json`](examples/experimental/motion_pipeline_adapter_api.json) +(text to video, then the standard de-rope with one `LoraLoaderModelOnly` +on the pass-2 model) and +[`examples/experimental/motion_window_pinned_adapter_api.json`](examples/experimental/motion_window_pinned_adapter_api.json) +(a clip you already have: the window is regenerated at denoise 0.70 with +its first and last frames pinned, adapter on the pass-2 model; this is the +graph behind the demo page's headline quad). Clips on the +[demo page](https://matlowai.github.io/ComfyUI-MAINodes/#adapter). + +Settings, measured on clips it never saw: strength 1.0 (strength and +inject are the same dial; 1.0 wins alternation in every paired cell); +inject is what you tune, 0.45 for character work where the base +over-produces, 0.30 where identity or props are the deliverable, anything +on very fast anime; keep the tail guide on. Known costs: about 1 dB of +anchor fidelity on native keyframes, over-correction of calm chains, and +muted colour on strong-colour or particle-heavy subjects, worst on the +Ref2VA checkpoint and on full-clip 3x passes (a prismatic creature came +out as a plain calico both ways). It is a pilot released as an intermediate option; a +more ambitious all-in-one adapter is in progress and may not work. + +### Repairing a few bad frames + +Sometimes a finished clip is fine except for half a second of it. Repair is +the bilateral sibling of the extension nodes: extension asks what comes +after a clip, repair says these frames are wrong, render them again, and +give the clip back with only those frames different. + +`H3 Repair Plan` does the arithmetic. You give it the clip length, the bad +frame range (0-based, inclusive) and a hold, and it emits four things: a +hold map for `H3 Time Smear`, a time-varying regenerate mask for +`H3 V2V Init` in DILATED coordinates, the splice bounds, and a report that +prices the pass. `H3 Repair Splice` then reassembles: original pixels +outside the splice, repaired pixels inside, nothing resampled and nothing +blended. + +Two rules run through both nodes, and they pull in opposite directions: + +- **Masks snap to tokens.** A latent time token cannot be half + regenerated, so the regenerate mask has to cover whole tokens. Frames + group in 17s, each group is 5 tokens covering (1, 4, 4, 4, 4) frames, so + "frames 45 to 47 are wrong" becomes "regenerate 43 to 50". +- **Splices are free.** Reassembly is pure frame selection and may cut + anywhere. So extend the mask where the grid forces it, then choose the + splice points for picture reasons: enter in quiet motion, and exit ON a + shot cut whenever one is near. + +The cut rule is the one that earns its keep. On the validation clip the +token snap pushed the regenerated span across a hard cut and the model +reinvented the first frames of the next shot; the exit seam popped at 2.6x +the clip's median frame delta. Extending the mask through the cut did not +fix it (2.3x). Handing back to the original AT its own cut did. Type the +cut into `shot_cuts` and the plan carries the mask through it while the +splice exits on it, so the seam becomes the edit the shot always had. + +Measured on that cell (90 frames, bad 45 to 47, hold 3, cut at 53): entry +seam 3.99/255, which is 0.26x the clip's median frame delta; exit 138.04 +against the original's own 135.57 at the same cut, a difference of 1.8%; +maximum absolute pixel difference outside the splice 0, asserted by the +node. The plan's own entry check called frame 43 quiet (2.0 against a +median of 15.2). `tests/test_repair_plan.py` pins that arithmetic and runs +on CPU with no models. + +**AUDIO IS STILL A WORK IN PROGRESS for the repair verb.** The video splice +is frame-exact; audio handling across the splice is not yet finished. +`H3 Repair Splice` passes an AUDIO input straight through, untouched and +the same length, which is right when the repair did not change the +performance and is not a general answer. Repair picture, keep your original +track, and do not expect the node to solve a repaired line of dialogue yet. + +Two things to set on the rest of the graph: `H3 Time Smear`'s `dilation` +must equal the plan's `hold`, and its `expand_to_end` must be OFF, because +an end-expansion rewrite moves every dilated coordinate the plan just +computed. The plan says so in its report if it detects the case. + +### DyRoPE: who gets the true clock + +`H3 True Clock` tells the model the true world duration of a time-smeared +clip, and it works: background agents hold world speed through a held span. +It was also measured to cost seam flash (7.17x against a control's 1.87x) +and jitter (5.06x against 0.85x), because the same non-uniform time grid +goes to all 50 blocks at every step, and that is off-distribution. + +`H3 DyRoPE` splits the two geometries apart so they can be handed out +selectively. Physical is True Clock's grid, compact is the stock uniform +grid the model was trained on. `physical_all` reproduces True Clock exactly +and `compact_all` reproduces having no node in the graph at all; those are +the identity arms. The `*_blocks` modes give a named block range one +geometry and every other block the other, and the `fade_*` modes give every +block one interpolated grid per step, as a function of sigma, complete at +`fade_end`. + +What a twelve-arm dose ladder on one clip says, meters first: + +| arm | flash | jitter | +|---|---|---| +| stock clock everywhere (control) | 2.09x | 1.77x | +| physical everywhere (= True Clock) | 8.14x | 2.93x | +| physical in blocks 0-9 only | 7.84x | 2.95x | +| physical in blocks 25-49 only | 1.87x | 2.61x | +| physical in blocks 30-49 only | 1.84x | 2.33x | +| physical in blocks 40-49 only | 1.94x | 1.39x | +| fade to stock by sigma 0.3 | 1.76x | 2.72x | +| fade to stock by sigma 0.7 | 1.80x | 2.06x | +| stock at high sigma, physical by sigma 0.5 | 2.58x | 8.32x | + +Two readings. **Flash is an early-block effect**: ten early blocks with +true time reproduce the whole True Clock flash, and every arm that keeps +true time out of blocks 0-9 sits at the control's level. **Jitter is a dose +effect**: it scales with how much physical-time exposure the run gets, once +the early blocks are excluded. + +The meters cannot pick the winner, though, because they say nothing about +whether an arm still delivers what the true clock was FOR. Playback maps a +benefit boundary the meters do not see: world timing survives at blocks +40-49 for all steps, and at all blocks above sigma 0.7, and at every larger +dose. It dies at `fade_end` 0.8 (the window gets too short), and at any +block restriction stacked on top of the sigma window. Every attempt to cut +jitter below those two doses lost the timing. + +So there are two settings worth recommending, and neither is a winner. They +trade the same two things against each other, and which one is right is a +property of your clip. Neither is a code default; the node ships with its +defaults unchanged. + +- **`physical_blocks` 30-49, the timing-fidelity setting.** The held span + holds world speed neutrally, without over- or undershooting it. The cost + is a slight flicker or hitch inside the span (this dose metered 2.33x + jitter against the stock control's 1.77x). +- **`physical_blocks` 40-49, the minimal-shimmer setting.** The smoothest + span of the pair and the cleanest meters on the board (1.17x to 1.39x + jitter across three takes, always below the stock control). On some + content it slightly overshoots the correction, so the span can read + over-smooth or slowed. +- **`fade_physical_to_compact` at `fade_end 0.7` is the flash-free + alternative.** No flash at all in playback, visible jitter (2.06x to + 2.87x across takes), timing held. +- The mechanism to keep in mind while you choose: **less dose than these + loses the world-time correction entirely, more dose adds shimmer.** There + is no setting that is quieter than 40-49 and still on time; every arm + tried below these doses came back on the stock clock's speed. +- The failure being fixed is worth naming, because it is easy to mistake + for a de-rope defect: on the stock clock a dilated span PLAYS + ACCELERATED. Background agents in the held region move too fast, because + the model was told the span is shorter than it really is. + +`H3 DyRoPE` is not composable with `H3 Streamed Blocks` in the `*_blocks` +modes: both own the double-block replacement slot and ComfyUI keeps one per +block. The capability probe reports the collision. The fade modes use no +block patches and compose fine. + +The clips these numbers came from are on the public deck: +. + +### Anchoring audio across a join (alpha) + +`H3 V2V Init`'s `audio_strength` is one number for the whole track. +`audio_prefix_ticks` makes it a shape: the first n audio-latent ticks are +frozen to the seeded `audio_latent` content (noise mask 0 there), and every +later tick keeps `audio_strength`. That is the audio twin of the video +prefix freeze, and it is what lets a continuation carry the previous +segment's sound into the new one instead of starting a new performance. + +The four things to know before wiring it: + +- **It needs `audio_latent` wired.** With nothing seeded there is nothing + to freeze to, and the setting does nothing but confuse the log. The tick + clock is the audio latent's, not the video's: a 39-frame carried handle + is exactly 65 ticks. +- **An AddGuide AUDIO guide and `ref_audios` cannot coexist.** They collide + in conditioning-audio packing. (Measured on core 82f839f5; treat as a current-core rule, not a model property.) Pick one route for a graph and stay on it. +- **`audio_prefix_release_ticks` changes what assembly has to do.** With a + release above 0 the last n ticks of the frozen prefix ramp from 0 up to + `audio_strength` on a half cosine instead of cutting hard (8 ticks, 0.2 + s, is the upstream lineage's tested recipe). If you use it, the assembly step must let the + CONTINUATION own the overlap tail, or the trim throws the ramp away and + you paid for nothing. +- **Scope: it carries local continuity, not structure.** Level, timbre and + beat come across the join. It does not carry global phrase structure. A + longer handle helps at the seam (90 frames measured 0.953 overlap + correlation vs 0.92 at 39) and gives the model a full musical phrase of + context, but only a pinned master track GUARANTEES the structure; that + guarantee is by construction. + +Alpha, and the honest reading is that this has been exercised on a narrow +slice of material. Both inputs default to 0 and the scalar path is +unchanged at that value, so a graph without them behaves exactly as it did +before. + +### Chained segments: drift and colour (alpha) + +Two different things decay when you chain segments, and they have separate +nodes. + +**`H3 Drift Control`** attacks clean-conditioning error. A chained +segment's carried prefix is bit-clean, which one seam loves and a chain +does not: repeated clean conditioning accumulates contrast and texture +error, and a seam probe watches the join decay from about 0.9 at the first +join to about 0.65 by the second across every variant tested. The node +gives the disposable carried VIDEO prefix a small, schedule-matched amount +of the sampler's own noise at every model evaluation, tapering to exact at +the seam end, so the model never treats the prefix as impossibly clean. +Audio is deliberately untouched: the frozen per-tick audio prefix stays +hard. + +What it demands, all of which it enforces rather than guesses: + +- `prefix_frames` must equal the plan's handle and sit on the 17k+5 grid. + 39 frames is 12 latent steps, and `matched_steps` + `taper_steps` must + sum to exactly that (8 + 4 is the field-validated recipe). +- The latent must already carry a noise mask: wire `H3 V2V Init` first. The + node rewrites that mask, it does not create one. +- It **refuses to stack** on another dynamic denoise-mask patch. Two of + them cannot share the model. +- Sigma-split samplers are not supported; our graphs run one + `SamplerCustomAdvanced` per pass. +- **Replicated across two chains and new seeds.** Joins hold 0.85-0.89 + through link 4 on the newer chain; the earlier chain, before this node, + fell to the 0.65 class by its second join. That is a cross-chain + comparison, not a paired drift-off arm. The matched+taper recipe itself + is still one recipe, not a swept space. + +**`H3 Delta Color Carry`** (with `H3 Scene Color Stats`) attacks the other +decay: every carried handle is a VAE round trip, each round trip darkens +about 2.4%, and chains accumulate it. Rather than regrading the sampled +latent, it decodes the prefix once, applies a weak scene-one +exposure/saturation correction in RGB, encodes BOTH the original and the +corrected frames, and adds only E(corrected) - E(original) to the latent. +The encode bias appears in both terms and cancels; only the intended grade +survives. The delta is spatially low-passed and tapered from zero at the +old edge to full strength beside the generated future, and audio is never +touched. Wire the delivered tail of scene one through one +`H3 Scene Color Stats` into `anchor_stats`, the current predecessor's tail +through another into `current_stats`, and the node between the extend +graph's `VAEEncode` and `H3 V2V Init`. On the first link the two stats are +the same tail, the transform is the identity, and the latent passes +through untouched. + +Status, stated plainly: Active path exercised on a real 4-link render 2026-08-24: it fires, corrects in the anchor direction, and stays sub-visible under its clamps on mildly-drifted content; on the deepest tested link it fires on both channels at or near its clamp. A strong-drift bench (where the 2.4% per-round-trip signature actually accrues) is still owed. + +Both nodes are adapted, with permission of the licence, from +ComfyUI-MiniMaxH3-Contex-Loop (GPL-3.0, the same licence as this pack): +Drift Control from its Drift-Control AV, Delta Color Carry from its +Color-Stable Drift AV. The per-module credit lines in `h3_drift.py` and +`h3_color_carry.py` say exactly what was taken and what was deliberately +not ported. + +### Retiming part of a clip (window mode) + +When only an excerpt of a long clip needs retiming, the graph passes the +rest through untouched and expands the excerpt. That shape is worth its own +page, because the window is encoded in four coupled places (two crops, the +hold map, and the regeneration's conditioning length) and editing three of +them produces a broken render whose damage sits at the OLD boundary. Window +starts also quantize to a 17-frame lattice, 0.708 s at 24 fps, which is why +"start at second 1" is not a thing the graph can do. + +The arithmetic, the failure signature and the procedure are in +[docs/WINDOW_MODE.md](docs/WINDOW_MODE.md). + +## Contact-Sheet diffusion + +Five standalone image latents packed on the model's time axis, jointly +denoised, decoded independently. Use with a Turnaround LoRA from +[matlod/minimax-h3-turnaround](https://huggingface.co/matlod/minimax-h3-turnaround). +Nodes: **H3 Contact Sheet**, **H3 Contact Sheet Decode**. +Drag-in workflow: [`examples/contact_sheet.json`](examples/contact_sheet.json) +(API twin alongside) — point the LoadImage at your reference image, pick +your downloaded LoRA file, queue. `ref_image` is optional: leave it +unconnected for a text-only sheet (drop the `` tag from the +prompt); [`examples/contact_sheet_t2i.json`](examples/contact_sheet_t2i.json) +is that graph. Stock loaders and sampler throughout; +28 steps of res_multistep at denoise 1.0, LoRA strength 0.75. A scripted +example is in [`example_api_workflow.py`](example_api_workflow.py). +Previously published as ComfyUI-H3-ContactSheet; that repo remains up for +existing installs. + +## Alpha work + +This pack ships finished work and unfinished work in the same install. +The Motion Lab pipeline and the contact sheet above are the finished part. +Alongside them are a research subsystem (Concept Lab), a timeline surface, +the audio init for dialogue, the motion adapter pilot, and the manual mask +paths, all at varying degrees of unfinished. + +**[ALPHA.md](ALPHA.md) says which is which**, what each one can and cannot +do today, and where each has and has not been tested. Alpha nodes carry +`(alpha)` in the ComfyUI menu, they load behind a guarded loader so a +broken one cannot take the pack down, and none of them changes existing +behaviour or defaults. + +## Comparing a batch of renders + +[`tools/compare_deck/`](tools/compare_deck/) builds the review page used for +the sweeps in this pack: a manifest JSON in, one self-contained HTML file +out, with a card grid, a sortable metric table, a synced A/B (side by side +or wipe) on a waveform timeline, and a frame-exact export of the current +view. `make_manifest.py` drafts the manifest from a folder of clips; you +fill in the groups and descriptions. The clips stay where they are, so +nothing but HTML is produced. A live deck built with it: +. Standalone Python, no +ComfyUI import, see [`tools/compare_deck/README.md`](tools/compare_deck/README.md). + +**MAI Video Compare** is the same review surface inside ComfyUI, and it grew +into a full player. Wire 2 to 6 renders into the node and queue once: it +writes each one as a small h264 preview (CPU, no VAE, no tensors kept) and +the widget plays them as live `