- PR #108 changed pyproject.toml without bumping the version, so the
registry publish on main failed with "The node version already exists".
- Bump to 1.3.0 (new node, route and override file) and add the release
notes to CHANGELOG.md and the README.
- An override family could declare a step such as 3; sizes rounded to it
are not divisible by 8, so create_empty_latent_batch raised ValueError
at execution instead of producing a latent (Codex review on PR #108).
- validate_table now rejects a step that is not a multiple of 8 with a
message naming the latent grid; the shipped steps (16, 32, 64) already
comply, and the schema docs state the rule.
- The ResizeObserver callback measured the panel and resized the node
synchronously, which forces a layout while the stylesheet may still be
applying; WebKit then reports "ResizeObserver loop completed with
undelivered notifications" as a page error, and the browser fixture
fails any test with a page error (CI WebKit job on PR #108).
- The callback now only schedules a single-flight requestAnimationFrame
that measures and refits, so no observed box changes during delivery.
- Reproduced in the pinned Playwright WebKit image: the picker tests pass
48/48 (16 tests × 3) with this change.
- New nodes started at a fixed 340×600, so one-entry size lists left a
large empty area between the list and the Swap button.
- The panel now reports its measured content height as both the minimum
and maximum DOM-widget height, and the extension sets the node height to
the host's computeSize() after every render, keeping the width.
- Hidden or detached panels are not measured, the first measurement is
retried for a few frames, and a ResizeObserver on the panel children
refits when the stylesheet arrives after the first render (the coverage
run exposed that race; a held-stylesheet regression test pins it).
- Workflows load at their saved width and are re-fitted on load; the spec
and docs describe the new sizing rule.
- edits show up on a page reload or Refresh node definitions, not on the
next node mount, because the frontend caches the payload per page
- the 14 count refers to shipped families; an override can add or remove
- workflows saved before the resolution widget load shifted by one slot
- onConfigure now maps exactly four widgets_values onto model, width,
height and batch_size and resets resolution to custom
- the host test stub applies widgets_values and calls onConfigure like LiteGraph
- table validation accepts sides 64..8192, matching the widget min/max
- parse_size_label (Python and JS) caps digits and rejects out-of-range
sizes so create() falls back to width/height instead of overflowing
- family_labels() and the combo default now read the merged table, so an
appended family is selectable and a removed one is not offered
- an alias used as the override default is normalised to its label
- the frontend rebuilds the model options from the payload and keeps a
saved family that is no longer listed so old workflows still show it
- replace the {ex} placeholder with a real override example validated against validate_table
- list the loading state among the cases that show custom
- say the override default may be a label or alias
- describe the families.json schema and the user override file with a full example
- document the warnings behaviour and resolution dropdown precedence
- add the dropdown sync rule to web/ui/README.md
- Set resolution to custom whenever the panel has no selection (wired,
failed, non-finite or loading) so a stale label cannot override width/height.
- Compute label megapixels with 1 MP = 1,048,576 px, matching the panel
header, with half-up rounding so Python and JS labels agree on ties.
- Add a native resolution COMBO (shipped sizes only) so a size can be picked
and saved in the workflow without the panel; custom or unparseable labels
fall back to width/height on both sides.
- Mirror the dropdown with the chips: options follow the active chip, the
value tracks the current size, and picking a label writes width/height.
- Draw a decorative ratio shape on each ratio chip and show the first
families warning in the status line.
- catch RecursionError alongside ValueError when loading, merging and validating
- add tests for deep nesting, remove vs families, and a default naming a removed family
- add override.py: override_path, merge_override, mtime-cached current_table
- resolve_family and families_payload consult the merged table and expose warnings
- an invalid override is ignored whole with a logged warning
- treat ints as finite instead of calling math.isfinite on them
- bound step (4096), megapixels (64) and side length (65536) with normal problem messages
- cover step, megapixels, default and size values of 10**400
- check default, labels and aliases are strings before set membership
- reject non-finite step and megapixels via a shared _is_step helper
- cover unhashable and Infinity/NaN inputs in the garbage test
- ship the table as families.json with per-family notes from the old source comments
- add table.py: load_table, pure validate_table and build_families
- families.py loads and validates at import, raising RuntimeError on problems
- include *.json as package data
- VALIDATE_INPUTS lets unknown family labels reach create()
- no size is listed under two chips; SD 1.5 3:4 gets true 3:4 sizes
- model change before the families payload loads is applied on load
- custom ratio: clear error on chip click, cap sides at 8192, accept X
- real-host assertions for model change and wired-in state
- name Flux.2 / Klein / MOSS at 1248x832 and HunyuanImage 2.1 at 2560x1536
- require saved PNG dimensions to match the node outputs, recorded in the PR
- add README tools row, section and status row
- add ui-migration row and web/ui README section
- add per-node doc with family table and manual GPU check
- extract the real-host beforeEach into tests/comfyui/host-setup.mjs and proxy /kikotools/model_resolution/ to the fixture
- add the picker spec: renderer switching, shared swap, themes, workflow reload, scope abort
- add light and dark screenshots for the docs
- render the static chip list in every state; payload only drives enabled/active
- re-derive size on model change via sizeOnModelChange
- validate custom ratio, keep last valid list, ignore repeated commits
- add swap, model change, custom ratio and route failure browser tests
- add coverage floors for the three picker files
- restore keyboard focus to the equivalent button after each render
- keep the accent background when hovering a pressed chip or size
- refresh the panel when input links change
- treat a size listed in the clicked chip as a no-op
- add resolution picker view with chip grid, size list and custom ratio input
- add extension that projects native widgets and writes sizes via callbacks
- add browser tests for rendering, theming, idempotent mount and disposal
- Treat a missing preset widget like preset value 'custom' in swapDimensions
- Keep every preset access behind the custom check
- Add a test that swaps width and height directly on a preset-less node
- add ModelResolutionPickerNode rounding to the family step
- serve GET /kikotools/model_resolution/families
- register the node in NODE_CLASS_MAPPINGS
- add CHIPS, MIRROR, Family and the FAMILIES literal table
- add family_labels, resolve_family and families_payload helpers
- cover step, ratio, mirror and sort invariants with tests
- New node: model dropdown drives a Pixaroma-style ratio chip grid and size
list, outputs width, height and an empty latent, with the toolkit Swap W×H
- Family table lives in Python and is served to the frontend by a local route
- Panel state is derived from the native model/width/height widgets only
- Video families are listed as keyframe sizes for first/last-frame generation
- Records the builder-check calls and the SDXL default
ComfyUI resizes an empty latent to the model's latent format only when the
latent carries downscale_ratio_spacial, as core EmptyLatentImage sets it.
Without it, models with 16x VAEs (Flux.2, Klein, MOSS-Image, Qwen-Image 2.1)
sampled at twice the requested width and height.