H3 Indecision Oracle (x0-jitter / blend) [experimental]
A second oracle that reads the model's doubt, not the motion
- samples
- images
- hold_map
- segments
- window_start
- window_len
- profile
- report
- comparison
- heat
The H3 Jerk Oracle decides where a de-rope slows the clip by reading motion out of a finished latent. H3 Indecision Oracle is the "what if we asked the model instead" experiment: it reads the model's own uncertainty out of two mid-schedule x0 predictions. The idea is elegant. At two denoise steps, the model has predicted a clean latent for both. Where those predictions still disagree, the model hasn't made up its mind - high jitter between x0_b and x0_a marks tokens that are still being decided. And a token the model can't commit to is exactly the kind of token that will smear later.
The mechanism
J per token = the mean over the 24 latent channels of |x0_b − x0_a|, pooled down to the (1,2,2) token grid. High J → uncertain token. The node's outputs mirror H3 Jerk Oracle exactly - hold_map, segments, window_start, window_len, profile, report - and compile through the same threshold, bridge, and ramp code, so an A/B between the two oracles differs only in the signal, never in the plumbing. Two extra outputs: comparison (a text A/B) and heat (a previewable map, overlaid on images if you wire them, or a tile atlas without).
The critical setup: it needs X0 Tap
Pass 1 must run through X0 Tap (the SAMPLER wrapper from the h3-motion-lab pack) with both steps you're differencing dumped. The validated pair is 6→12 on a 25-step schedule. And here's the trap the node shouts about: 0→1 is degenerate. The gap between the first two steps is dominated by the (1,4,4,4,4) chunk-phase ramp, not by content - it correlated at or below zero with the picture on 6 of 7 test scenes. Several shipped graphs tap 0,1,12,24; there 12→24 is the usable pair. auto_fallback (on by default) picks the nearest available pair and says so loudly; turn it off to hard-fail on a mis-tapped graph instead of silently A/Bing the wrong steps.
It is NOT a replacement
The desk study over 7 scenes found genuinely independent signal - controlling for pixel motion it still correlates +0.41 with static detail energy, and +0.51 on the quietest third of token-times. But it misses things motion catches: one fast swinging prop read motion rank 0.97 and jitter rank 0.04. The two disagree in both directions, which is the argument for blend max (the recommended experiment) rather than a straight substitution. mode gives you indecision, jerk passthrough (which reproduces H3 Jerk Oracle byte-identically when samples is wired - so the A/B is one widget, not two graphs), and the two blends.
Second trap: on masked, pinned, or repaint runs, composited token rows read as exactly zero jitter - the map becomes a picture of the noise mask, not the content. If more than 30% of token rows are exactly zero, the report says so in capitals. Believe it, and don't drive a hold map off that.
The knobs you'll actually touch: step_a/step_b, q and d_max (same semantics as the jerk oracle, defaults 0.75 and 4), mode, and - only for blend weighted w - blend_w (weight on indecision, default 0.5). detrend_phase (on) removes the chunk-phase ramp from the temporal axis; keep it on.
Installing it
Pure-Python pack:
cd ComfyUI/custom_nodes
git clone https://github.com/matlowai/ComfyUI-MAINodes
Restart, look under latent/minimax/motion. Note it needs the separate h3-motion-lab pack's X0 Tap node to feed it - that's a real dependency beyond this repo. Example graphs want ComfyUI-KJNodes too. H3 weights are community-licensed (US, EU, UK, South Korea excluded), as always.
My take: this is a research node you reach for when the jerk oracle's take doesn't match what your eyes see on playback. The jerk passthrough identity arm means it's cheap to test - one widget flip - and the author's own recommendation is that blending beats substituting.
Inputs (23)
| Name | Type | Default | Description |
|---|---|---|---|
| dump_dir | STRING | /tmp/x0_tap | X0 Tap dump_dir from PASS 1 — the same path you gave the X0 Tap (SAMPLER wrapper) |
| length | INT | 1245–3600 | world frames of the tapped clip (17k+5) |
| width | INT | 102432–8192 | — |
| height | INT | 102432–8192 | — |
| step_a | INT | 60–999 | first tapped step. 6->12 is the validated pair on a 25-step run; 0->1 is degenerate (phase ramp, not content) |
| step_b | INT | 120–999 | second tapped step, later than step_a |
| mode | COMBO | indecision | which signal drives the hold map. 'jerk passthrough' needs samples wired and reproduces H3 Jerk Oracle exactly (same knobs, same code) so the A/B is one widget. Blends operate AFTER per-source rank normalization. |
| q | FLOAT | 0.750.5–0.99 | same quantile knob as the jerk oracle |
| d_max | INT | 42–8 | peak hold count; 4 = the jerk oracle's measured sweet spot |
| ramp | BOOLEAN | true | C1 ramp shoulders — keep ON |
| samplesopt | LATENT | the same latent H3 Jerk Oracle reads. REQUIRED for 'jerk passthrough' and the blends; optional in 'indecision' mode, where wiring it only fills in the comparison report and the second heat panel | |
| imagesopt | IMAGE | optional frames to overlay the heat on. Without them the heat output is a tile atlas of the token map | |
| normalizationopt | COMBO | rank | per-source normalization before blending; rank is what the desk study validated and is the only one that makes the two scales comparable |
| blend_wopt | FLOAT | 0.500–1 | 'blend weighted w': weight on INDECISION (1-w on jerk) |
| detrend_phaseopt | BOOLEAN | true | remove the (1,4,4,4,4) chunk-phase ramp from the temporal axis. Spatial ranking is unaffected either way, but the hold map is compiled from the temporal axis, so keep ON |
| spatial_reduceopt | COMBO | mean (matches the jerk oracle) | how the token map collapses to a per-token profile. mean matches the jerk oracle's spatial mean |
| bridgeopt | INT | 80–20 | same valley-bridging rule as the jerk oracle; keep it matched when you A/B the two |
| auto_fallbackopt | BOOLEAN | true | if a requested step was not dumped, use the nearest pair that WAS (loudly, in the report) instead of failing the render. Turn OFF to hard-fail on a mis-tapped graph |
| alphaopt | FLOAT | 0.550–1 | heat overlay strength when images are wired |
| fpsopt | INT | 241–120 | only used to phrase the report in seconds |
| s_per_stepopt | FLOAT | 0.000–120 | seconds per step from a baseline render of this clip; 0 skips the minutes estimate |
| est_stepsopt | INT | 181–100 | steps the regen pass will actually run (total_steps x inject) |
| overhead_sopt | FLOAT | 6.70–600 | fixed non-sampling seconds per render (setup, VAE encode/decode). 40 measured at 1.5 MP on a warm instance; take it from the gap between your own 1-step and 2-step wall times |
Outputs (8)
| Name | Type | Description |
|---|---|---|
| hold_map | STRING | — |
| segments | STRING | — |
| window_start | INT | — |
| window_len | INT | — |
| profile | STRING | — |
| report | STRING | — |
| comparison | STRING | — |
| heat | IMAGE | — |