Commit Graph
4 Commits
Author SHA1 Message Date
Æmotion StudioandClaude Fable 5.1 5c28c42981 fix: let every registered shader name through the parameter whitelist
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-22 01:21:37 -07:00
Æmotion StudioandClaude Opus 5 2fed935313 feat: sample part of a schedule, so a run can be split
MiniMax H3 fixes faces with a latent upscale partway through the run, which
means splitting the generation: some steps, the upscaler, then the rest. The
sampler could only ever run a schedule end to end, so getting the upscaler in
meant dropping shader noise out of the workflow entirely.

Four inputs, the same ones KSampler (Advanced) has: add_noise, start_at_step,
end_at_step and return_with_leftover_noise. They land at the tail of the
optional block, because ComfyUI maps saved widget values by position.

The machinery was already there. The pipeline builds one sigma schedule and
samples it in segments, slicing sigmas[start:end + 1] for each; a window is
that same slicing applied once more at the outer edges. Indices stay absolute,
so the per-segment seed still comes out as seed + start -- which means a split
run draws the same ancestral and SDE noise as the unsplit one it came from.

Decisions worth naming:

- Stages spread across the steps the node actually samples, not the whole
  schedule. Two stages over a three-step window are two stages in those three
  steps; spread over the schedule, one would land outside the window and never
  fire. merge_boundaries takes the window's own edges for this, and its first
  parameter is renamed end_step to say so -- measuring the tail against the
  schedule length instead would leave a 1-step tail inside a long window.

- stage_progression keeps measuring position in the whole trajectory, so a node
  running the last three steps of seven gets the fine end of coarse_to_fine
  rather than a fresh coarse-to-fine sweep of its own.

- With add_noise off the opening boundary is not painted. The latent already
  carries its noise from whatever ran before, and the shader on a zero tensor
  would add back exactly what was turned off. Later boundaries still paint,
  since their noise is recovered from the latent rather than made here. The
  refusal for an unpaintable latent weighs only the stages that will actually
  be painted, so it no longer rejects a latent on behalf of noise nobody makes.

Two things fixed on the way:

- force_full_denoise was dead. KSampler.sample only reads it alongside
  last_step, and this code passes sigmas= with last_step unset, so it was
  discarded on every call. The window's zeroed sigma tail is what does that job
  now. The golden fixtures recorded the flag, so they are re-captured; every
  sigma, noise tensor, seed and output across all thirteen is unchanged, which
  was checked before blessing them.

- The progress bar counted the schedule rather than the steps being run.
  ProgressBar takes its total from the callback, so a windowed run would have
  started part-filled and stopped short of the end. At the defaults the numbers
  are identical to before.

A schedule with fewer than two sigmas now returns the latent instead of being
handed to the sampler, which is what denoise 0.0 builds.

Verified against comfy.samplers.KSampler itself across seven start/end/leftover
combinations, requiring the sigmas to match bit for bit -- the parity that lets
this node sit on one side of a split and a stock KSampler (Advanced) on the
other. Two golden fixtures cover the two halves. Also run for real on H3:
4 steps, latent upscale, 3 steps, 896x896x124 with audio, in the new
example_workflows/MiniMaxH3_Split_Upscale_SNK_Direct.json.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-22 00:27:18 -07:00
Æmotion StudioandClaude Opus 5 7b40c556d4 feat: expose temporal_coherent and correct the parameter tooltips
The Direct node's shader_type list offered three of the four generators this
repository ships. temporal_coherent was registered, covered by the test suite
and reachable from both the standard and legacy dispatch paths -- but absent
from the combo, so no workflow could select it. Nothing tied the advertised
list to the registry, so nothing caught it.

It is the generator best suited to video: 4D simplex with time as a real axis
rather than a per-frame redraw. On real MiniMax H3 weights it degrades far more
gracefully than the others (faint background striping at strength 0.35, where
domain_warp already shows blocking and curl_noise has heavy colour casts), and
it is the only type whose audio level stays flat as strength rises: -24.0 /
-23.7 / -23.7 dB against a -22.6 dB baseline, where domain_warp climbs to -17.0.

Two tests now pin the dropdown and the registry to each other in both
directions. The second fails on the previous list, naming temporal_coherent.

The tooltips implied the whole 0.0-1.0 strength range was usable. Measured on
H3 at 608x352 and 8 steps it is not:

    domain_warp + multiply      photoreal to ~0.25, gone by 0.75
    tensor_field                tolerates ~0.5
    curl_noise                  ~0.2, heavy colour casts by 0.5
    soft_light / difference     clean at 0.3, the gentlest blends
    add                         ~0.15, the most aggressive
    shape masks                 ~0.2; at 0.6 the mask is drawn into the picture
    use_temporal_coherence      ~0.2; 0.5 swamps the frame

use_temporal_coherence was the worst offender: it claimed to help "maintain
frame-to-frame consistency", when holding one seed across frames stops the
pattern varying between them and so reinforces it rather than averaging it out.
The tooltips now carry these ceilings, rank the blend modes by aggressiveness,
and note that the live preview only draws three of the four types.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 01:32:41 -07:00
Æmotion StudioandClaude Opus 5 3af34338ab feat: add sampling_mode and route the node to the corrected pipeline
The Direct node now dispatches: "standard" (default) runs the new pipeline,
"legacy" runs the frozen pre-2.0 one. Measured through the node with a
recording sampler, 20 steps:

  standard, 1 stage       1 call  x 20 steps, from sigma 14.61
  standard, 2 stages      2 calls x 10 steps, from 14.61 then 1.48
  standard, denoise 0.6   1 call  x 20 steps, from 2.23
  standard, 3 injections  4 calls x  5 steps, 14.61 / 3.87 / 1.48 / 0.60
  legacy,   2 stages      2 calls, each rebuilding a full schedule

The 1.48 is the fix: stages continue one trajectory instead of restarting at
maximum noise, where flow models discard the previous stage entirely. The 2.23
is denoise finally reaching the schedule.

Also on the node:
- sequential_distribution, injection_distribution and fast_high_channel_noise
  become real optional inputs. As V1 `hidden` tuple inputs ComfyUI never
  delivered them, so they were stuck at their defaults.
- the debug/visualisation hidden inputs are gone; they drove stub no-ops.
- IS_CHANGED is removed: it only restated widget values that are already part
  of the cache key, and would have rejected the new input.
- new widgets are appended last, so saved workflows keep their widget order.

web/src/sampling_mode_migration.ts switches nodes loaded from pre-2.0
workflows to "legacy", recognising them by the absence of the snk_version
property, so existing seeds keep reproducing.

186 Python tests and 85 web tests pass; the 11 legacy goldens now exercise the
legacy branch through this dispatch.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-11 15:35:14 -07:00