Commit Graph
4 Commits
Author SHA1 Message Date
SiandClaude Opus 5 3aade6f361 Let several text stages share one named look
A picture with a title, a caption and a credit meant typing the same
font, size and colour into every text stage, and changing the look meant
typing them all again. A project now holds named styles: a stage follows
one, and editing it moves every stage that follows it at once.

The front-ends learn nothing effect-specific. A ParamSpec can be marked
.styled(), saying a style carries it rather than the stage, and
Effect::styleKind() names the pool it comes from -- so styleSpecs(kind)
is to a style what params() is to a stage, and a second text-ish effect
would slot into the styles that already exist. The look is what a style
carries; the words and the placement stay on the stage, which is what
lets two stages share a typography in two different corners.

stageValues() resolves one in a single place, and a stage keeps a full
set of values of its own beside the style, so switching it to Custom,
dropping the style, or opening the project in a build that does not know
it renders exactly the same picture. A style moves stages together; it
never holds the only copy of anything.

The command line builds no styles and passes none, so it renders what it
always did.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 21:55:55 +02:00
SiandClaude Opus 5 eb417bb41a Let a chain stage be switched off without taking it apart
Trying a stage out meant removing it and building it again from scratch,
settings and all, to see what the picture looked like without it. A stage now
carries an `enabled` flag and can simply be switched off: it keeps its place
in the chain and everything it was set to.

`enabledStages` is the one place that reads the flag, and renderChain,
chainNeedsSources, chainTitle and chainSlug all go through it. A disabled
stage is skipped whole — handed no image and drawing nothing from the shared
rng — so switching one off renders byte for byte what the chain rendered
before that stage was added, which is the only thing that makes the switch
worth anything while comparing. Whichever stage runs first is the one handed
the sources, so disabling a leading scanlines lets blur lead and the chain
needs no images at all. The status line and the generated file name follow
too: they name what was rendered, not what sits in the sidebar. A chain with
every stage disabled throws rather than quietly rendering nothing.

In the interface it is a check on the chain row: the row dims, the params
heading says "(off)" and the settings stay editable — a stage being worked on
is not the same as one being deleted. On the command line it is
`--disable NAME`, which picks its stage by effect name exactly as the params
do. A project writes `"enabled": false` only for a stage that is off, so
existing project files are unchanged and an ordinary one stays uncluttered.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 21:11:17 +02:00
SiandClaude Opus 5 4739d39a51 Let effects declare whether they need source images
Whether an effect works from the loaded photographs is now part of the
declarative plug-in contract, next to params(): Effect::needsSources()
defaults to true, and blur — which only softens what it is handed — says
no and blurs an empty canvas when given nothing.

Only the first stage of a cascade ever sees the sources, so
chainNeedsSources() just asks the first stage. Both front-ends gate on
that instead of on "are there any images": the CLI only refuses an empty
batch when the chain wants one, and the interface renders a blur-led
chain with no images loaded, saying whichever thing is actually missing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-18 15:49:16 +02:00
SiandClaude Opus 5 89985cb989 Cascade effects through a chain
renderChain runs a list of stages in order: stage 0 works on the loaded
sources, every later one on the output of the stage before it, so blur
after scanlines softens the scanlines rather than the photographs. The
effects themselves are untouched — none of them knows whether its input
came from disk. All stages share one Rng and run in sequence, so a seed
still reproduces the cascade byte for byte.

The sidebar grows an "Effect chain" list: add a stage from a menu built
from the registry, reorder it, remove it, and edit the selected stage's
params underneath. Each stage keeps its own values. The CLI takes the
same chain from repeated -e, with every flag going to the stage whose
effect declares it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-18 15:21:29 +02:00