Commit Graph
1349 Commits
Author SHA1 Message Date
digital-garbageandClaude Opus 5 33aaa1b883 fix(models): expose Studio's positive_conditioning; ignore dead pass-throughs
A CONDITIONING output had no port to reach in guided mode. It wires explicitly
only — it replaces the typed prompt. An unwired pass-through no longer counts as
a source, which had made every CLIP consumer read as ambiguous.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 19:46:31 +03:00
digital-garbageandClaude Opus 5 65814fa590 fix(models): H3's image-to-video latent had nowhere to wire
Studio's latent port does not exist in this family, so the node could be added,
filled in and never connected. Its LATENT and keyframe CONDITIONING now reach the
sampler, with a test that every open core input stays reachable in both families.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 19:30:40 +03:00
digital-garbageandClaude Opus 5 614ce0a196 feat(models): the LoRA loader gets a real picker; advanced inputs fold away
Rows are picked from a searchable list of installed files instead of typed into a
table of dropdowns, and an input the node calls advanced (the trained stack) is
folded away unless something feeds it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 19:29:35 +03:00
digital-garbageandClaude Opus 5 e93ad88ec8 fix(models): a new project starts as FunPack's loaders, not as the last import
An imported workflow was copied into every new project, so a fresh wizard setup
handed the user third-party loaders to wire. It now seeds FunPack's own and
carries the picked files across; an audio VAE feeds the audio latent too.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 19:25:45 +03:00
digital-garbageandClaude Opus 5 eb78f35a1e fix(sampler): sweep leaked hooks below the blocks; log a hook census per run
v2a scale and bounded attention install on attn2 / video_to_audio_attn, which the
block-only sweep never reached and never tagged. The census prints what is still
installed before sampling, so a count that grows is proof rather than a hunch.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 19:14:24 +03:00
digital-garbageandClaude Opus 5 aa08b909f3 feat(models): seed the LoRA loader; empty list passes the model through
Empty is a working state now, logged as "No active LoRAs", so the hop every
LoRA needs is already wired into a fresh pipeline.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 19:09:33 +03:00
digital-garbage 41bba44b54 feat(models): a new project starts as FunPack's loaders, already wired
Seeded server-side on first read, once, per family — plus the family's own plumbing, so
nothing required is left to wire by hand. A seed never reaches the global default, which
would replace configured loaders with empty ones. Wizard and node picker follow.
2026-08-20 19:01:59 +03:00
digital-garbage 8d4a199e1f feat(sampler): second pass and segmented detailing on any model family
Both were switched off on H3 because Lightricks' upsampler is 128-channel — a fact about
the file, not the family. They now load any upsampler ComfyUI can (core's loader handles
the rest), refuse a mismatched one by name, and never download the LTX file for H3.
2026-08-20 18:38:36 +03:00
digital-garbage 1efa4ce5b2 feat(models): list inputs, loaders pinned to the top, auto-rewire on remove
A funpack_list widget renders as rows with Add/reorder/remove instead of raw JSON.
Loaders sit in a pinned section above everything else; imported workflows fall back to
what a node outputs. Removing a node joins its neighbours, the way ComfyUI's delete does.
2026-08-20 18:32:35 +03:00
digital-garbage 3837f8fc95 feat(loaders): FunPack diffusion/CLIP/VAE loaders; LoRA loader works alone
Quantization + a per-model attention backend read from ComfyUI's own registry, so only
installed ones are offered. The LoRA loader now takes its own list and scores wrapper
prefixes against the model's key map, instead of applying a diffusers LoRA as a silent no-op.
2026-08-20 18:20:16 +03:00
digital-garbage 9d15a2726f feat(models): bypass a whole group; fix bypassing connected nodes
The group button just sets the per-node bypass every card already has. The builder was
judging each node against a graph still holding its doomed siblings, so it refused any
bypass of connected nodes and left chains pointing at deleted ones — an output read only
by other leaving nodes needs no pass-through, and a leaving consumer needs no repair.
2026-08-14 23:54:22 +03:00
digital-garbage f3c8e33f47 feat(models): node groups and search
Groups come from the workflow's own group boxes and from each subgraph's name, so what
the author organised survives import. A group is a VIEW — nodes stay flat, every wire
keeps its real endpoints, there is no inside to navigate into. Search covers class, label,
widget names and values (model files) and socket types; it overrides folds.
2026-08-14 23:45:15 +03:00
digital-garbage b6163e9070 fix(import): resolve KJNodes Set/Get instead of importing them as nodes
They exist only in web/js/setgetnodes.js — no Python class — so the frontend resolves
them away and emitting one queues a type the backend has never heard of. Links are
re-pointed past each pair; a Get with no Set leaves the input unwired rather than dangling.
2026-08-14 23:24:08 +03:00
digital-garbage 36501d5aa2 fix(import): expand subgraphs instead of importing the uuid as a node class
A subgraph instance's type is a uuid from definitions.subgraphs, so every node inside it
was lost and the graph queued a class ComfyUI has never heard of. Boundary links are
rewired both ways, and promoted widget values win over the inner node's stale copy.
2026-08-14 23:19:53 +03:00
digital-garbage ec90c19d2f feat(models): missing requirements are a compact list above the grid
One line each with a + on the right, dismissible (persisted, returns as a one-line link).
Satisfied, optional and the guided-wiring rules fold away.
2026-08-14 23:11:14 +03:00
digital-garbage e1a907a93b fix: redirect the legacy /movie and /easy API prefix, not just the page
Old frontends build their API base from location.pathname, so a page left open on the old
URL polled /funpack/<old>/api/health, got 404, and sat on "Reloading ComfyUI" forever —
never reaching the reload that would have hit the page redirect.
2026-08-14 23:01:40 +03:00
digital-garbageandClaude Opus 5 58a2a24f10 feat(simple): Simple mode turns off refinement, and nothing else
The strip list had grown a second and a third justification — "cross-shot" and
"experimental / expensive" — and those were decisions about what is worth someone's time,
made for them. Eleven settings came off a run that way, none of them hidden, so the
controls stayed on screen and did nothing.

