The floor sat at 0.25 MP, so 16:9's cheapest entry was 768x432 — and that
one is K2-only (432 % 32 = 16), leaving 1024x576 as the smallest H3-legal
16:9 in the list. An audio-only H3 render wants 512x288, the n=1 lattice
point at alignment 32, where the video canvas is pure overhead.
Dropping PRESET_MIN_MP alone re-picks the geometric thinning and silently
drops labels — 3:2 1152x768 and 1920x1280 among them — which breaks saved
workflows, since the label string is what a graph stores. Raising
PRESET_MAX_ENTRIES to 11 in the same step absorbs that: 79 -> 87 entries
with every existing label still present and still pointing at the same
size. The six entries beyond 512x288 / 288x512 are lattice points the old
9-entry cap had been skipping over.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1sGVWw5KU3GD7CrhdZR7M
Model guides quote megapixels in the built-in node's 1024^2 unit, so a
value copied straight across is 4.86% short here. ComfyUI's MiniMax H3
tutorial is the live case: its "0.98 MP" is 1.03 real MP, and the
1344x768 it produces is 7:4, not the 16:9 it is offered under.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017wbEdyZBPqUP2KNC5K9YoH
The mark shipped as an opaque 400x400 square, which reads as a hard tile
on the Manager's pack card. The frontend's PackBanner draws the icon
twice into a 7:3 box: once bg-cover plus blur(10px) at opacity-30 as a
backdrop, once object-contain on top. bg-cover crops to the centre and
zooms about 2.3x, so it samples mostly glow and lifts the surround to
~47, while the contained copy still shows the icon's own near-black
corners at ~17. Measured off a card screenshot, that is a 26-34 level
step at the tile edge; the same measurement on rgthree-comfy, whose icon
is a transparent SVG, is 2-3 levels.
Alpha now comes from luminance, which is the right derivation for
artwork that is additive glow on near-black, and it removes the edge
outright. Checked against a local reimplementation of PackBanner that
reproduces the screenshot's tile corners exactly.
The trade is that the pale mark washes out on ComfyUI's light theme.
Taken deliberately: the dark theme is the common case, and it is what the
comparable packs do. A dark backing disc was the alternative and reads as
a grey blob on light instead.
No version bump. The registry stores the icon URL rather than the bytes
and the Manager hotlinks it, so replacing the file on main restyles every
card; only a changed URL would need a republish. Also worth recording:
Banner is deliberately still unset, because PackBanner resolves
banner_url || icon, so a banner replaces the mark instead of sitting
behind it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015p88qHFcfungDkCbG1n7z2
[tool.comfy] Icon gets the raw GitHub URL for the assets/icon.png added
in the previous commit. It is already live on main and serving 200, so
the registry has something to resolve the moment this lands.
The version bump carries no functional change and exists only to deliver
the icon. icon is node-level metadata that the registry writes as a side
effect of publishing a version -- comfy-cli sends it inside the node
object of POST /publishers/{id}/nodes/{id}/versions -- and an existing
version cannot be re-pushed, so a bump is the only way an icon reaches a
node that has already published.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015p88qHFcfungDkCbG1n7z2
Registry and ComfyUI-Manager cards for this node render with no icon --
[tool.comfy] Icon has been empty since the first publish, and the API
agrees ("icon": ""). Next to the other three dreevelle node packages,
which are equally empty, that reads as four unaffiliated anonymous
entries rather than one publisher's set.
assets/icon.png is the creator mark already used across sites, authored
for the Alora project. It goes in unchanged apart from a downscale to
the registry's 400x400 square maximum, done in linear light: the naive
sRGB-space resize dulls the ring stroke and blurs the bar separations
inside the D. Kept full colour at 79KB rather than quantised to 23KB,
because 128 colours band visibly across the dark glow halo. The mark is
identical across all four packages; the node name and description
already tell the cards apart, and sameness is the point of a publisher
mark.
The asset lands in its own commit, ahead of the pyproject bump that
references it. The registry stores the URL rather than the bytes, and
raw.githubusercontent.com serves a brand-new path through a CDN that can
briefly 404, so having it on main first removes the race. assets/ stays
out of .comfyignore and ships in the archive -- that file is scoped to
dev-only files, and a brand asset is not one.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015p88qHFcfungDkCbG1n7z2
Moves the actionable part above the ~60 lines of rationale. Covers the
basic wiring, that either empty-latent node works (comfy/sample.py's
fix_empty_latent_channels repeats an all-zero latent out to the model's
channel count), what the megapixels/label outputs are for, and three
concrete pipelines: Krea 2 stills downscaled to 1080p, H3 video with the
2048x1152-vs-1536x864 trade-off, and a Krea 2 Edit character reference
fed at native resolution with no downscale on that branch.
Adds a "when to use the other two nodes" note, since the preset node is
an alternative to Resolution Selector rather than a stage before it --
chaining them is meaningless, as the selector takes a ratio and a budget
rather than dimensions.
The old "Wiring it up" subsection now points at Usage and keeps only the
ffmpeg delivery detail. Also fixes the header diagram's box border, which
was one column short of its content.
Verified: every "ratio · W × H · MP · TAG" string quoted anywhere in the
README resolves to a real generated preset; box borders equal width; both
cross-link anchors exist; all 69 megapixel-table rows still re-derive
through the solver. Docs only -- no version bump, so this does not
republish.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CdgKVDqEbD14EJ4RC3GPmg
With exact_ratio on, the valid outputs are a discrete lattice, so the
continuous megapixels input advertises precision that does not exist and
pushes the lookup table out of the node and into a sticky note beside the
graph. This adds a third node that is a single combo of 79 known-good
resolutions, each labelled
16:9 · 2048 × 1152 · 2.36 MP · K2+H3+SDXL
with the trailing tag derived from divisibility (grid 16 / 32 / 64), not
a hand-kept table.
The list is generated at import time by build_presets() from the same
lattice_step() the solver uses, so it cannot disagree with solve_exact().
Per ratio it picks the coarsest grid still yielding six sizes: 1:1 has
L=16 and would otherwise contribute 105 near-identical entries, whereas
the coarse grid lands it on canonical squares (512 ... 2048). Coarse
ratios like 16:9 fall through to grid 16 and keep their full set.
Additive only — ResolutionSelectorMP and ResolutionAlignToGrid are
untouched and remain the escape hatch for custom ratios and for sizes
off the preset list.
Verified: ruff clean; comfy node validate passes; all three nodes
register; all 79 presets checked for exact ratio, 16-grid alignment,
correct compat tag, correct megapixels, label/value agreement and
execute() round-trip — zero problems, labels and sizes both unique;
existing solver anchors and all 69 README table rows unchanged.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CdgKVDqEbD14EJ4RC3GPmg
The working tree was symlinked into custom_nodes for pre-publish testing.
Manager's remove/replace path runs shutil.rmtree on the resolved path, so
it deleted the target's contents rather than unlinking the symlink --
wiping this tree, .git included. Recovered by re-cloning; nothing was
lost because everything was pushed.
Updates the local-environment section to describe the post-publish
arrangement (Manager install under the lowercase registry id) and to
require tearing down any dev symlink before touching Manager.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CdgKVDqEbD14EJ4RC3GPmg
Generating on the exact-ratio lattice and downscaling beats generating
at the delivery size and cropping. 1920x1080 is exactly 16:9 and so is
every lattice row, so the whole table resizes onto it with no crop --
1920x1088 is the only entry needing one, being the only non-16:9 size.
Downscaling is also supersampling, which a 1:1 render plus a trim isn't.
Filter choice measured on a zone plate against an antialiased reference:
lanczos wins (RMSE 0.00298 at 0.9375x), bicubic second. Notably `area`
is ~10x worse than bicubic despite the usual "area is the downscale
filter" advice -- that only holds for large reductions; a box filter at
a non-integer factor near 1 weights unevenly. Documents lanczos's 8-bit
quantisation in comfy/utils.py and when it matters.
Recommends ImageScale over ImageScaleBy: identical code path, but
scale_by's 0.01 step rounds four of seven lattice factors to sizes that
aren't 1080p, and a pinned delivery size is correct for every row
without edits while a hardcoded factor is correct for exactly one.
Adds wiring for both models and the alignment=32 simplification (legal
on Krea 2 and H3 simultaneously).
All 79 table rows verified by parsing them back out of the README:
megapixel rows re-derived through the node, crop rows checked for exact
16:9 and uniform scale, ImageScaleBy rows confirmed to actually produce
the wrong sizes claimed. Zero mismatches.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CdgKVDqEbD14EJ4RC3GPmg
Sweeps to ~4 MP in both modes, in real megapixels.
Exact-ratio tables list the complete lattice (256n x 144n at alignment
16, 512n x 288n at 32) -- there is nothing valid between the rows.
Area-target tables cover 0.2-4.0 MP in the independent-rounding mode for
when a pixel budget matters more than a perfect ratio.
Also adds a portrait/landscape ratio table at ~2.36 MP and per-model
guidance on which row to pick: Krea 2's sanctioned band tops out at
2.36 MP (2048x1152), H3's native canvas is 1.03 MP with 1.33 MP
(1536x864) the highest row worth running by default.
All 69 rows verified by parsing them back out of the README and
re-deriving each through solve_exact / solve_nearest: zero mismatches,
every row on-grid, every exact-ratio row satisfying w*b == h*a.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CdgKVDqEbD14EJ4RC3GPmg
Two nodes addressing distinct problems with ComfyUI's built-in
Resolution Selector (comfy_extras/nodes_resolution.py).
ResolutionSelectorMP
Core computes `megapixels * 1024 * 1024`, so every target is inflated
4.86% in area: 2.36 MP at 9:16 yields 1184x2096 = 2.48 real MP. This
uses 10^6.
Core also rounds each axis onto the grid independently, which drifts
the aspect ratio (that same result is 0.5649, not 0.5625). With
exact_ratio on, this solves instead on the lattice of sizes that are
simultaneously grid-aligned and exactly on-ratio: for a reduced ratio
a:b and alignment m those are (a*L*n, b*L*n) where
L = lcm(m / gcd(a, m), m / gcd(b, m))
9:16 at m=16 gives the lattice 144n x 256n, and n=8 lands on
1152x2048 -- exact 9:16, on the grid, 2.36 MP. solve_nearest()
preserves core's behaviour behind exact_ratio=False for when the
lattice is too coarse.
ResolutionAlignToGrid
Snaps arbitrary dimensions onto the grid (1920x1080 -> 1920x1088),
with round/up/down.
Alignment is vae_spatial_downscale * dit_patch_size, verified against
the ComfyUI source rather than assumed: 16 for Krea 2 (Wan21 inherits
spacial_downscale_ratio 8, patch 2), 32 for MiniMax H3
(spacial_downscale_ratio 16, patch_size (1,2,2)), 64 for SDXL/SD1.5.
Off-grid dimensions get circular-padded by
comfy.ldm.common_dit.pad_to_patch_size -- the pad row is a wrapped copy
of the top of the image, folded into the same patch token as the real
bottom row, which decodes to a band of artifacts along the bottom edge.
Padding is only ever appended, so the artifact is never top/left.
Verified: ruff clean; both schemas construct and both execute() paths
run; a 4000-case fuzz over random ratio/alignment/target triples asserts
w % m == 0, h % m == 0 and w*b == h*a (zero ratio drift); core's formula
reimplemented and reproduces the observed 1184x2096 exactly.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CdgKVDqEbD14EJ4RC3GPmg