The button now clears the wizard, applies the cleared state to the builder,
and closes the modal in one click.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Bug: after "Clear all" + "Apply", the builder's photo (or art_style) field
stayed filled. applyToBuilder computed kind=null when both were empty and
skipped the style block entirely, leaving the builder's previous value.
Fix: mirror the wizard exactly — when both are empty, set the builder's
"style" combo to "none" (its DynamicCombo drops the photo/art_style
sub-widget, actually clearing it), matching how the builder's own
applyCaption handles a style-less import.
Also add a "Clear & apply" button (clears the wizard and pushes the cleared
state to the builder in one click).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Bump the Pick-tab status text 11px -> 13px and color the not-connected
warning red (bold) instead of orange, so it reads clearly.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
An extra ")" in the parsePresets() error-message concatenation closed the
string early and left a dangling token, so web/js/ideogram4_style_wizard.js
failed to parse as an ES module. The whole extension never registered:
the node showed its raw wizard_data widget with no "Open Style Wizard" button.
`node --check` on the .js false-passed; validated now as strict ESM (.mjs)
and via a mocked import()+onNodeCreated harness (button is added again).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Bump version to publish the Overview right-click "Move to root" item (and everything since 1.0.1).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The context menu gains a "Move to root" item that unparents the right-clicked node (or the whole
selection if that row is part of it) — a discoverable alternative to dragging onto the header.
Disabled when nothing in the target is nested. The node's subtree comes with it.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Set the Comfy Registry publisher to "littlegod", bump to the first release version 1.0.0, and point
the registry Banner at the repo's banner asset.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The lock condition was "(effectively off) && (not own-disabled)", so a child that was ALREADY
individually disabled stayed clickable after the group was disabled — and clicking it merely flipped
it into the locked state. Lock now keys purely on whether a parent group is off (ancestorOff), so
once a group is disabled ALL its children are consistently 🚫 + non-toggleable until the group is
re-enabled.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The per-row eye reflected only the box's OWN state, so children under a disabled group still showed
👁 even though they were hidden everywhere. Now the eye shows EFFECTIVE visibility: a child of a
disabled group reads as 🚫, faded and non-toggleable (the group is the master switch — flip it to
show them again). The whole disabled row dims for a clear hidden look.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The enable toggle was a tiny native checkbox at the left of each Overview row — easy to miss on the
dark dock. Replaced it with a clear button: 👁 when enabled, 🚫 when disabled (click to toggle),
styled like the other row buttons.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Each region and group row in the Overview gets an enable checkbox. Disabling a box (or a group —
which cascades to all its members) hides it from the canvas AND excludes it from the exported prompt,
the bbox output, and the preview render. Still listed in the Overview (dimmed) so it can be re-enabled.
- JS: isDisabled(b) walks the parent chain (own or any ancestor disabled); applied in the canvas draw,
hit-testing, and buildCaptionObject (so token estimate reflects it too). Row checkbox toggles
b.disabled and commits; effectively-disabled rows render dimmed. State persists + round-trips via
the _ai2go sidecar / workflow.
- Python: _eff_disabled(box, by_id) mirrors the cascade; skips disabled in execute (elements + bboxes)
and in _render_preview.
JS + Python parse clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Move AI2Go-Banner.jpg and How-It-Works.jpg into assets/.
- README: banner at the top, how-it-works image in the node section.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Add .github/workflows/close-prs.yml — politely auto-closes any opened/reopened pull request
(pull_request_target, no PR-code checkout, so it's safe for fork PRs).
- README: note up front that issues are disabled, PRs are auto-closed, no support/contributions,
and that forking under GPL-3.0 is welcome.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Documents the region editor, the Overview scene tree, parenting, named groups (hide/show, scale,
duplicate, mirror), and the _ai2go copy/paste interop. Strengthens the GPL-3.0 credit to Kijai /
ComfyUI-KJNodes as the base of the Ideogram 4 editor.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
If a JSON containing the _ai2go sidecar is wired into import_json (always mode), the node passed it
straight through to the `prompt` output. Strip _ai2go from the emitted caption so the model prompt
stays clean; the full imported caption (with _ai2go) is still mirrored to the editor via ui.caption,
so hierarchy/groups still restore in the editor.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copy and templates now emit the clean caption PLUS an "_ai2go" sidecar holding the full editor box
list (groups, parenting, ids, names, collapse/lock). Paste/import/template-load restores from it when
present, so AI2Go→AI2Go round-trips losslessly. KJNodes (and the model) ignore the unknown key, so:
- AI2Go → KJ: pastes as a normal flat scene.
- KJ → AI2Go: no sidecar → imports flat (as before).
- AI2Go → AI2Go: hierarchy + groups fully preserved.
The sidecar is added only when there's hierarchy/groups to keep (plain scenes stay clean). The Python
`prompt` output and the token estimate use the clean caption — the sidecar is clipboard/template-only.
JS parses clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Duplicate: derive the shift delta from the copy's actual bounding box (not the group frame, since a
member can protrude after individual editing) and apply one uniform delta with no per-clone clamp, so
the copy's internal layout is preserved exactly. Falls back to a negative shift when the group is
pinned to an edge (no more copy-on-top-of-original).
- Mirror: skip whole LOCKED sub-branches as a unit (collect members without crossing a locked box) so a
nested sub-group frame and its children always mirror together; clamp the whole reflected interval
(keeps box size, stays on-canvas) instead of one edge; validate the axis.
JS parses clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Three buttons in a selected group's panel:
- Duplicate: clones the group and its whole subtree (fresh ids, parents remapped within the copy,
shifted slightly so the copy is visible and stays on-canvas; copy is editable).
- Mirror ⇆ / Mirror ⇅: flip the group's members left↔right / top↕bottom about the group's frame
(frame unchanged). Locked and unplaced members are left as-is.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Previously a group frame could be resized but it did nothing to the children. Now resizing a
group's frame (corner/edge handle) scales its placed children proportionally about the same anchor
edge — reusing the existing group-resize transform. Skips locked sub-branches and unplaced (nobbox)
children. Resizing a normal region is unchanged (children don't scale). Show frames with 👁️ first
to grab a group's handles.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Toolbar button icon is now 👁️ (lit/active = group frames visible).
- Group frames are HIDDEN on the canvas by default (showGroups defaults off; only `true` shows them).
Click 👁️ to reveal them. Groups remain in the Overview tree at all times and are never exported.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- New 📁 toolbar button toggles on-canvas visibility of group frames (node.properties.showGroups).
When off, group frames aren't drawn and aren't grabbable on the canvas — but groups still appear
in the Overview tree. State persists and is restored on load. Groups are never exported regardless.
- Dragging a multi-selection in the Overview now shows live feedback WHILE dragging (not just on
release): every dragged row fades, and a small pill follows the cursor showing "N regions → <target>"
(the group/region you're about to drop onto, or "→ root"). Cleared on drop/cancel/teardown.
JS parses clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Locked rows no longer reparent (lock = frozen): pointerdown bails on a locked row, and locked
boxes are filtered out of a multi-selection drag.
- Drop cue only highlights a target when at least one dragged box would actually change parent
(no more misleading blue ring over a box's current parent).
- Trailing-click suppression now fires only when a reparent actually happens, so a tiny accidental
drag that lands on nothing no longer eats the row's click.
- Keep _selAnchor in sync after a multi-reparent so a later Shift-click range starts correctly.
JS parses clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Headline (requested): dragging a row that's part of a multi-selection now reparents the WHOLE
selection — drop it onto a group to add all selected regions at once, or onto the header to send
them all to root. Only the selection's top-level boxes move (internal nesting preserved); cycle-
guarded against dropping onto any dragged box or a descendant. The moved boxes stay selected.
Group-review fixes:
- Major: selecting a group showed the region editor; its bbox fields silently detached the group
from its children. Groups now get a dedicated panel (name + frame color only) — no bbox fields.
- Moving a parent/group no longer places its UNPLACED (nobbox) descendants (which would alter the
export); only directly-selected boxes get placed on a drag.
- Groups no longer reserve a phantom number badge / invisible title hotspot (tagRects + titleAt skip them).
- Locked groups now show the tight frozen dash + a 🔒 glyph.
- Groups can't be duplicated into orphans (startPlacing/copySelection skip them; ⧉ hidden on group rows).
JS parses clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Right-click the Overview → "Create group from selection" wraps the selected regions in a new,
named **group**. Groups are editor-only organizers — never exported to the caption.
- A group is a box with `group:true` + `name`, parented over the selection (its bbox = the
selection's union + a small margin so its dashed frame is grabbable). Only the top-level selected
boxes are reparented, so internal sub-hierarchies are preserved.
- Move the group on the canvas → the whole group moves (Phase-2 propagation). Drawn as a dashed
named frame; shown in the Overview tree with a 📁 label and a collapse triangle.
- Double-click a group's Overview row to rename it.
- Deleting a group keeps its children (they promote to the group's parent) — already how delete works.
- Excluded from export in BOTH the editor (buildCaption) and the Python node (execute elements,
bbox output, and preview render), so the Ideogram caption stays a flat list of real regions.
JS parses clean (ES module); Python parses clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- The region panel is now titled "Overview" (with a tooltip describing the gestures); README updated.
- Overview rows: Ctrl/Cmd-click toggles a row in/out of the selection; Shift-click selects the
range from the anchor to the clicked row in displayed (tree) order. Plain click still single-selects
and sets the range anchor. Selection is shared with the canvas, so multi-selects show + move there.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adversarial review of the hierarchy change found three real bugs + polish:
- Major: keyboard Delete (removeSelected) dropped a deleted parent's children to ROOT, while the
per-row ✕ promoted them to the grandparent. removeSelected now promotes orphans to the nearest
surviving ancestor (skipping co-deleted parents), matching the ✕ behavior.
- Major: a cycle or self-parent (possible via a hand-edited/imported save) silently hid regions
from the tree — ensureParentsValid only nulled MISSING refs. It now also nulls self-parents and
breaks cycles by cutting the back-edge, so every box stays reachable from a root.
- Major: dragging a parent tore apart a locked sub-branch — a locked intermediate box stayed put
but its children still moved. Move-group build now skips locked boxes AND their whole subtree.
- Minor: snap-then-clamp could overflow the canvas by a grid cell (now reachable via single-parent
drag); snap first, clamp last so the clamp always wins.
- Minor: setParent now returns false when the parent is unchanged (no churn commit), and the drop
cue skips the box's current parent.
- Minor: clear any prior _exDragCleanup before a new row drag (no leaked listeners on overlap);
clear the click-suppress flag on consume.
JS parses clean as an ES module.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Editor-only parent/child hierarchy on top of the stable ids — never reaches the exported caption
(Python ignores unknown box fields).
- Data: each box gets an optional `parent` (another box's id). Helpers: boxById, isAncestor,
descendantIds, setParent (rejects self/missing/cycles), ensureParentsValid (drops dangling refs
to root on delete/import; runs in serialize()).
- Move propagation: dragging a box on the canvas moves its whole subtree (children follow). Resize
affects only explicitly-selected boxes — children don't scale. Locked descendants stay put.
- Object Explorer is now a tree: indentation by depth, per-parent ▶/▼ collapse (persists on the box).
Drag a row ONTO another to nest it (cycle-guarded, live drop highlight); drop on the "Regions"
header to send it back to root. Trailing-click after a reparent is suppressed.
- Delete promotes a box's children to its parent (no surprise subtree wipe).
- Paste/duplicate clear parent (become roots) so clones never carry stale parent ids.
- Z-order stays independent of hierarchy (still reorder via the right-click region menu).
JS parses clean as an ES module.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adversarial review of the Phase 1 change surfaced one real bug + polish:
- Major: drag-reorder called commit() -> renderExplorer(), which cleared the list and destroyed
the row whose _dragged guard was just set, so the trailing click wasn't suppressed and fired a
spurious re-select. Drag-end now repaints in place (serialize/renderPanel/drawCanvas/tokens)
without rebuilding the list — mirrors the right-click region menu.
- Leaked listeners: explorer drag binds document-level pointer listeners; store _exDragCleanup and
call it from onRemoved so a mid-drag node deletion can't leak them.
- Resizer stayed draggable while collapsed (silently mutating explorerW); hide it when collapsed.
(Also reordered the init call so applyExplorerCollapsed never references exRsz before it exists.)
- scrollIntoView fired on every commit; now only scrolls when the active row is actually off-view
and the rail isn't collapsed.
- startPlacing (duplicate from the list) now refreshes the explorer immediately.
- Hardened .ai2go-ideo-cv with explicit min-width:0; widened resizer max-clamp by the divider width.
JS parses clean as an ES module.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Object Explorer: a persistent, collapsible rail left of the canvas listing every region
(number, color swatch, label, lock, duplicate, delete, drag-reorder). Click a row to select
a region — two-way synced with the canvas — so regions can be picked and edited from the list
without dragging them by accident. Width + collapsed state persist in node.properties.
Stable IDs: each box gets a makeUUID() id (stamped in serialize via ensureIds; regenerated on
paste/duplicate). Editor-only groundwork for parenting — Python ignores unknown box fields, so
the id never reaches the exported caption.
JS parses clean as an ES module.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Set the GitHub repository URL (pyproject + README clone) and the publish
workflow's owner gate to Little-God1983.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Port the Ideogram 4 Prompt Builder node and its visual bbox editor from
ComfyUI-KJNodes (GPL-3.0, by Kijai) into this pack, fully renamed so it can
coexist with KJNodes if both are installed:
- nodes/ideogram4_nodes.py class/node_id/display_name -> AI2Go*, category AI2Go/text
- web/js/ideogram4_prompt_builder.js extension name, CSS id + 'kjideo-' prefix -> 'ai2go-ideo-',
CSS vars '--kj-dock-' -> '--ai2go-dock-', template dir -> ai2go/ideogram4
- web/js/utility.js shared helpers the editor imports (sibling module)
- fonts/FreeMono.ttf preview font
- __init__.py registers AI2GoIdeogram4PromptBuilder
GPL-3.0 attribution headers added to each derived file. Python + JS syntax verified.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>