Now it strips refinement only: the five rating-driven sampler knobs, the Studio refiner
keys, and the per-sampler velocity bias / rescue that replay a rated bank. Those cannot
work here — there is no rating UI to feed them. Cross-shot memory, guides, ALG, bounded
attention, identity transfer, segmented detailing, the plateau cache and context windows
all run as configured.

The lists now mirror the frontend's own gates, and a test reads engine_settings.js to
hold them in step: stripped-but-visible is a control that lies, hidden-but-live is the
same lie inverted.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 20:26:31 +03:00
digital-garbageandClaude Opus 5 831de6e325 fix(simple): the second pass works in Simple mode again
Easy Gen loaded the same engine_settings.js and posted to the same endpoint with no
simple flag, so it always allowed the second pass. Simple mode stripped it because
"costs real time for a quality bet" got written into the rule, which is not a reason —
that is the user's call.

The rest of the strip list stands on a rule that actually holds: a setting belongs there
only if it CANNOT work in this mode — a no-op without a trained key (there is no rating
UI), or a relationship between shots (there is one shot). The second pass is neither. It
needs no rated history and no second shot, and upscaling a single shot is one of the
main things the mode is for.

The switch was on screen the whole time: Simple hides only the rating-gated knobs, so
Enable, the schedule and the between-pass operation all rendered and were then ignored.
Until this morning the run report that said so was being discarded too.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 03:31:41 +03:00
digital-garbageandClaude Opus 5 39ce5f7891 fix(builder): a linked input that doesn't fire says so
Linked inputs failed in silence. A link whose member names a node that was replaced, or
a widget renamed out from under it, wrote nothing — the node kept its own value, the
project setting never reached the graph, and no report line, log line or UI element said
which value won.

Each way it can fail is now reported, in a new `ignored` bucket: a value the user SET
that did not reach the graph. That is its own class — the run is valid, it just isn't
the one they configured — so it is kept apart from `unsatisfied`, which is mostly
routine.

The editor was discarding the build report entirely, so every line the builder already
wrote (including the anchorless-scene and Simple-mode notes) went nowhere. `ignored` now
raises the timeline notice, and the links that DID fire are logged to the console with
their values, so a setting can be confirmed without reading the queued prompt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 02:40:00 +03:00
digital-garbageandClaude Opus 5 43bf9f1939 feat(editor): the project's Frames wins over a length the timeline gave a shot
A resize, trim or split moved a shot off project length as a side effect of a drag, and
nothing moved it back. Editing Frames now resets those shots to follow it.

