feat(minimax-h3): dropdowns for canvas size and frame count - #82
Merged
Conversation
lstein
requested review from
JPPhoto,
Pfannkuchensack and
blessedcoolant
as code owners
August 9, 2026 17:18
lstein
force-pushed
the
minimax-h3/13-dimension-presets
branch
2 times, most recently
from
August 9, 2026 18:34
5f70a0a to
b747761
Compare
lstein
force-pushed
the
minimax-h3/12-turbo-lora
branch
from
August 9, 2026 21:50
c07729f to
d414bdc
Compare
lstein
force-pushed
the
minimax-h3/13-dimension-presets
branch
from
August 9, 2026 22:10
b747761 to
f0fab83
Compare
lstein
force-pushed
the
minimax-h3/12-turbo-lora
branch
from
August 9, 2026 23:37
d414bdc to
b3fefce
Compare
Adds a target_resolution dropdown with two presets: - '768 highres' (default): the released canvas policy — short edge 768, soft area cap 768x1344. Identical to the node's previous behavior. - '768 lowres': pins the LONG edge to 768 instead, yielding roughly half the pixels for non-square ratios (2:3 -> 512x768 instead of 768x1152) for fast preview/test renders. Both presets round to the 32-pixel grid the H3 nodes require and share the 1:4-4:1 aspect validation. The bundled First Frame to Video workflow pin moves to 1.1.0 with the default preset. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The denoise node's Number of Frames was a free integer that had to land on the video VAE's 17n+5 grid; a mistyped value only surfaced as a validation error once the graph was already running. It is now a choice list of every legal count from 90 (3.75 s) through 345 (14.38 s), defaulting to 124, plus the 5-frame block the still-image path uses. Labels show the duration. The accepted floor for video moves from 124 (the released 5 s training window) to 90, so short test renders are possible; validate_num_frames enforces the same range for hand-authored graphs. Choice values are strings because that is the only enum shape both workflow editors render as a dropdown; the node converts to int at invoke time. An import-time assert keeps the Literal in sync with the computed grid. Node version 1.2.0 -> 1.3.0; both bundled H3 workflows repinned. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adversarial review of the dropdown found that a workflow saved before 1.3.0 keeps num_frames as a number through the editor's recursive node update, and the enum instance schema rejects it - the field then rendered as nothing at all, with no way to fix it from the UI, and enqueue 422'd. Adds a node migration alongside migrateImageCollectionInputValues that converts a stored count still on the offered grid and falls back to the template default otherwise. Wired into both paths that rebuild nodes from a template: updateNode (saved workflows) and graphToWorkflow (workflows recalled from an older session's graph metadata). Also from the review: drop the now-inert integer-field-config form settings the two bundled workflows carried for this field, make the 5-frame label consistent with the others, and show ui_choice_labels in the canvas workflow panel's enum select (it rendered raw values). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
lstein
force-pushed
the
minimax-h3/13-dimension-presets
branch
from
August 9, 2026 23:38
f0fab83 to
f5f4c1e
Compare
… vendored module packing.py is vendored from the diffusers MiniMax-H3 branch and is kept byte-identical to upstream apart from the absolute-import rewrite, so that re-syncing when a tagged diffusers ships these classes is a clean copy — see the vendoring note in invokeai/backend/minimax_h3/__init__.py. This branch had added MINIMAX_H3_MIN_VIDEO_FRAMES, MINIMAX_H3_VIDEO_FRAME_CHOICES and resolve_lowres_canvas_size to it, and refactored the released resolve_canvas_size to share a new _validated_aspect_ratio helper, which means the next sync stops being a copy and becomes a manual re-application. Those four move to a new first-party module, invokeai/backend/minimax_h3/presets.py. resolve_lowres_canvas_size repeats the aspect validation rather than sharing it, since factoring it out is what required editing the vendored function in the first place. packing.py is restored verbatim from main. transformer_minimax_h3.py and autoencoder_kl_minimax_h3_audio.py had also drifted here — one rewrapped line each, no semantic change. They predate the [tool.ruff.format] exclude that landed with the model-support PR, so `ruff format` reflowed them on this branch; both are likewise restored from main. That exclude is also narrowed from an `invokeai/backend/minimax_h3/*.py` glob to the five vendored files by name. The glob was correct when everything in the package was vendored, but the package now holds first-party modules (presets.py, sampling.py, denoise.py, int8_convrot.py, ...) that must stay formatted — and would silently stop being formatted under the glob. Verified: all five vendored files now differ from huggingface/diffusers@abc5e9bf71 by import lines only; 314 passed, 13 skipped; ruff check and ruff format clean. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Four conflicts, all where this branch and main changed the same H3 validation surface. pyproject.toml: main carries the [tool.ruff.format] exclude as a directory glob over invokeai/backend/minimax_h3/. This branch narrows it to the five vendored files by name, because the package now also holds first-party modules (presets.py, sampling.py, denoise.py, int8_convrot.py) that must stay formatted — the glob would silently stop formatting them. Kept the narrowed list. sampling.py, minimax_h3_denoise.py, test_sampling.py: main added validate_canvas and its tests while this branch restructured the same imports and turned num_frames into a choice list. All resolved keep-both. validate_canvas stays alongside the new dropdowns for the same reason this branch keeps validating num_frames — a hand-authored graph can bypass the dropdown, and should fail with a named error rather than deep in the VAE. MINIMAX_H3_MIN_DURATION became an unused import: this branch replaces the 5 s duration floor with a frame-count floor (MINIMAX_H3_MIN_VIDEO_FRAMES = 90, 3.75 s, for fast test renders), so validate_num_frames no longer references it. Removed. Vendored check: the five minimax_h3 files still differ from huggingface/diffusers@abc5e9bf71 by import lines only. Verified: 4706 passed / 120 skipped backend; 1747 frontend tests; all five frontend lint tasks; ruff check + format; schema regenerated from the merged source; 14/14 bundled workflows carry current node versions. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two MiniMax H3 node-parameter changes, both turning constrained numeric fields into dropdowns so an invalid value cannot be typed in the first place.
1. Ideal Dimensions: resolution presets
A
target_resolutionpopup onminimax_h3_ideal_dimensions(1.0.0 → 1.1.0):Both presets share the 1:4–4:1 aspect validation (extracted into
_validated_aspect_ratio; the highres path is line-for-line unchanged) and round each axis to the 32-pixel grid every H3 node requires.2. Denoise: frame count as a grid-aligned dropdown
num_framesonminimax_h3_denoise(1.2.0 → 1.3.0) was a free integer that had to land on the video VAE's17n+5grid; a mistyped value only surfaced as a validation error once the graph was already running. It is now a choice list of every legal count from 90 (3.75 s) through 345 (14.38 s), defaulting to 124, plus the single 5-frame block the still-image output mode uses. Labels show the duration ("124 frames - 5.17 s").The accepted floor for video moves from 124 frames (the released 5 s training window) to 90, so short test renders are possible;
validate_num_framesenforces the same range for hand-authored graphs. Choice values are strings — the only enum shape both workflow editors render as a dropdown — and the node converts to an int at invoke time. An import-time assert keeps theLiteralin sync with the computed grid.Compatibility. A workflow saved before 1.3.0 stores
num_framesas a number, which the new enum template rejects. A node migration (alongside the existingmigrateImageCollectionInputValues) converts a stored count that is still on the grid and falls back to the default otherwise; it is wired into both paths that rebuild a node from its template —updateNodefor saved workflows andgraphToWorkflowfor workflows recalled from an older session's graph metadata. Deliberate tradeoff: an integer edge intonum_frames(e.g. aniteratesweeping clip lengths) is no longer type-compatible — that is inherent to making the field a choice list.Review
Both commits went through fresh-context adversarial review.
The presets diff came back clean: ~340k integer aspect pairs brute-forced against five invariants (32-grid, long edge pinned at exactly 768, area within the cap and never above the highres result, no orientation inversion) with zero violations; the highres refactor verified byte-identical including NaN/inf and boundary-ratio exception paths.
The dropdown review found one real defect and several nits, all fixed in the follow-up commit:
InputFieldRendererreturnsnullwhen the instance fails the enum schema, leaving the user no way to fix it before the enqueue 422. Fixed by the migration described above (the codebase's documented rule is that a merge which would produce an invalid node needs either a major bump or a migration hook).integer-field-configform settings for the field (inert, but stale) — dropped.ui_choice_labels— now shows the labels (generic fix, newly visible for this node).Verified-and-held attacks worth recording: the validator's accept/reject verdict changed for exactly two inputs over −50…500 (90 and 107, both intended); every value the linear UI's duration slider can produce is in the enum; pydantic does not coerce
124→"124"for a strLiteraleven in lax mode (so nothing silently passes); and both generated artifacts are byte-identical to what CI's recipes produce.Testing
pnpm test:no-watch1728 passed (incl. three new node-migration tests),lint:tscand eslint clean.ruff@0.11.2 format --checkandruff checkclean; schema.ts and openapi.json regenerated per the CI recipes.🤖 Generated with Claude Code