Releases: corderro-artz/nfty
Release list
v1.7.1 — the export card fits the window it is given
The export card scrolled on every tab, at every window size the app allows.
2,286 tests, 0 failures.
What was wrong
Opening Export and switching to IMAGES put the whole watermark group below the fold, cut
"Stamp each asset's set number in a corner" through the middle of its letters at the
scroller edge, and left the corner picker — the control that is supposed to say what it
does by its shape — drawn as four unexplained specks.
None of it was visible in review, because the card was being photographed 780 pixels
tall. A modal in this app is never given more than 526. So every frame of it was a
picture of a card no window hosts, and it looked tidy in all of them.
The one assertion about its height checked that the card clamps to the page it is in —
which the framework does on its own. Nothing asked whether the contents fit inside it.
What changed
Measured, the three pages want 246, 251 and 213 pixels. The shared floor said 262 and
credited that to CONTENTS; the tallest page is IMAGES.
- The head was three rows for one idea — a
• EXPORTkicker above a title reading
"Export this Set" above the tabs, 98px of a 470px card. The title and the tabs share one
row now, which is how the Set browser's own header already reads. 98 → 40. - The manifest's contents are a run, not a column. Five short phrases down five lines
spent about 80px of a pinned block on fifteen words. - The manifest is reserved at its tallest. The pages already shared one height so they
could not move it; nothing stopped it moving them. It measured 113, 145 and 130 as a
spritesheet line and a debug caveat came and went, and the card is centered — so
switching tabs grew the card and shifted every row in it.
All three tabs are now identical, the card fits the smallest window with 30px to spare,
and nothing scrolls.
The corner picker
Unarmed, it was disabled, and the app dims a disabled control to 38% — which is legible
over strong ink and invisible over a hairline and a near-black ground. Restoring the
opacity brightened the dots and still drew no cells: the edge is painted by a part of the
button template whose brush Fluent replaces in its own disabled state, so it has to be
asked for again. The cells keep their strength now and the mark carries the state.
Every capture of this card had both boxes already ticked, so no frame had ever drawn it.
Downloads
| Size | .NET 10 needed | |
|---|---|---|
| Portable | 84 MB | no — unzip anywhere and run. Start here if you are unsure. |
| Single file | 77 MB | no — one .exe. Unpacks itself on first run, so that launch is slower. |
| Single file, .NET | 14 MB | yes — one .exe, runtime left out. |
| Framework-dependent | 14 MB | yes — the same, as a folder. |
The two .NET builds need the .NET 10 desktop
runtime; the other two carry everything.
nfty 1.7.0 — spritesheets, a debug number, and a space that outgrew a long
Spritesheets, a debug number on every sprite, and a DNA space that stopped fitting in a long.
2,286 tests, 0 failures.
Two tags in one release: v1.6.0 is the large-integer audit, v1.7.0 the features on top of it.
Export as spritesheet
Every asset stitched into one image, left to right then top to bottom in the Set's own
numbering — so cell n is asset n+1, and an engine indexing frames agrees with a reader
counting rows without anything being recorded. You give it columns and rows; both boxes open
already filled with the squarest grid that holds the collection, and the pixel size sits beside
them so the two numbers explain themselves.
A short last row leaves transparent cells, because that is what a spritesheet looks like and
closing the gap would renumber every frame after it. A missing asset leaves a hole rather than
failing the sheet — a gap among drawn cells is unmistakable, which is the point.
There is a real ceiling, and it refuses with the numbers rather than dying: a sheet is one
contiguous raster, so 500 assets at 1000px in a 23×23 grid is 529 megapixels and about 2 GB of
RGBA. A refusal an author can act on beats an OutOfMemoryException half a minute in.
A set number stamped on every sprite
Loose sprites lose their filenames the moment they are dragged into an engine or a chat window,
and a folder of five hundred near-identical characters is unsortable. Tick the box, pick a corner,
and every exported asset carries its set number — so a loose sprite cross-references
nfty/NNNN.json with nothing else written down.
The digits are a 3×5 bitmap font, not a typeface. A real font would mean a new dependency
beside an ImageSharp pinned on purpose, and would put grey anti-aliased ink on art that has no
grey anywhere in it. White over a one-pixel black halo, so it reads on any ground; it declines to
draw rather than clip, because a "12" cropped to "1" is a wrong answer where a missing stamp is
merely a missing one.
It never touches your Set. The export renders a stamped copy and ships that. Stamping runs
before stitching, so the sheet carries the same numbers its sprites do.
Progress that means something
Opening a Set ran on the UI thread. That unpacks a .set into a temporary directory and reads a
file per asset, so a real collection froze the window for seconds with nothing on screen saying
why. The async path had always existed — nothing was calling it.
There is one small card for every job that has no screen of its own, and the export's bar is a
real fraction now instead of spinning whatever it was doing: a barber pole for minutes is
indistinguishable from a hang. Indeterminate survives only where the work genuinely cannot count.
The export card is three pages — CONTENTS, IMAGES, SEAL — with the manifest and the footer
outside the tabs, because what is going and what is stopping it are the two things you should
never have to go looking for. It also stopped stretching, which was costing about 230px of empty
panel on every page.
The DNA space outgrew a long
Six layers of ten variants at a 10°/10% quantize is about 2.2e21 distinct assets, against a
long's 9.22e18 — so that book's headline figure read more than 9,223,372,036,854,775,807: a
constant, printed where an author is trying to read a count. The totals are BigInteger now and
the ceiling is gone rather than raised again, along with the saturating arithmetic that
existed to keep a number inside a type too small to hold it.
The figure prints in full whenever it fits, measured against the cell at the window you
actually have — so a maximised window shows what the smallest one abbreviates — and the exact
digits are always on the tooltip. Past the named magnitudes it becomes an exponent, because there
is no name above "quintillion" that a reader knows.
Seven smaller things went with it, each probed by reverting the fix:
- A
NaNcolorization range validated clean. Every check inCheckRangeis false forNaN,
so the inverted-range test and both axis tests all waved it through. Describeclaimed "at most 1 in a trillion" on a bounded figure, which is a tighter bound
than the arithmetic supports. That branch had only ever been tested unbounded.- A target over an
AtLeastspace warned that the supply would not fit. That total is a
floor, so it proves nothing — and it is exactly the count a big book produces. - A Set past ten thousand assets loaded in the wrong order: the reader sorted by filename, and
the stem pads to four, so10000.jsonsorts before9999.json. - A non-positive enumeration budget was laundered into an answer instead of refused.
- One unchecked multiply in the odds walk, safe only at the default budget.
- Rare traits all printed
0%— the same string a trait nothing carries gets — and sorted
arbitrarily, because a data source was rounding for display. Two of the three surfaces that
print a share were also culture-sensitive, under comments promising otherwise.
Downloads
| Size | .NET 10 needed | |
|---|---|---|
| Portable | 84 MB | no — unzip anywhere and run. Start here if you are unsure. |
| Single file | 76 MB | no — one .exe. Unpacks itself on first run, so that launch is slower. |
| Single file, .NET | 14 MB | yes — one .exe, runtime left out. |
| Framework-dependent | 14 MB | yes — the same, as a folder. |
The two .NET builds need the .NET 10 desktop
runtime; the other two carry everything.
nfty 1.5.1 — one mark, and a reorder that waits for its own write
One mark instead of two, and a reorder that waits for its own write.
2,220 tests, 0 failures.
The brand mark is the application icon's own symbol
The product wore two marks and nothing in the code said they were meant to agree: a
lowercase "n" turned 45° in the titlebar, and a plain rotated square on the quick-reference
sheet — which is what the titlebar's own comment says it had replaced. The sheet's had
already drifted.
A letter rotated into a diamond spells the name and says nothing about what the app makes.
The mark is a stack of layers with the top one live, which is what an asset is here —
drawn once in Views/BrandMarkView.axaml and used by both. Its ink is AccentBrush over
FgBrush, so light and dark are one drawing rather than two, exactly the way the icon set
already works.
It carries two layers where the 256px card carries three, and the shipped 64px favicon
makes the same cut: a third row at 24px is a smear rather than a layer.
tools/icons/make-app-icon.py redraws nfty.ico from the theme's own token values rather
than exporting a copy, and keeps its per-size tuning — the small sizes now vary how many
layers rather than a letter's contrast. The .ico shows the symbol on the app's washed
tile rather than the card, because the wordmark is unreadable below 64 and a near-black
ground vanishes into a dark taskbar, which is the size and the place this is seen most.
TextBlock.brandmark is deleted with the glyph it described. The README's second badge
points at the brand art in the site repo, closing the backlog entry that asked for it.
A locked file was the disguise on a real race
ExplorerTreeReorderTests' drop test failed about four runs in six with an IOException
out of Cleanup — the temp directory deleted while the persist still held
book.cbk.<guid>.tmp open. That reads as a file-locking nuisance and is nothing of the kind.
A teardown that throws replaces the assertion failure underneath it. The drop handler is
async void, so MouseUp returns the instant PersistAsync reaches its first await — the
assertion on the moved stack was failing too, and the finally's exception took its place.
Dispatcher.UIThread.RunJobs() drains what has been posted and returns; it is not a wait,
which is why this tracked disk speed and passed nine times running on a fast machine.
Two fixes, each probed by breaking it:
- Every reorder shares one in-flight flag. The tree's drag and its reentrant
Alt+Up
chord arrived throughMoveNodeToAsynccarrying no guard at all — the same door
MoveLayerAsyncwas already guarded for, reopened one screen over. They all write the
whole book back to one archive, so two in flight collide whichever gesture started them.
One flag, not one per gesture: a second would only make each door safe against itself.
Refused rather than queued — a queued move is computed against a stack the reader can no
longer see. ExplorerView.PendingReorderis the task the gesture started, which is the one
observable trace anasync voidhandler leaves. The gesture tests await it instead of
pumping once or polling on a timer; a sleep-until-it-looks-right loop passes for the wrong
reason on a fast disk.
The guard is pinned by re-entering from inside ICookBookSession.Replace — the one moment a
persist is provably mid-flight — because starting a second gesture from the test body and
hoping it overlaps proves nothing on the machine where it does not.
Downloads
| Size | .NET 10 needed | |
|---|---|---|
| Portable | 84 MB | no — unzip anywhere and run. Start here if you are unsure. |
| Single file | 76 MB | no — one .exe. Unpacks itself on first run, so that launch is slower. |
| Single file, .NET | 14 MB | yes — one .exe, runtime left out. |
| Framework-dependent | 14 MB | yes — the same, as a folder. |
The two .NET builds need the .NET 10 desktop
runtime; the other two carry everything.
v1.4.0 — exact odds, and a canvas you can zoom
Two features and a fix to the harness. 2,219 tests, 0 failures.
The combined chance is exact now, when the CookBook is at hand
The Set browser's this combo 1 in N was the product of the rarity rows above it, and
that is an estimate twice over: it assumes the layers roll independently, and it is
built from the shares this Set happened to produce rather than from the weights the
book asked for.
CookBookLocator already finds a Set's book by hash — so a folder of a dozen books
produces no answer rather than a wrong one — and SelectionOdds (in Core, so the CLI
and the GUI cannot disagree) prices an asset from it. Generation is rejection sampling,
so the correction is the whole feature:
w_r/W × P(layers)
P = ------------------------------------------------
SUM over recipes of w/W × P(it rolls legal)
The denominator sums over the whole book, not one recipe, because a rule violation
throws the recipe roll away too. With no rules anywhere it is exactly 1 and the figure
reduces to the product — which is the right relationship between the two: the estimate
is this model with its correction dropped.
On the test book, whose background rolls 70/30 and whose aura rolls 60/40 with a rule
excluding one pair, the surviving combinations are worth 47.73%, 31.82% and
20.45%. Multiplying the Set's own twelve-asset shares says 48.61%.
Giving up costs a direction, not the answer: every legal mass is at most 1, so a book
too large to walk reports the numerator as a true floor — at most 1 in N — rather than
a guess. And it reads the book as manifests alone (ArchivePeek.CookBookTree),
because a probability is a few dozen weights and a full read would pull every variant
PNG in the collection into memory to reach them.
Without a book beside the Set nothing changes except honesty: the figure carries a ~
and its tooltip says what it assumed.
The canvas zooms and pans
An 8px sprite in the editor's tile is forty device pixels to the art pixel. A 512px
drawing in the same tile is under two thirds of one — finer than the backdrop will even
draw a lattice at.
- Wheel to zoom, anchored on the pointer.
- Middle-drag, or the arrow keys, to pan.
+/-/0, and a chip at the corner of the canvas whose label is the current
zoom and whose click is fit.
The zoom exists in exactly one function — the one the pointer, the marquee and the
backdrop lattice are already mapped through — so the pixel you click is the pixel you
paint, and the lattice stays in phase with the art, at every magnification.
The editor opens in the view you left
The pixel grid, its step, the preview tile's size and which half of the rail is showing
are remembered between sessions. An author who paints 16px sprites on an 8px lattice was
setting that on every layer they opened.
Zoom and pan are deliberately not remembered — they belong to the image, and opening
an unrelated layer magnified and panned into a corner is a lost canvas rather than a
restored preference.
And four screenshots that were of the wrong thing
The harness's four REFERENCES frames reached that panel by scrolling the colorize rail
to its end. Splitting the rail into two tabs moved the panel out of that scroller and
the scroll became a no-op — leaving four frames named refs, every one a picture of the
colorize rail, with the tab bar beside them announcing "REFERENCES 3/5" about a panel
nothing showed. Nothing failed, because a capture asserts nothing. It asserts this much
now.
Downloads
| Size | .NET 10 needed | |
|---|---|---|
| Portable | 84 MB | no — unzip anywhere and run. Start here if you are unsure. |
| Single file | 76 MB | no — one .exe. Unpacks itself on first run, so that launch is slower. |
| Single file, .NET | 14 MB | yes — one .exe, runtime left out. |
| Framework-dependent | 14 MB | yes — the same, as a folder. |
The two .NET builds need the .NET 10 desktop
runtime; the other two carry everything.
nfty 1.3.3 — the rarity unit is a page-level control
One placement fix. 2,172 tests, 0 failures.
The rarity unit is a page-level control now
The % | 1 in N toggle sat in the rarity table's own sub-header, which said it was that
table's setting — and it is not. It drives the trait column and the asset's own combined
chance, which sit in different panels. A reader who switched to odds and then found one
figure still reading in percent has been told the screen is inconsistent about its own
numbers. It always did drive both; only its placement said otherwise.
It is in the page header now, beside Export — everything to the left of there is a fact
about the Set, everything to the right is a control:
VaporCats [ASSETS 6] [SEED seed1] [RECIPES 1] RARITY [ % | 1 in N ] [Export…]
Exactly one tray, which is what stops a second copy reappearing next to the thing it governs.
Two tests hold it: one asserts the column header, the rarest-trait line and the combined
chance all move together; the other asserts the tray's count and its place.
The label is its own class rather than the chip label's — a bare .ck is only styled inside a
chip, so outside one it took the inherited 14px and read a size larger than every chip on the
row. Caught on a captured frame.
Downloads
| Size | .NET 10 needed | |
|---|---|---|
| Portable | 84 MB | no — unzip anywhere and run. Start here if you are unsure. |
| Single file | 76 MB | no — one .exe. Unpacks itself on first run, so that launch is slower. |
| Single file, .NET | 14 MB | yes — one .exe, runtime left out. |
| Framework-dependent | 14 MB | yes — the same, as a folder. |
The two .NET builds need the .NET 10 desktop
runtime; the other two carry everything.
nfty 1.3.2 — a missing asset image looks like damage
One fix. 2,170 tests, 0 failures.
A missing asset image now looks like damage
SetItemRow.Decode falls back to a 1×1 transparent bitmap rather than throwing — a browser
over a damaged Set should show the damage, not refuse to open. But the moment that
placeholder was published IsLoading went false, the breathing diamond that covers a pending
decode went with it, and the tile settled into a flat empty square: indistinguishable from
a decode still in flight, and from a fully transparent asset, which is a legal thing to mint.
Found by opening a Set whose folder had been half cleaned up — 24 images for a 60-asset Set,
and 36 tiles that looked like they were still thinking.
The decode returns the flag beside the bitmap now, and the tile draws a mark: the same
diamond, so an unfilled tile still looks like part of the product rather than a hole in it,
but static and in the warning ink. Static is the whole point — a pulse means "coming", and
nothing is coming. The detail rail's preview carries the same mark, because a blank square
there is the identical defect one level over, and both carry a tooltip naming what happened.
Two tests either side of it: one asserts the mark is drawn only on the row that lost its file
and that the loading pulse is absent; the other that an intact Set draws no marks at all.
Neither can pass on a constant.
Downloads
| Size | .NET 10 needed | |
|---|---|---|
| Portable | 84 MB | no — unzip anywhere and run. Start here if you are unsure. |
| Single file | 76 MB | no — one .exe. Unpacks itself on first run, so that launch is slower. |
| Single file, .NET | 14 MB | yes — one .exe, runtime left out. |
| Framework-dependent | 14 MB | yes — the same, as a folder. |
The two .NET builds need the .NET 10 desktop
runtime; the other two carry everything.
nfty 1.3.1 — what the app says when you have not started, and how rare this one is
Two fixes to what the app says, following 1.3.0. 2,167 tests, 0 failures.
A brand-new CookBook no longer greets you with an error
Make a CookBook and the status bar says 1 problem before you have made a single
decision. The problem is real — CookBook has zero total recipe weight — and it is exactly
what the CLI prints, but to a first-time author it reads as something they broke.
The report leads with the explanation now:
1 problem — Fresh Book
This CookBook has no Recipes yet. Add one, then add Ingredients to it — until there is
something to stack, there is nothing to cook. Nothing below is a mistake you made.
1 · CookBook has zero total recipe weight.
It is derived from the graph, not from matching Validator's wording — a reworded message
must not silently stop being recognised — and it names the empty Recipes, because "add an
Ingredient" without saying where is barely better than the raw problem.
The kicker gets a third state: a half-built book is not a broken one, so it takes a plain
dot rather than the warning ink. And the footer stops saying "cooking is refused until these
are fixed" on a book nobody has started — true, but the reader was just told what to do one
line above, so a refusal underneath is a telling-off carrying no information. On a genuinely
broken book it still says exactly that.
An asset's rarity, as a percentage or as odds
Three answers the Set browser's rail could not give, all from the numbers it was already
showing.
The unit toggles. A percentage compares traits to each other; odds are what "how rare is
this one" actually asks — 4.17% against 2.08% reads as a near-miss where 1 in 24 against
1 in 48 does not. The whole column switches, header included.
The whole asset's odds. "The lock is 1 in 4 and the bands are 1 in 3" is not an answer to
how rare the asset is. The rail now prints this combo 1 in 43,200 beside the id — the
product of exactly the rows underneath it, recipe share included, so you can check it by
hand. It assumes the layers roll independently, which incompatibility rules and optional
layers both break, and the tooltip says so.
The rarest trait stays beside the RARITY heading. Deliberately not a rarity score: the
sum of the reciprocals is a convention this project has never adopted and would have to
invent, where the rarest trait is a fact already in the table.
Downloads
| Size | .NET 10 needed | |
|---|---|---|
| Portable | 84 MB | no — unzip anywhere and run. Start here if you are unsure. |
| Single file | 76 MB | no — one .exe. Unpacks itself on first run, so that launch is slower. |
| Single file, .NET | 14 MB | yes — one .exe, runtime left out. |
| Framework-dependent | 14 MB | yes — the same, as a folder. |
The two .NET builds need the .NET 10 desktop
runtime; the other two carry everything.
nfty 1.3.0 — the lock, the tree, the die and the rail
Four fixes and three features across the Explorer, the Recipe and Ingredient panes, the
Ingredient Editor and the Set browser. 2,154 tests, 0 failures.
The one that mattered
The Ingredient Editor could save into a read-only CookBook. The pencil opens the editor
whether or not the edit lock is on, and that is deliberate — the editor is also how you
look at a layer. Saving from it was not. The editor took no lock at all, so a book the
Explorer was refusing to add to, delete from or reorder could have a layer's manifest
rewritten, its KIND changed and the whole archive persisted, from one click away, with the
titlebar still saying read-only.
The gate is checked inside Save() as well as in CanSave: a generated
RelayCommand's ExecuteAsync does not consult its own CanExecute, so the disabled
button was the entire enforcement — and a disabled button is a label. Painting stays live;
a read-only editor is a scratch surface, and the footer says so from the moment it opens.
Reorder in the Contents tree
Drag, or Alt+Up / Alt+Down, on recipes and layers, among their own siblings only.
The two moves are not the same act and the status line says which. A layer move rewrites
layerOrder, which is the paint order — and the generator consumes one RNG draw per layer
in order, so the same seed over a reordered recipe is a different collection. A recipe
move is presentation and cannot change an asset, because the roller sorts its keys ordinally
before it rolls anything. Both are gated by the edit lock all the same, and books open
read-only.
Recipe order had nowhere to live, so CookBookManifest.RecipeOrder is new: optional,
additive, no schema bump, and tolerant of going stale.
The rest
- The reroll die has six faces, lands on a new one every press, and its single pip is
red. No more "sample 1" — that number was the reroll count, not a fact about the recipe. - The recipe's layer rows scroll under a pinned header instead of running off the pane.
- The ingredient hero is a 2×2 block that pages — one height in every book, where before
it grew a row per two variants and pushed the pane's own buttons off the screen. - The validity count is a button. "3 problems" used to put the problems on a tooltip;
both it and the CookBook card's chip now open the full numbered report. It opens on a
valid book too and says what was checked. - The Set browser's rail shows the asset it is describing — a live preview that follows
the hover, the right-click-to-keep and the inspector, beside the id it already showed.
Known, not fixed
A cooked Set whose image files are missing draws blank tiles and says nothing — a missing
file ends up looking like one still loading, forever, and identical to a fully transparent
asset. Found by opening a Set whose folder had been half cleaned up. Recorded in CLAUDE.md.
Downloads
| Size | .NET 10 needed | |
|---|---|---|
| Portable | 84 MB | no — unzip anywhere and run. Start here if you are unsure. |
| Single file | 76 MB | no — one .exe. Unpacks itself on first run, so that launch is slower. |
| Single file, .NET | 14 MB | yes — one .exe, runtime left out. |
| Framework-dependent | 14 MB | yes — the same, as a folder. |
The two .NET builds need the .NET 10 desktop
runtime; the other two carry everything.
nfty 1.2.8 — the README gets a hero
The README gets a hero frame. No engine, CLI or GUI behaviour changes — the binaries are
1.2.6's, rebuilt so every archive carries the current file.
The frame
One pair, light and dark, swapped by the reader's theme: the Explorer with the built-in demo
CookBook open — a layer tree beside a card reading 2 recipes · 12 layers · 31 variants ·
615,600 unique DNA. It is the README's own thesis stated as a picture.
Shot from the running app with tools/docs-capture, not from the VisualCapture harness,
whose 8×8 fixtures render empty panels and quote "2 unique DNA".
It lives in assets/readme/, deliberately outside docs/manual/images/. That whole figure set
still shows Vapor Pets on the pre-1.2 card layout, and BACKLOG.md holds the reshoot as a single
pass that has to move the tutorial prose with the pictures — half of it would leave one document
showing two collections. A README hero sits outside that document, so it can be current on its own.
assets/readme/README.md carries how to reshoot it and what the frame has to show.
It is referenced by absolute URL rather than a relative path, because every release archive carries
README.md and a relative image path there points at a file the archive does not contain.
Also
- Backlogged: the project icon the other Vaporsoft repos carry beside the Vaporsoft logo. The
mark exists andtools/icons/make-app-icon.pyalready generates it from the theme's own values —
the work is teaching that script to emit a web-sized PNG too, which is the only way to add one
without creating the second copyIconSourceTestsexists to prevent. - Corrected a stale number in
BACKLOG.md: it said the window minimum was 1200x712. It has been
1280x720 since the milestone commit.
Downloads
| Size | .NET 10 needed | |
|---|---|---|
| Portable | 84 MB | no — unzip anywhere and run. Start here if you are unsure. |
| Single file | 76 MB | no — one .exe. Unpacks itself on first run, so that launch is slower. |
| Single file, .NET | 14 MB | yes — one .exe, runtime left out. |
| Framework-dependent | 14 MB | yes — the same, as a folder. |
The two .NET builds need the .NET 10 desktop
runtime; the other two carry everything.
nfty 1.2.7 — the README, rewritten against the code
The README is rewritten. No engine, CLI or GUI behaviour changes in this release — the
binaries are 1.2.6's, rebuilt so every archive carries the new file.
The README
It now follows the flow the other Vaporsoft repos use: tagline, grounded intro, grouped
badges, Table of Contents, Overview and Capabilities, Requirements, Installation, Quick
Start, Concepts, Architecture, Command Line, Desktop Application, Performance,
Development, Deployment, Troubleshooting, Links, Contributing.
Every figure in it was checked against the repository rather than carried over:
- Five real commands were missing —
demo,export,add rule,remove ruleand
set chance— andinspecthad grown.setand.tinsince the table was written. - The test badge said 1672 and the layout said 1454. A full run is 2,088: 152 CLI,
1,058 Core, 878 App. - 615,600 was re-derived with
stats, and the demo's eighteen distinct sprites counted
out of the archive itself. - Sealing, export, optional layers and the counted DNA space had no place in the file
at all, which left the two features most likely to be asked about undocumented. - Two screenshots were drafted and pulled again:
docs/manual/images/still shows Vapor
Pets on the pre-1.2 card layout, whichBACKLOG.mdalready holds as a deferred reshoot.
A stale frame in a README is worse than none.
The project tree and the pipeline sketch were also brought under 80 columns, so a narrow
viewport no longer cuts the right-hand end off every line.
Downloads
| Size | .NET 10 needed | |
|---|---|---|
| Portable | 84 MB | no — unzip anywhere and run. Start here if you are unsure. |
| Single file | 76 MB | no — one .exe. Unpacks itself on first run, so that launch is slower. |
| Single file, .NET | 14 MB | yes — one .exe, runtime left out. |
| Framework-dependent | 14 MB | yes — the same, as a folder. |
The two .NET builds need the .NET 10 desktop
runtime; the other two carry everything.