Custom is the exception, and the same one the rest of the app already makes: a shot set
to Custom is locked against timeline resize too. It is the one length typed on purpose,
so the warning above the field is now only about those — with the button to fold them in
as well.

Quiet patches record no history (they fire per keystroke), but this one discards work,
so it takes one undo point. Only the first keystroke of a burst finds anything left in
timeline mode, so the stack gets one entry, not one per character.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 02:31:11 +03:00
digital-garbageandClaude Opus 5 bf73835e3b fix: wiring survives a project load; Frames says when it reaches nothing; anchor survives upscale_2x
Three unrelated reports.

Wires lost or "(not allowed)" after loading a project. /api/pipeline-ports read the
family from the GLOBAL models.json, so it described whichever project was saved last.
Open one on the other family and its saved wires point at ports that family has no rule
for. It takes ?pid= now, and the panel asks for the config before the rules that depend
on it. Reconcile also dropped a port wire when core_overrides named a deleted slot — it
cleared every other slot's wire to that port, then failed to add the replacement.

Guided mode also filtered harder than the builder validates. A node added through
"Any node…" has role `custom`, which no rule table mentions, so a custom VAE loader
could not reach the pipeline at all. A role with no rule for an output type now reaches
any port of that type; a role that HAS one keeps it, and internal links stay closed.
Both sides read the same list, since the panel hiding what the builder accepts is what
produced "(not allowed)".

Frames / scene silently missed shots. Any timeline resize, trim or split moves a scene
off project length for good, and nothing said so — typing 305 and rendering 450 read as
the edit being ignored. The Project panel now says how many shots it doesn't reach and
offers to put them back. The panel's fingerprint had to learn about scene state, or the
warning outlived the fix.

second_pass_op=upscale_2x no longer drops the i2v pin. The pinned frames in the upscaled
latent ARE the anchor — carried through the same upsampler as the rest of the clip — so
only the mask needed scaling to the new grid. Pass 2 at 4x the pixels was the run most
likely to drift off the reference, and it was the one running unpinned. The pin now
holds the upscaled anchor rather than the encoded source image, and the report says so.
Guide keyframes are still dropped: those are token indices, not pixels.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 02:24:53 +03:00
digital-garbageandClaude Opus 5 b56900b499 fix(refiner): follow the encoder instead of assuming Gemma3
LTX-2.5 encodes with Gemma4 where 2.3 used Gemma3. Concept steering finds a phrase
by matching its token ids inside the prompt's, so a tokenizer from the wrong family
still returns spans — pointing at the wrong tokens. Nothing raises; steering just
stops working.

The tokenizer now comes from the connected CLIP, which is by construction the one
that produced the conditioning. The download stays as the fallback for runs with no
CLIP, and says so rather than claiming to be Gemma3.

Learned state is stamped with its encoder and cleared when that changes, on both the
V1 and V2 paths. Clearing reuses Session Reset so the value function, x0 snapshots
and the keyless Absolute store go with it instead of being orphaned. An unstamped
key is adopted, never wiped: every key predating this has no stamp.

The vision probe no longer depends on the submodule being called gemma3_12b — it
still is on 2.5, where it holds Gemma4.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 20:03:37 +03:00
digital-garbage a458e1222f feat(ui): Simple mode is one prompt; shorter long-form hints
Assets and Properties stop being pinned in Simple mode. They become slide-overs
on the same zones — not rebuilt, not duplicated — reached from Media and
Advanced settings, and closed by their own ✕, Escape, or a click on the preview.
The preview then fills the window over one big prompt bound to the global
prompt, so split markers and the Composer still agree.

Hint audit: 113 of 126 user-facing strings were already a sentence or two. The
twelve that were not are rewritten — what it does, what it costs, when it does
nothing — the longest dropping from 1749 characters to 440.
2026-08-13 15:22:52 +03:00
digital-garbage 1b8ae08b08 feat(sampler): second pass gets an Enable switch; shorter hints
The pass was derived from whether the schedule field had content, so turning it
off meant deleting a schedule you wanted to keep. It has its own checkbox now
and the schedule is just configuration; enabling without one is reported rather
than silently ignored.

