1.1.0: docs, version, and the devlog for all of it
Browse filesREADME gets the 1.1.0 block and its resolution references move to the new
rungs. The hop-cache section now states the thing that changed underneath it:
changing a reference picture re-renders only the hops that picture rides.
CLAUDE.md's verified-size instruction follows the top rung rather than naming
1.0 MP, and the iteration-canvas note moves off 0.5 MP -- a label that still
RESOLVES, because retired labels are parsed, but is no longer on the dropdown.
Both prompt_pack prompts, together as the rule requires, note that the
nine-reference limit is per hop and that a whole list of nine can never breach
it. The numbered rules are untouched and still number 13.
Devlog 37-40: the uncited-reference failure and its three appearances; the
canvas formula against the table it replaced, including the two cells I got
wrong by hand and the grid search that was not worth it; the first check the
JavaScript has ever had, and the bug it found in itself on its first run; and
why render_from replays through the loop instead of seeding prev_* up front.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014VB4Dw6F79643vySkf19KV
- CLAUDE.md +2 -2
- PROMPTING.md +1 -1
- README.md +35 -6
- docs/DEVLOG.md +174 -0
- prompt_pack/AUTHORING_PROMPT.md +1 -1
- prompt_pack/SYSTEM_PROMPT.md +1 -1
- pyproject.toml +1 -1
|
@@ -320,7 +320,7 @@ Offline results (`frame_shift`, synthetic): recovers a planted additive shift to
|
|
| 320 |
1. **Cache fingerprint.** LoRA strength 1.0 → 0.9, re-queue. Both hops re-render. (Before the latent sidecar, a hop-1 hit made hop 2 log `AddGuide pixel pin`; that line now means the entry predates the sidecar or its latent failed to load.)
|
| 321 |
**Note ComfyUI's own node cache sits in front of this one:** re-queueing with *nothing* changed skips `run()` entirely (no `[HandTieClips]` lines at all, ~9 s), so it tests nothing. Nudge `cache_budget_gb` to force re-execution -- it is in neither `chain_salt` nor the hop key, so every key stays byte-identical.
|
| 322 |
2. **Chained re-roll.** Revert strength. Change one word in hop 2 only. Hop 1 cache hit, hop 2 renders.
|
| 323 |
-
3. Confirm the same join at **1.0 MP** (`1280×736`) before calling it shipped. Keep `seed_per_shot`. 777777 was join-hostile on the old 5 s pin-only graph; do not treat that seed as the only one.
|
| 324 |
|
| 325 |
**chain_00030_.mp4 / chain_00031_.mp4 / the keyframe-completion re-queue.** Hard cut at hop 2, f124, onto the outfit still’s commercial kitchen. Drink beat ran; pin did not. Official hop 2 cannot join at 8 steps.
|
| 326 |
|
|
@@ -330,7 +330,7 @@ Offline results (`frame_shift`, synthetic): recovers a planted additive shift to
|
|
| 330 |
|
| 331 |
**H3 soundtrack (official methods, user 2026-08-26):** do not invent a pack dialect for quiet vs speech. Dialogue belongs in `detailed_description` as `(S1)` + `<d>[English] …</d>` with the actual words. Ambience/physical/non-verbal belong in `overall_soundscape`. Requested silence throughout a hop is `overall_soundscape: N/A` (the official complete-silence token), not the English word “Silence” stuffed into a beat. “No speech” / “no dialogue” is still negation and still gibberish. `_assemble_next` currently does not emit these fields; when the beat already contains them, leave them alone.
|
| 332 |
|
| 333 |
-
**Iteration canvas (user 2026-08-26):** further tests run at **0.
|
| 334 |
|
| 335 |
**chain_00028_.mp4 (0.5 MP, 960×544, 702 f / 29.25 s, 8 step).** Same stress plan. Frame-walked.
|
| 336 |
|
|
|
|
| 320 |
1. **Cache fingerprint.** LoRA strength 1.0 → 0.9, re-queue. Both hops re-render. (Before the latent sidecar, a hop-1 hit made hop 2 log `AddGuide pixel pin`; that line now means the entry predates the sidecar or its latent failed to load.)
|
| 321 |
**Note ComfyUI's own node cache sits in front of this one:** re-queueing with *nothing* changed skips `run()` entirely (no `[HandTieClips]` lines at all, ~9 s), so it tests nothing. Nudge `cache_budget_gb` to force re-execution -- it is in neither `chain_salt` nor the hop key, so every key stays byte-identical.
|
| 322 |
2. **Chained re-roll.** Revert strength. Change one word in hop 2 only. Hop 1 cache hit, hop 2 renders.
|
| 323 |
+
3. Confirm the same join at the top rung -- **0.98 MP** (`1312×736`) as of 1.1, **1.0 MP** (`1280×736`) before it -- before calling it shipped. Keep `seed_per_shot`. 777777 was join-hostile on the old 5 s pin-only graph; do not treat that seed as the only one.
|
| 324 |
|
| 325 |
**chain_00030_.mp4 / chain_00031_.mp4 / the keyframe-completion re-queue.** Hard cut at hop 2, f124, onto the outfit still’s commercial kitchen. Drink beat ran; pin did not. Official hop 2 cannot join at 8 steps.
|
| 326 |
|
|
|
|
| 330 |
|
| 331 |
**H3 soundtrack (official methods, user 2026-08-26):** do not invent a pack dialect for quiet vs speech. Dialogue belongs in `detailed_description` as `(S1)` + `<d>[English] …</d>` with the actual words. Ambience/physical/non-verbal belong in `overall_soundscape`. Requested silence throughout a hop is `overall_soundscape: N/A` (the official complete-silence token), not the English word “Silence” stuffed into a beat. “No speech” / “no dialogue” is still negation and still gibberish. `_assemble_next` currently does not emit these fields; when the beat already contains them, leave them alone.
|
| 332 |
|
| 333 |
+
**Iteration canvas (user 2026-08-26):** further tests run at **0.45 MP** (`896×512` landscape) for speed. (Was 0.5 MP / `960×544`; 1.1 computes the canvas from an area budget and the rungs moved. `0.5 MP` still resolves -- retired labels are parsed -- but it is off the dropdown.) 8 steps, seed 777777, 4×8 s, overlap 0.9 s stay. Seam times do not move (still master frames 192 / 362 / 532). Resolution is in `chain_salt`, so the top-rung cache will not hit. A low-rung pass validates join / speech / cache behaviour, not full-resolution texture. Confirm anything that ships at the top rung on that canvas before calling it done.
|
| 334 |
|
| 335 |
**chain_00028_.mp4 (0.5 MP, 960×544, 702 f / 29.25 s, 8 step).** Same stress plan. Frame-walked.
|
| 336 |
|
|
@@ -504,7 +504,7 @@ Two related dials:
|
|
| 504 |
- **`render_through=N`** stops after N hops. With `cache_hops=on`, 3 → 5 → 8
|
| 505 |
builds a chain up in stages and only ever renders the new hops. The plan is
|
| 506 |
not truncated; shot 4 still keys exactly as it will in the full run.
|
| 507 |
-
- **`quality=draft`** forces 0.
|
| 508 |
camera and whether a join lands. Both values are in the cache key, so a draft
|
| 509 |
never overwrites the final it stands in for.
|
| 510 |
|
|
|
|
| 504 |
- **`render_through=N`** stops after N hops. With `cache_hops=on`, 3 → 5 → 8
|
| 505 |
builds a chain up in stages and only ever renders the new hops. The plan is
|
| 506 |
not truncated; shot 4 still keys exactly as it will in the full run.
|
| 507 |
+
- **`quality=draft`** forces 0.30 MP and 6 steps. Enough to read blocking,
|
| 508 |
camera and whether a join lands. Both values are in the cache key, so a draft
|
| 509 |
never overwrites the final it stands in for.
|
| 510 |
|
|
@@ -80,6 +80,34 @@ of a second, separate generation. The pack exists so that you cannot tell which.
|
|
| 80 |
> quiet buys a quiet pin, not a quiet opening. Sections 31 and 32 of the devlog
|
| 81 |
> have the measurements.
|
| 82 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 83 |
> **1.0.1 — 2026-09-02.** Three fixes, all found by the first people to use
|
| 84 |
> 1.0.0. The **WRITE** panel never saved your model on a fresh install: with
|
| 85 |
> nothing stored, no entry in the dropdown was ever *selected* and the browser
|
|
@@ -235,7 +263,7 @@ Two modes:
|
|
| 235 |
|
| 236 |
Only one of them is on screen at a time, so there is never a text box quietly doing nothing.
|
| 237 |
|
| 238 |
-
Under the script sits **RUN**, collapsed, holding everything that is not per-shot: output size and length, sampling, the join and pin controls, and the hop cache. Its title line summarises the run — `
|
| 239 |
|
| 240 |
**`tone_compensate`** lives in that panel's *join & pin* group. The H3 denoiser biases each hop's tone, so a chain gets steadily brighter; this measures the bias on the overlap each hop regenerated and undoes it, correcting each hop against the previous **corrected** one so the whole chain lands on hop 1's tone. `frame_shift` is the mode to reach for: all three modes remove the drift equally well (within 0.4/255 of each other), but `gain_bias` and `lut` pair pixels between a frame and its *regeneration*, which fits a slope that is not really there and flattens contrast a little more with every hop. `frame_shift` uses frame averages only, so it can shift but never distort. **Measured on a 3-hop render: chain drift 5.6/255 without it, 0.3/255 with it.** Worth turning on for anything past two hops. It ships off because enabling it also clamps the master to 0..1, and because the correction grows with hop count — by hop 10 it is subtracting ~23/255 and will start crushing blacks. Switching modes never invalidates the hop cache, so it is free to A/B. Do **not** judge it by whether the seams flatten to zero: real scene brightness changes across a cut should survive, and they do.
|
| 241 |
|
|
@@ -411,7 +439,8 @@ The key **chains** — each hop's key includes the previous hop's — because ho
|
|
| 411 |
|
| 412 |
- edit shot 3 and re-queue → shots 1 and 2 load from cache, only 3 renders;
|
| 413 |
- edit shot 1 → all three re-render, which is correct, not a bug;
|
| 414 |
-
- change resolution, sampler, a
|
|
|
|
| 415 |
|
| 416 |
That last one is worth knowing about. The node cannot read the settings on your LoRA and attention nodes, so instead it fingerprints what they *did* to the model — which weight keys were patched, at what strengths, and the attention overrides. Change a LoRA strength and the cache correctly invalidates. Two different LoRAs touching exactly the same keys at exactly the same strengths would look identical to it; that is the one gap.
|
| 417 |
|
|
@@ -433,14 +462,14 @@ rendered stay on disk, so 3 → 5 → 8 builds a chain up in stages and only eve
|
|
| 433 |
renders the new hops. The plan is not truncated: shot 4 still knows it is shot
|
| 434 |
4, keeps its own seed, and keys the same way it will in the full run.
|
| 435 |
|
| 436 |
-
`quality=draft` forces 0.
|
| 437 |
whether a join lands. Resolution and steps are both in the cache key, so a draft
|
| 438 |
never overwrites the final it stands in for; the two simply cost two entries.
|
| 439 |
|
| 440 |
Treat it as a **fidelity** lever rather than a speed one. Measured at ~42 s/hop
|
| 441 |
-
against ~45 s/hop at 7 steps: if you already render at 0.
|
| 442 |
the regime this pack targets — draft saves almost nothing, and `dry_run` is the
|
| 443 |
-
fast button. Draft earns its place when your final is genuinely heavier,
|
| 444 |
at 14 steps.
|
| 445 |
|
| 446 |
## Contact sheet
|
|
@@ -556,7 +585,7 @@ The DiT pin is the previous hop’s **sampler latent** through Motion-Context wh
|
|
| 556 |
|
| 557 |
| | |
|
| 558 |
|---|---|
|
| 559 |
-
| resolution |
|
| 560 |
| duration | 10 s (243 frames) |
|
| 561 |
| overlap | 0.9 s (22 frames) |
|
| 562 |
| steps | 8, with a 4-step turbo LoRA — the regime this node targets |
|
|
|
|
| 80 |
> quiet buys a quiet pin, not a quiet opening. Sections 31 and 32 of the devlog
|
| 81 |
> have the measurements.
|
| 82 |
|
| 83 |
+
> **1.1.0 — 2026-09-03.** The panel is a 4:3 box with tabs instead of one long
|
| 84 |
+
> scrolling column, and RUN stays pinned at the bottom. The **WRITE** draft is
|
| 85 |
+
> readable — it used to clip every beat at 110 characters and throw away the
|
| 86 |
+
> duration, seed, directives and per-shot references before rendering, so what
|
| 87 |
+
> you were asked to Accept was a row of sentences ending in an ellipsis — and it
|
| 88 |
+
> now survives leaving the tab or reloading the page. Shot cards carry `⏵` and
|
| 89 |
+
> `lock` buttons driving `render_from` / `render_through`, the new one being the
|
| 90 |
+
> other end of a range `render_through` has had since 0.4: everything before the
|
| 91 |
+
> start is replayed from the hop cache rather than re-rendered.
|
| 92 |
+
>
|
| 93 |
+
> The bug worth upgrading for: **a reference pinned to any hop but the first
|
| 94 |
+
> tended to be rendered as the shot.** `retention_analysis:` — the text that
|
| 95 |
+
> tells the encoder what a picture is *for* — was emitted on hop 1 only, so a
|
| 96 |
+
> still scheduled onto hop 3 arrived uncited; and the identity lock never read
|
| 97 |
+
> `retention`, so a wardrobe plate carrying a subject was announced as *"the
|
| 98 |
+
> only identity … that face, bone structure, and hairstyle match the photograph
|
| 99 |
+
> exactly"* about a photograph of an apron, while the closer simultaneously said
|
| 100 |
+
> clothing follows the live frame. Both fixed. The reference *clip* had the same
|
| 101 |
+
> gap — it went in as `<Video 1>` with nothing naming it — and now has a
|
| 102 |
+
> description field.
|
| 103 |
+
>
|
| 104 |
+
> Output size is computed rather than tabulated: eleven aspect ratios from 21:9
|
| 105 |
+
> to 9:21 across five megapixel rungs, every one on H3's 32 px grid and under
|
| 106 |
+
> its 768×1344 cap. **The top rung is 0.98 MP, and 16:9 there is 1312×736** —
|
| 107 |
+
> the hop cache invalidates once because of it. Saved 1.0.x workflows keep the
|
| 108 |
+
> exact pixels they were built with. And changing a reference picture now
|
| 109 |
+
> re-renders only the hops that picture rides, instead of the whole chain.
|
| 110 |
+
|
| 111 |
> **1.0.1 — 2026-09-02.** Three fixes, all found by the first people to use
|
| 112 |
> 1.0.0. The **WRITE** panel never saved your model on a fresh install: with
|
| 113 |
> nothing stored, no entry in the dropdown was ever *selected* and the browser
|
|
|
|
| 263 |
|
| 264 |
Only one of them is on screen at a time, so there is never a text box quietly doing nothing.
|
| 265 |
|
| 266 |
+
Under the script sits **RUN**, collapsed, holding everything that is not per-shot: output size and length, sampling, the join and pin controls, and the hop cache. Its title line summarises the run — `1312x736 · 10s ×3 · 14 steps res_multistep · cache off` — so you can read the setup without opening it. In Shots mode `chains` and `hop_script` are not offered there, because the shot list already decides both.
|
| 267 |
|
| 268 |
**`tone_compensate`** lives in that panel's *join & pin* group. The H3 denoiser biases each hop's tone, so a chain gets steadily brighter; this measures the bias on the overlap each hop regenerated and undoes it, correcting each hop against the previous **corrected** one so the whole chain lands on hop 1's tone. `frame_shift` is the mode to reach for: all three modes remove the drift equally well (within 0.4/255 of each other), but `gain_bias` and `lut` pair pixels between a frame and its *regeneration*, which fits a slope that is not really there and flattens contrast a little more with every hop. `frame_shift` uses frame averages only, so it can shift but never distort. **Measured on a 3-hop render: chain drift 5.6/255 without it, 0.3/255 with it.** Worth turning on for anything past two hops. It ships off because enabling it also clamps the master to 0..1, and because the correction grows with hop count — by hop 10 it is subtracting ~23/255 and will start crushing blacks. Switching modes never invalidates the hop cache, so it is free to A/B. Do **not** judge it by whether the seams flatten to zero: real scene brightness changes across a cut should survive, and they do.
|
| 269 |
|
|
|
|
| 439 |
|
| 440 |
- edit shot 3 and re-queue → shots 1 and 2 load from cache, only 3 renders;
|
| 441 |
- edit shot 1 → all three re-render, which is correct, not a bug;
|
| 442 |
+
- change resolution, sampler, a LoRA, or an attention setting → the whole chain re-renders;
|
| 443 |
+
- change a reference picture → only the hops that picture rides re-render. Swapping the file behind `@outfit` when it rides hop 5 leaves hops 1-4 on cache. Before 1.1 this invalidated everything.
|
| 444 |
|
| 445 |
That last one is worth knowing about. The node cannot read the settings on your LoRA and attention nodes, so instead it fingerprints what they *did* to the model — which weight keys were patched, at what strengths, and the attention overrides. Change a LoRA strength and the cache correctly invalidates. Two different LoRAs touching exactly the same keys at exactly the same strengths would look identical to it; that is the one gap.
|
| 446 |
|
|
|
|
| 462 |
renders the new hops. The plan is not truncated: shot 4 still knows it is shot
|
| 463 |
4, keeps its own seed, and keys the same way it will in the full run.
|
| 464 |
|
| 465 |
+
`quality=draft` forces 0.30 MP and 6 steps — enough to read blocking, camera and
|
| 466 |
whether a join lands. Resolution and steps are both in the cache key, so a draft
|
| 467 |
never overwrites the final it stands in for; the two simply cost two entries.
|
| 468 |
|
| 469 |
Treat it as a **fidelity** lever rather than a speed one. Measured at ~42 s/hop
|
| 470 |
+
against ~45 s/hop at 7 steps: if you already render at 0.30 MP and 6–8 steps —
|
| 471 |
the regime this pack targets — draft saves almost nothing, and `dry_run` is the
|
| 472 |
+
fast button. Draft earns its place when your final is genuinely heavier, 0.98 MP
|
| 473 |
at 14 steps.
|
| 474 |
|
| 475 |
## Contact sheet
|
|
|
|
| 585 |
|
| 586 |
| | |
|
| 587 |
|---|---|
|
| 588 |
+
| resolution | 0.98 MP (1312×736 landscape) |
|
| 589 |
| duration | 10 s (243 frames) |
|
| 590 |
| overlap | 0.9 s (22 frames) |
|
| 591 |
| steps | 8, with a 4-step turbo LoRA — the regime this node targets |
|
|
@@ -1954,3 +1954,177 @@ The general shape, and section 34's lesson one level down: a control that
|
|
| 1954 |
displays a value it has not committed is bad, and a generator that emits a
|
| 1955 |
value it could not compute is the same bug wearing a different hat. Neither
|
| 1956 |
one fails; both produce something that looks like an answer.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1954 |
displays a value it has not committed is bad, and a generator that emits a
|
| 1955 |
value it could not compute is the same bug wearing a different hat. Neither
|
| 1956 |
one fails; both produce something that looks like an answer.
|
| 1957 |
+
|
| 1958 |
+
## 37. Two ways to hand a model a photograph and not say why (2026-09-03)
|
| 1959 |
+
|
| 1960 |
+
A user: *"pinning outfit to anything but first hop throws the actual image
|
| 1961 |
+
in."* The obvious suspect was the image ordering -- something prepending the
|
| 1962 |
+
still ahead of the continuity frame. It was not. `_attach_pin_to_qwen` builds
|
| 1963 |
+
`[last_frame] + refs`, and `still_shift` moves the text ordinals to match. The
|
| 1964 |
+
pictures arrive in the right order with the right numbers.
|
| 1965 |
+
|
| 1966 |
+
What was wrong was that nothing said what the picture was *for*.
|
| 1967 |
+
|
| 1968 |
+
`retention_analysis:` is the block that does that -- `<Picture 2> (denim apron
|
| 1969 |
+
over a grey tee): the garment and its cut carry over`. It is produced by
|
| 1970 |
+
`subject_prose`, and `subject_prose` is gated on `i == 0`. That gate is correct
|
| 1971 |
+
for its other half: `subject_definitions:` introduces `<Subject N>`, and a
|
| 1972 |
+
subject token first introduced on hop 4 has no antecedent in its own encode.
|
| 1973 |
+
But retention has no such problem, and it went out with the gate. A still
|
| 1974 |
+
scheduled onto hop 3 therefore reached the encoder as `ref_image_2` with no
|
| 1975 |
+
retention line, no `desc`, and no subject entry. If it also had no subject
|
| 1976 |
+
number, `id_ords` came back empty, `_identity_lock` returned `""`, and the
|
| 1977 |
+
photograph was never named anywhere in the prompt at all.
|
| 1978 |
+
|
| 1979 |
+
The second defect is worse because it is confidently wrong rather than silent.
|
| 1980 |
+
`_identity_lock` decides who is a person by `subject is not None` and has never
|
| 1981 |
+
read `retention`. The canonical outfit reference in the README carries
|
| 1982 |
+
`subject: 1` *and* `retention: partially_copy` -- it is a garment belonging to
|
| 1983 |
+
person 1, not a photograph of their face. So hop 3 opened with *"`<Picture 2>`
|
| 1984 |
+
is the only identity. That face, bone structure, and hairstyle match the
|
| 1985 |
+
photograph exactly"*, asserted about an apron. And because `lock` was then
|
| 1986 |
+
non-empty, the closer became *"Faces and hair follow the identity photographs.
|
| 1987 |
+
Clothing follows whatever is already on them in the live frame"* -- which
|
| 1988 |
+
contradicts the wardrobe plate riding that very hop. At cfg 1.0 there is no
|
| 1989 |
+
negative branch, so both instructions are additive and the encoder gets each at
|
| 1990 |
+
full weight.
|
| 1991 |
+
|
| 1992 |
+
Three changes. `retention_prose` splits out of `subject_prose` and takes an
|
| 1993 |
+
explicit ordinal map, because on a continuation hop the live frame is `<Picture
|
| 1994 |
+
1>` and every still shifts up -- deriving the map a second time is exactly the
|
| 1995 |
+
drift the `hop_ords` comment warns about. The identity filter requires
|
| 1996 |
+
`fully_preserved`, which `refs.py` already defaults subject-bearing refs to, so
|
| 1997 |
+
ordinary face plates are untouched and only garment and setting plates stop
|
| 1998 |
+
being called people. And the closer points clothing at the plate when one is
|
| 1999 |
+
actually present.
|
| 2000 |
+
|
| 2001 |
+
Hop 1 escaped all of this because `subject_prose` runs there, which is
|
| 2002 |
+
precisely why the report said "anything but the first hop".
|
| 2003 |
+
|
| 2004 |
+
The same shape turned up a third time while writing this. The author's
|
| 2005 |
+
reference *clip* has always gone in as `<Video 1>` with nothing naming it --
|
| 2006 |
+
`_live_cite` covers the pinned tail, which is a different video. Same failure
|
| 2007 |
+
mode, same fix: a description field, and a note printed when a clip is wired
|
| 2008 |
+
without one. It is gated on the field being filled and asserted as such, so no
|
| 2009 |
+
existing workflow has its prompt quietly rewritten by upgrading.
|
| 2010 |
+
|
| 2011 |
+
The lesson is not about pinning. It is that an uncited reference is not
|
| 2012 |
+
neutral. A Ref2VA model handed a photograph and no reason for it will find a
|
| 2013 |
+
reason, and the reason it finds is "render this".
|
| 2014 |
+
|
| 2015 |
+
## 38. Fifteen tuples, of which the formula gets nine (2026-09-03)
|
| 2016 |
+
|
| 2017 |
+
The output canvas was a hand-authored table: five resolution labels by three
|
| 2018 |
+
aspects. Adding eight more aspects would have made it fifty-five, so it became
|
| 2019 |
+
a function -- mirroring core's `adapt_canvas`, nearest 32 per axis, under the
|
| 2020 |
+
`768*1344` cap.
|
| 2021 |
+
|
| 2022 |
+
The interesting part was checking it against what it replaced. I predicted the
|
| 2023 |
+
formula would reproduce thirteen of the fifteen old tuples and wrote that into
|
| 2024 |
+
the plan. It reproduces nine. Two cells I had done in my head were simply wrong
|
| 2025 |
+
-- `sqrt(200000/1.7778)` is 335.4, which rounds to ten 32-blocks and not eleven
|
| 2026 |
+
-- and I had also forgotten that every landscape divergence has a portrait
|
| 2027 |
+
twin.
|
| 2028 |
+
|
| 2029 |
+
Six diverge, all in the 16:9/9:16 column, and the pattern says why: that column
|
| 2030 |
+
was hand-tuned for ratio fidelity rather than derived from area. 1280x736 is
|
| 2031 |
+
1.739:1, closer to 16:9 than the 1344x736 (1.826:1) the area allows. So the old
|
| 2032 |
+
table was not sloppy; it was optimising something else.
|
| 2033 |
+
|
| 2034 |
+
They are pinned rather than recomputed, because width and height are in
|
| 2035 |
+
`chain_salt`: resolving them differently would re-render every chain a 1.0.x
|
| 2036 |
+
user has on disk *and* change the pixels of a graph they already signed off.
|
| 2037 |
+
`check_canvas.py` asserts both halves -- that the six stay pinned, and that the
|
| 2038 |
+
other nine still need no pin. A compat shim nobody re-checks becomes a bug the
|
| 2039 |
+
moment the thing it was shimming moves.
|
| 2040 |
+
|
| 2041 |
+
I also tried a small grid search to beat per-axis rounding on ratio fidelity.
|
| 2042 |
+
Weighting ratio twice as heavily as area took the worst ratio error from 3.3%
|
| 2043 |
+
to 2.1% and pushed the worst area error from 2.7% to 3.8%, and produced
|
| 2044 |
+
identical sizes for 16:9 at every rung. Not worth diverging from core's
|
| 2045 |
+
arithmetic for. Matching `adapt_canvas` exactly is worth more than a point of
|
| 2046 |
+
ratio error on one cell, because the two agreeing is a property somebody can
|
| 2047 |
+
rely on.
|
| 2048 |
+
|
| 2049 |
+
Separately: `media._mp_cap_size` rounded reference stills to a multiple of 16
|
| 2050 |
+
on the stated grounds that "that is H3's canvas grid". It is not.
|
| 2051 |
+
`CANVAS_MULTIPLE` is 32; 16 is the VAE's spatial factor, a different number
|
| 2052 |
+
that happens to divide it. Core re-snaps every reference to 32 on the way in,
|
| 2053 |
+
so nothing wrong ever reached the model -- the only casualty was that the size
|
| 2054 |
+
printed in the log was not the size the encoder saw, which is the one job that
|
| 2055 |
+
rounding has. `check_waveform.py` asserted the wrong number and had been
|
| 2056 |
+
passing on it since it was written.
|
| 2057 |
+
|
| 2058 |
+
## 39. Four thousand lines with nothing in front of them (2026-09-03)
|
| 2059 |
+
|
| 2060 |
+
There is no Node in this environment and no build step in this pack, so `js/`
|
| 2061 |
+
had no check of any kind between an edit and a browser. That matters more than
|
| 2062 |
+
it sounds: the browser reports a bad import as a node with no editor, which
|
| 2063 |
+
looks exactly like the pack failing to load, and the console line is one
|
| 2064 |
+
`console.warn` among ComfyUI's own.
|
| 2065 |
+
|
| 2066 |
+
`tools/check_ui.py` is not a parser and does not try to be. It checks four
|
| 2067 |
+
things that have gone wrong or could go wrong silently: delimiters balance per
|
| 2068 |
+
file; every named import resolves to a real export in the file it names; every
|
| 2069 |
+
`var(--h3-*)` the stylesheet reads is declared in it; and no rule targets a
|
| 2070 |
+
class the JS never sets.
|
| 2071 |
+
|
| 2072 |
+
It found three things on its first run, before it had checked any new code.
|
| 2073 |
+
`--h3-line` was read in two rules and declared nowhere, so the trim bar's and
|
| 2074 |
+
the draft list's borders had been resolving to nothing. `--h3-fg` fell back to
|
| 2075 |
+
a literal `#fff` that no longer matched the palette. And two classes had rules
|
| 2076 |
+
but no setter -- `.h3e-drag-over`, left behind when the drop target was renamed
|
| 2077 |
+
`.h3e-drop`, and `.h3e-card.h3e-dragging { opacity: .45 }`, which is feedback
|
| 2078 |
+
the stylesheet was clearly written for and the drag reorder was never wired to.
|
| 2079 |
+
The first is deleted; the second is now wired.
|
| 2080 |
+
|
| 2081 |
+
Its own first run also caught a bug in itself, which is the honest way to
|
| 2082 |
+
calibrate one of these: the import scan ran against the string-stripped source,
|
| 2083 |
+
and the module specifier of an import *is* a string literal, so it found zero
|
| 2084 |
+
imports and reported success. The "something was actually imported" assertion
|
| 2085 |
+
exists because of that, and it is the more valuable line -- a checker that
|
| 2086 |
+
silently checks nothing is the failure mode every checker has.
|
| 2087 |
+
|
| 2088 |
+
## 40. The range that only had one end (2026-09-03)
|
| 2089 |
+
|
| 2090 |
+
`render_through` has stopped a chain after N hops since 0.4. There has never
|
| 2091 |
+
been a way to start at one, so re-rendering shot 5 of an eight-shot chain meant
|
| 2092 |
+
re-rendering shots 1 through 4 first, or accepting a chain that began at 5 with
|
| 2093 |
+
nothing before it.
|
| 2094 |
+
|
| 2095 |
+
The obvious implementation is to seed `prev_imgs`, `prev_audio`, `prev_sampled`
|
| 2096 |
+
and `prev_key` from the hop store before the loop starts. `HopStore.get`
|
| 2097 |
+
already returns all four, so it is maybe fifteen lines.
|
| 2098 |
+
|
| 2099 |
+
It is the wrong fifteen lines. The cache-hit branch inside the loop already
|
| 2100 |
+
carries exactly those four forward, and a second implementation is a second
|
| 2101 |
+
thing to get subtly wrong -- the sampler latent especially, which is what
|
| 2102 |
+
decides whether the next hop joins by Motion-Context or falls back to the
|
| 2103 |
+
weaker AddGuide pin. Getting that wrong produces a chain that renders fine and
|
| 2104 |
+
joins badly, which is the hardest class of bug to attribute.
|
| 2105 |
+
|
| 2106 |
+
So `render_from` truncates nothing. The leading hops run through the loop like
|
| 2107 |
+
any other hop and are simply *required* to hit the cache; a miss names the hop
|
| 2108 |
+
and says why it might be gone. One code path carries continuity, and it is the
|
| 2109 |
+
one that was already carrying it.
|
| 2110 |
+
|
| 2111 |
+
Two things fell out of writing the guards. Every misconfiguration is refused
|
| 2112 |
+
before the master tensor is allocated, which on an 8x15s plan is ~31 GB -- the
|
| 2113 |
+
first draft checked `hop_store is None`, which meant the check sat after the
|
| 2114 |
+
allocation, so a typo cost 31 GB before being told it was a typo. And the
|
| 2115 |
+
inverted-range check has to run against the *original* `render_through`,
|
| 2116 |
+
because `n` has already been truncated to it by then: testing `start_at > n`
|
| 2117 |
+
first reported "past the end of the plan" for `from=5, through=2` and then
|
| 2118 |
+
rendered the whole thing.
|
| 2119 |
+
|
| 2120 |
+
The cache change shipped alongside is the one that will be felt more.
|
| 2121 |
+
`chain_salt` digested every wired reference chain-wide, so swapping the file
|
| 2122 |
+
behind `@outfit` moved hop 1's key even when `@outfit` rides only hop 5 -- and
|
| 2123 |
+
the key is chained, so that re-rendered everything. References are keyed per
|
| 2124 |
+
hop now, from `base_images`, which is the right set on both paths: this hop's
|
| 2125 |
+
scheduled stills when there is a ref plan, every wired reference when there is
|
| 2126 |
+
not, and the pin frame it excludes is already covered by `prev_key`.
|
| 2127 |
+
|
| 2128 |
+
And the nine-reference ceiling turns out to be per *encode*, not per plan,
|
| 2129 |
+
while the check counted the whole rail. Twelve references at three per shot
|
| 2130 |
+
across four shots was refused against a limit no shot came near.
|
|
@@ -444,7 +444,7 @@ Before you answer, check every one of these:
|
|
| 444 |
and the wardrobe plate is `partially_copy`.
|
| 445 |
- [ ] Every subject in `subjects` is claimed by a ref, and has both a `name`
|
| 446 |
and a `locked`.
|
| 447 |
-
- [ ] `refs` holds at most 9 entries in total.
|
| 448 |
- [ ] Dialogue uses single quotes.
|
| 449 |
- [ ] Both blocks are valid JSON: no trailing commas, no comments, no smart
|
| 450 |
quotes, plain ASCII, and no field outside the lists above.
|
|
|
|
| 444 |
and the wardrobe plate is `partially_copy`.
|
| 445 |
- [ ] Every subject in `subjects` is claimed by a ref, and has both a `name`
|
| 446 |
and a `locked`.
|
| 447 |
+
- [ ] `refs` holds at most 9 entries in total. (The encoder's real limit is 9 on any ONE hop, so a whole list of 9 can never breach it.)
|
| 448 |
- [ ] Dialogue uses single quotes.
|
| 449 |
- [ ] Both blocks are valid JSON: no trailing commas, no comments, no smart
|
| 450 |
quotes, plain ASCII, and no field outside the lists above.
|
|
@@ -431,7 +431,7 @@ Before you answer, check every one of these:
|
|
| 431 |
and the wardrobe plate is `partially_copy`.
|
| 432 |
- [ ] Every subject in `subjects` is claimed by a ref, and has both a `name`
|
| 433 |
and a `locked`.
|
| 434 |
-
- [ ] `refs` holds at most 9 entries in total.
|
| 435 |
- [ ] Dialogue uses single quotes.
|
| 436 |
- [ ] Both blocks are valid JSON: no trailing commas, no comments, no smart
|
| 437 |
quotes, plain ASCII, and no field outside the lists above.
|
|
|
|
| 431 |
and the wardrobe plate is `partially_copy`.
|
| 432 |
- [ ] Every subject in `subjects` is claimed by a ref, and has both a `name`
|
| 433 |
and a `locked`.
|
| 434 |
+
- [ ] `refs` holds at most 9 entries in total. (The encoder's real limit is 9 on any ONE hop, so a whole list of 9 can never breach it.)
|
| 435 |
- [ ] Dialogue uses single quotes.
|
| 436 |
- [ ] Both blocks are valid JSON: no trailing commas, no comments, no smart
|
| 437 |
quotes, plain ASCII, and no field outside the lists above.
|
|
@@ -1,6 +1,6 @@
|
|
| 1 |
[project]
|
| 2 |
name = "comfyui-hand-tie-clips"
|
| 3 |
-
version = "1.
|
| 4 |
description = "Native MiniMax H3 Ref2VA chain: persistent references, previous-segment clip+audio pin, one queue."
|
| 5 |
readme = "README.md"
|
| 6 |
# SPDX string, not `{ file = "LICENSE" }`. The registry does not resolve the file
|
|
|
|
| 1 |
[project]
|
| 2 |
name = "comfyui-hand-tie-clips"
|
| 3 |
+
version = "1.1.0"
|
| 4 |
description = "Native MiniMax H3 Ref2VA chain: persistent references, previous-segment clip+audio pin, one queue."
|
| 5 |
readme = "README.md"
|
| 6 |
# SPDX string, not `{ file = "LICENSE" }`. The registry does not resolve the file
|