Trims the second-pass and ALG hints from four paragraphs to a sentence each.
The long-form detail stays behind the Details link, which is what it is for.
2026-08-13 15:15:58 +03:00
digital-garbage 8e3e23252f fix(wizard): ask for the mode after model selection
It sat second, before the project even existed. It belongs near the end, once
the pipeline is set up and the choice is about how much of the app to show.
2026-08-13 15:06:52 +03:00
digital-garbage 0a38ddbb48 feat: Simple mode switches the enhancements off
Simple mode is no longer presentational. A run made in it strips rating-driven
steering, cross-shot memory, experimental sampling and the second pass, and the
scene report says so. The set lives in one place, pipeline_caps.SIMPLE_MODE_*,
and is applied to a copy: the project keeps whatever the Editor set, so
switching back restores it.

Switching to Simple warns once what will be off. The wizard asks for the mode
up front and says it can be changed later.

Fonts: the About facts and the length readout drop monospace for tabular
figures, which is how Apple sets a spec list; what genuinely stays monospace
(log, prompts, node classes) moves to JetBrains Mono.
2026-08-13 14:58:28 +03:00
digital-garbage 957c562c95 fix(ui): trim the inspector in Simple mode; drop stale route references
Simple mode no longer renders the engine strip or the split preview (with its
sync-scenes button). The Project/Scene switch stays: it is the only route to
frames, fps, resolution and the t2v/i2v mode, so hiding it would have cost
function rather than clutter. Exposed node controls stay too — those are knobs
the user chose to surface.

Removes a dead .insp-tabs rule that never matched anything (the control is
.insp-switch), and the last /funpack/movie references, which were all comments
and docs.
2026-08-13 14:44:06 +03:00
digital-garbage 9ecdb7e07c feat: one app at /funpack/
The editor moves from /funpack/movie/ to /funpack/, taking its API to
/funpack/api/*. The frontend needed no change — api.js already derives its base
from the page's own path. /funpack/movie/ and /funpack/easy/ redirect there;
they are registered before the static catch-all, which would otherwise swallow
them, and after the /funpack/refinement_keys and /funpack/batch routes, which
still win by registration order.

Deletes hub.py and the easy_gen package: the hub picked between two apps that
are now one, and every Easy Gen frontend file was either a duplicate of an
editor file or a second way to do something the editor already does.

window.FunPackAppName went with them, so the three gates that read it —
models.js, sampler_panel.js, onboarding.js — now read the mode instead, live
rather than once at load. The wizard drops its second host table.
2026-08-13 14:38:47 +03:00
digital-garbage 5ca34a9b1d feat(ui): Simple mode keeps the Media Bin
The Media Bin IS the gallery, so Simple mode shows the same one the Editor does
rather than hiding it behind a second, parallel screen. Nothing to port from
Easy Gen's gallery.
2026-08-13 14:27:38 +03:00
digital-garbage 8ca4c1b0e3 feat(ui): Simple ⇄ Editor mode switch
Easy Gen becomes a mode of the editor rather than a second app. FunPackMode
stamps data-ui-mode on <html>; Simple hides the timeline, assets, dock tabs,
Composer, scene-selection and Auto Montage, and the rating-gated Studio and
Chain Sampler settings. Nothing is disabled and no state is dropped — switching
back shows everything as it was.

The transport bar moves to the preview header in Simple mode instead of being
rebuilt, so a running generation's timer keeps writing to the same buttons
across a switch.

The mode is folded into every ViewBus fingerprint, in one place rather than per
zone: each zone builds different content per mode, and without it a switch left
the old copy on screen.

First stage of the merge. Routes, the hub, and the easy_gen frontend still
stand; the inspector still shows its full field set in Simple mode.
2026-08-13 14:23:13 +03:00
digital-garbage b28071bca2 fix(ui): node shelf fills its row; light preview stage isn't black
The shelf capped tiles at 168px, so a pane wide enough for three but not four
left a dead strip down the right. Tiles now take 1fr and stretch to fill the
row — safe because the art is a fixed height, where an aspect-ratio would have
made a wide column a tall one too.

The preview letterbox stays black behind real video in both themes, but an
empty or generating stage is just a panel: in the light theme it was a black
rectangle with slate text and a vignette.
2026-08-13 14:13:28 +03:00
digital-garbage db70062bb7 feat(ui): one start screen, and chrome in the system face
The welcome card is gone. The full-screen splash is the start screen for both
frontends, shown whenever nothing is open — Begin, the last project, the full
project list (with import), and the maintenance actions. "Load an existing
project" now opens a picker inside that surface instead of handing off.

Chrome type follows Apple's conventions: group headers, field labels, tabs,
segmented controls, lane names and status chips are sentence-case system sans,
sized on the scale, with no letter-spacing. Monospace is now reserved for data —
timecodes, counts, paths, prompts, node classes — which is what it was doing in
the timeline ruler all along. Zone padding moves onto the 4pt grid.

Scene length/fps modes read "Project default" / "Timeline trim" instead of
labels too long for their control.
2026-08-12 19:56:10 +03:00
digital-garbage 457136ca68 feat: t2v mode, a type scale, Inter, and 4.0.0
t2v: projects carry generation_mode ("i2v" default). In t2v nothing checks or
reports a missing anchor, and a new scene starts empty rather than from an
image. Images stay wireable either way — the mode decides what is expected, not
what is allowed. Switchable any time in Project settings; the wizard writes it.

Scaling: one type scale (Apple's macOS text styles) replaces ~64 off-grid sizes
like 11.5px, body drops 14 → 13, and buttons/fields/menu items take their height
from shared control tokens instead of per-component padding. Fixes the timeline
zone head overlapping the panel above it: its status block wraps, and a fixed
34px height let it spill both ways.

Node cards carry their name and destination ON the tile instead of captioning it
from below, and no longer print the class twice. The add-node list flips above
the card when it would run off the bottom.

Fonts: Inter (open, Helvetica/SF-alike) with system-ui behind it, Inter Tight
for display, Roboto Mono for mono. Apple ships SF free but licenses it for work
on Apple platforms only, so it cannot be bundled.

Also: "Continue with <project>" on the wizard splash, and About reads
FunPack 4 "Blinding Blackout" 4.0.0.
2026-08-12 19:43:39 +03:00
digital-garbage 218bf5e628 feat(wizard): tour step, one continuous surface, restart-on-abandon
Setup panes no longer hand you off elsewhere. Models, pipeline links, prompt
shortcuts and prompt splits mount as full screens of the wizard itself, with the
section's own toolbar in the header and one Done button back to the step you
came from. Same builders and editors as before — SettingsWindow.mountSection()
and Composer.mountPane() host them without the window around them.

New Tour step before the last screen: Watch tour / Skip the tour, with the tour
starting when setup finishes.

An unfinished wizard now starts over instead of resuming mid-flow. Only the
wizard's own ComfyUI restart (installing node packs) writes a resumable record;
a refresh or a closed tab does not. The project an abandoned run created is
adopted by the next one, so changing your mind leaves nothing behind.

The wizard also stops appearing when it has already been answered: loading a
project from the splash silences it for the session, and it never opens over a
project that is already open. File ▸ Project Setup Wizard (Easy Gen: Setup
Wizard…) runs it again on demand.

Renames the LTX family label to LTX2 / LTX2.3 / LTX2.5.
2026-08-12 19:18:16 +03:00
digital-garbage 5babbdda82 fix(settings): hold autosave until the Settings window closes
Every knob in Settings writes through the store, so the debounce could fire
mid-session: it sent a half-edited value and came back with a server copy that
replaced state.project, putting the knob under the cursor back where it was.

Opening the window now holds scheduled saves; closing it writes once, with the
values on screen. An explicit flush still goes through, so Generate and the
update/switch/restart actions cannot build or reload from an unsaved project.
Leaving the tab flushes too.

Also fixes the same stale-echo race in the models save path (an edit made while
a save was in flight was overwritten by the response), and makes commit() wait
for an in-flight models reload before copying it into project.models.
2026-08-12 19:06:18 +03:00
digital-garbageandClaude Opus 5 2c0b08bdee fix(models): wires onto core ports can be removed again; readable node shelf
A wire onto an open core port is recorded twice — as the slot's wire and as a
core_override — and reconcileOpenPortWiring() rebuilds each from the other. Removing
the wire cleared only the first, so the next reconcile put it straight back. That is
why "Studio · model" could not be unwired without deleting the node. _setWireTarget
now drops the override too, and only when it still names that same wire.
Confirmed both ways: with a stale override alone, reconcile resurrects the wire.

Cards now derive their name from the file the node loads, so five LoRAs read as
add-detail-xl / filmgrain_v2 instead of five nodes called "LoRA". An explicit rename
still wins. Each card also says where it feeds ("→ Studio · model"), using the same
derived names, so the shelf shows how the pipeline is put together.

Tiles are capped rather than 1fr — in a narrow pane two stretched columns made each
card ~270px tall.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 18:47:43 +03:00
digital-garbageandClaude Opus 5 ef9f7d02f7 feat(models): node shelf, and no autosave while a node is open
Nodes are a grid of cards led by a "+ New node" tile; clicking one opens that
node's editor. The sidebar keeps only the two places you can be.

The important half is the saving. Editing a node saved on every change, so a save
landing between two keystrokes wrote whatever was on screen at that instant —
start at 1.0, type 0.5, and 0.58 could reach disk with no way to tell. The editor
now buffers: config is still mutated in place (wiring edits legitimately touch
other slots' wires, so a per-slot draft could not hold them) but persist() is a
no-op until Save. Cancel restores the snapshot taken when the page opened, and
navigating away with unsaved changes asks first.

Verified: five intermediate values including 0.58 typed into a float field leave
the server on 1.0; Save writes 0.5.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 18:39:25 +03:00
digital-garbageandClaude Opus 5 9916840cb1 fix(theme): apply the colour scheme on click only
The picker previewed on hover, and preview stamped data-theme-pref as well as
data-theme. That attribute is what get() reads, so after clicking a card, hovering
another and moving away restored the HOVERED theme, not the chosen one — clicking
looked like it did nothing.

Hover preview is gone entirely: the theme now changes on an explicit click and
nothing else, which removes the ambiguity rather than patching it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 14:46:14 +03:00
digital-garbageandClaude Opus 5 03c0b2dcd9 fix(onboarding): setup panes open over the wizard instead of replacing it
The wizard sat at z-index 800, above .modal-overlay (500) and below .fw (4000),
so "Open Models…" opened behind it and did nothing visible, and the extras step
worked around that by closing the wizard first — which dropped you into a
half-finished editor. It now sits at 400: Models, Settings and the Composer layer
over it the way they layer over the editor, and closing one returns to the step.

Prompt splits called Composer.open(), which does not exist; the export is toggle().

Also: MiniMax H3 no longer pulls in ComfyUI-LTXVideo. LTXFloatToInt only converted
the project's frame rate for user slots, and H3's rate is fixed at 24 by the model,
so an LTX pack was a hard requirement of a pipeline with no use for it. Core
producers are now filtered by what the family's graph actually built.

The Cutting Room brand links to the hub, as Easy Gen's already did.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 14:41:02 +03:00
digital-garbageandClaude Opus 5 f28e57fbe3 feat(onboarding): first-run wizard for both frontends
Shape follows the macOS Setup Assistant: full screen, no chrome, one centred
column per step — glyph, headline, one short paragraph, controls — with the
primary button in a bar pinned to the bottom so it never moves between steps,
and Back as a chevron in the top-left. Type follows Apple's macOS text styles;
--font-system resolves to SF Pro on a Mac.

Splash (Welcome to FunPack / Begin / Load existing, Return advances) then:
theme, name + model family, missing node packs, t2v-or-i2v, models, optional
links/shortcuts/splits with Skip for now, ready. Steps a host runs are declared
in one table — Easy Gen has no timeline, so it never offers prompt splits.

Installing node packs restarts ComfyUI, so the wizard saves its position and
resumes there after the reload instead of starting over. Returning users still
get the project picker, not the wizard.

pipeline_setup gains applyFamily/markHandled so the wizard can drive it without
its modal reopening over the finished editor, and no longer assumes the Editor's
store — Easy Gen keeps model config on project.models and has no loadModels.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 14:28:56 +03:00
digital-garbageandClaude Opus 5 c5b2e6e48f feat(splash): Update / Switch branch / Restart on every entry screen
One shared FunPackGit.maintenanceRow(), used by the Editor's welcome screen and
Easy Gen's project menu; the hub gets the same three, with the branch list as a
select since /git/status already carries it. These are the actions you need
before opening a project, so none of them should require opening one.

Also drops the phantom "origin" entry from the branch list — refs/remotes/
origin/HEAD shortens to a bare remote name, which fails on checkout.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 14:04:01 +03:00
digital-garbageandClaude Opus 5 65976d0c26 feat(theme): light, dark and auto colour schemes
styles.css and easy.css no longer name a colour, only a role: ~250 hard-coded
literals became semantic tokens, with the dark values kept byte-identical. Light
is a white/grey/daylight-blue palette; auto follows the OS and is resolved in
theme.js, so CSS only ever sees dark|light and there is no first-paint flash.
Media letterboxes, badges over frames and the log body stay dark in both.

--amber* is now --accent*, since the accent is amber only in the dark theme.
Picker in Settings ▸ Appearance for both frontends; the hub follows the same key.

Also fixes the rating picker's rgba(var(--accent), x) rules, which were invalid
and being dropped.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 13:55:40 +03:00
digital-garbageandClaude Opus 5 5cbe20e6c9 ui(models): input sources above values, wired outputs at the bottom
Node cards and the add-node panel now read top-down in signal order.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 13:42:37 +03:00
digital-garbageandClaude Opus 5 7b84dfeebc docs: trim backstory from changelog, README, tooltips and comments
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 03:21:48 +03:00
digital-garbageandClaude Opus 5 7329cd9680 fix: multi-scene chains work with a resolution-changing second pass
second_pass_op="upscale_2x" hands a scene back at twice the latent size while
every LATER scene is still built from latent_template at the original size.
Everything that crosses a scene boundary — carried overlap frames, the anchor's
continuation, the soft join, the JoyAI memory frame, per-scene guide sources —
is spliced into a chunk on the template's grid, so the second scene died on the
shape mismatch and the combination was simply unavailable.

One choke point, _match_template_resolution, brings the carried material back
before it is used, applied at the three places a finished scene crosses into the
next one. Each scene still samples and OUTPUTS at 2x: only what is carried gets
resampled, and only downwards, which is the direction that survives it — those
frames exist to say "continue from here", which a resample preserves far better
than invented detail would.

Identity no-op when the grids already agree, so any run without a resizing op is
bit-identical. Audio has no spatial axes and is never touched. A stale
noise_mask is dropped rather than reapplied at the wrong scale, and a resample
that throws costs continuity with a console line, not the run.

No grid guard on the chain blend: second_pass and second_pass_op are run-level
settings applied to every scene, so a chain cannot hold two resolutions — every
scene is upscaled or none is. Both tooltips said this combination dropped
multi-scene; they now say how it works.

Also: About reads "FunPack 3" with the codename on its own line, rather than
attaching the major to the codename.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 00:05:52 +03:00
digital-garbageandClaude Opus 5 06c3f75080 release: 3.5.1 "Auspicious Asparagus"
Release codenames, the way Ubuntu does it: an adjective and a vegetable
sharing an initial, advancing alphabetically, one per MAJOR version — so all
of 3.x is "Auspicious Asparagus" and only a new major earns a new letter.

CODENAMES lives beside funpack_version() because the two are read and shipped
together, and rides out on the same git-status payload the About panel already
fetches. A major with no entry renders as absence, not as an empty pair of
quotes. The test pins the naming rule itself (shared initial, ascending) so a
future entry that breaks the pattern fails rather than quietly shipping.

Version 3.5.1 in pyproject; CHANGELOG entry covering the whole cycle (the
Unreleased section only documented the first few commits of it); README gains
a Versions preamble explaining the scheme plus notes for 3.5.0 and 3.5.1.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 23:55:53 +03:00
digital-garbageandClaude Opus 5 98d48e78e3 fix: cut_opening_frames cuts decoded pixels, not latents (noisy first frame)
The opening frame came out noisy because the cut was made in latent space. The
LTX video VAE is causal: latent frame 0 is the temporal origin and decodes to a
single pixel frame, while every later latent frame was generated as a
CONTINUATION of the frames before it. Slicing the front off the latent promoted
a continuation frame to position 0, and the decoder then applied the
temporal-origin handling that frame was never generated for. H3 already cut
decoded images for unrelated reasons and so never had the bug; LTX now does the
same thing.

The count was wrong too, quietly. A latent cut could only remove whole latent
frames, and the promoted frame changed from covering 1 pixel to covering
`scale`, so dropping k latent frames shortened the clip by k*scale rather than
the (k-1)*scale+1 it actually spanned. The value was also rounded up to a whole
latent frame on the way in. It is now exact: N means N, matching H3.

Each eligible scene records a (start, count) pixel span instead of cutting; the
spans are removed after decode, later ones first so earlier removals cannot
shift their indices. Mid-chain hard-cut scenes keep working — the span is
computed from the scene's position in the chain, which is exact because anchor
scenes append with zero blend overlap. The latent's audio stream loses the same
stretches of TIME, mapped by proportion on its own axis, or sound would run
ahead of picture with no error. The latent's VIDEO stream is deliberately left
whole (cutting it is the bug), so video comes from the IMAGES output — which the
Editor already wires. A run with IMAGES unconnected now skips with a reason
instead of silently doing nothing.

_cut_opening_latent is removed rather than left dead, since its docstring
documented the broken approach as correct.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 23:47:51 +03:00
digital-garbageandClaude Opus 5 e7b624d684 fix: drop guide keyframes on a resized second pass; unify the two ALG switches
Two unrelated fixes.

**Guide keyframes vs a resolution-changing second_pass_op.** Guide keyframes are
recorded as TOKEN indices into pass 1's latent grid, so upscale_2x — which
doubles each spatial dim and thus quadruples the tokens per latent frame —
leaves them addressing the wrong tokens. Since the LTX-2.5 commit core rejects
that outright ("keyframe_idxs holds N tokens, which is not a whole number of
M-token latent frames"), which is how this surfaced; older cores silently
mis-placed the guides instead, which is worse. Pass 2 now drops them and says
so in the scene report, exactly as segmented detailing already does for its
crop — so detailing's stripper becomes public rather than being duplicated. Only
pass 2 is affected; pass 1 ran at the grid the guides were recorded against and
keeps every one. The pin loss and the guide loss now share one predicate
(_latent_spatial_changed) so they cannot drift apart, and an unreadable shape
answers "no change" so a probe failure never costs a guide.

**One ALG control instead of two.** The Distilled Flow panel had its own
alg_enabled while the chain sampler's alg_anchor did the same guidance on any
sampler and already drove the Distilled Flow one when set — two switches for one
behaviour, with precedence depending on which you had touched. The Editor now
shows only alg_anchor. The node input stays for hand-built graphs; what moved is
the Editor's control. A project still carrying the old switch is migrated once,
strength and threshold included, and told so, rather than left running ALG with
nothing on screen to turn it off.

The migration is deferred out of the render pass and guarded by a module-level
set of project ids: every store write re-renders the pane synchronously, so
migrating inline recursed until the stack blew (caught in the browser, not by
the suite).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 23:39:47 +03:00
digital-garbageandClaude Opus 5 b6fa5b177d feat: About panel reports the host's hardware and software
About showed only version/commit/branch. Add the facts you actually want to
check on a fresh rental: chip, memory, GPU (name, VRAM, compute capability),
free disk, OS, ComfyUI, Python, torch (+CUDA), and which fast-attention
backend is importable — the last one answers "is sage actually installed
here" without reading the launch args.

Everything describes the machine ComfyUI runs on, not the browser. On a
rental those differ, and the host is the one worth looking at, so the panel
says so in a line under the facts.

Every probe is individually guarded and degrades to a dash: About is the one
screen that should still render when the install is broken, so no missing
psutil, torch, or shell binary may raise. The frontend optional-chains the
call, so a frontend sharing settings_window.js without the endpoint keeps the
old version-only panel instead of erroring.

Facts move to a two-column grid; values now range from "3.14" to a full GPU
name, and only a shared column keeps the keys aligned.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 23:15:30 +03:00
digital-garbageandClaude Opus 5 03158b4edf fix: two LTX-2.5 assumptions that would have failed silently
LTX 2.5 reuses LTXAVModel/LTXBaseModel behind config flags, so the samplers,
the identity-transfer wrappers and the guide path all bind to it unchanged.
Two places assumed 2.3 specifics, and both would have gone wrong quietly.

The AV channel split was a hardcoded width table. From 2.5 on comfy reads the
video/audio projection widths off the checkpoint rather than assuming them, so
a checkpoint can ship a pair the table has never seen — and an unrecognised
width made ltxav_video_channels return the FULL width, which silently steers
the audio text context along with the video one. The only symptom would have
been degraded audio. The split is now measured off the live model when one is
on hand; the table stays as the fallback.

Decode-time noise only ever reached VideoVAE.decode. 2.5's diffusion decoder
takes no timestep and seeds itself, but it is an nn.Module, so stamping the
attributes onto it succeeded and was then ignored — a knob that reads as live
and does nothing. It is now capability-tested against the real contract
(hasattr decode_timestep, not a class name) and says so when it cannot apply.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 22:36:38 +03:00