Let painted frames override a composed pose - #23
Merged
Conversation
Every pose is composed in code, which is why one sit covers 28 coats and a new coat costs nine hex values instead of an art pass. The trade is that changing how the pet looks means editing geometry, and there was no way in for hand drawn or generated art at all. src/art-frames.js is the escape hatch: a table of role-letter grids that wins over the composer for the pose and the coats it names, and nothing else. Lookup runs coat name, then build name, then '*', then the composer, so a pack of one frame is a valid pack and a half finished one still runs. Baked grids are stamped THROUGH buildSprite rather than around it, so they pick up outlineHalo(), the eye boxes and the muzzle anchor exactly as a composed pose does. That means the halo is never authored, a patchy outline gets its gaps filled, and drawCat needs no special case. A grid that does not match the pose's canvas is ignored rather than trusted, because the layout maths around it is built on those constants. scripts/import-frames.js turns painted PNGs into that table. It carries its own PNG decoder (colour types 0/2/3/4/6, every filter) rather than adding a dependency, the way pet-sheet.js hand-rolls its encoder. Each cell takes an area majority vote over the pixels covering it, so art that does not land exactly on the grid still imports, and every frame is checked before it is written: canvas size, an eye block either side of the seam eyeBox() splits on, a nose for the whiskers to anchor to, a floor row to stand on. A frame that fails is dropped with a reason instead of shipped. Only the five held poses are importable. The raised-limb activities are parameterised rigs (4 climb frames, up to 45 paw frames, 14 bat frames per coat) and a single still would freeze them mid swing, so the importer refuses them on purpose. The load-bearing test is a round trip: compose a real pose, paint it out to a PNG, read it back through the importer and assert the grid is identical. That covers decode, resample and colour snap against real sprite shapes rather than a hand written fixture.
Covers the role grid model, the placeholder palette to paint against, the three things the engine draws on top that must never be authored (the halo, the pupils, the dog tongue), the file naming, and the checks the importer runs. Also spells out which activities are held poses and which are animation rigs, with the frame count behind each rig, because that is the distinction that decides whether generated art is a drop in or a reference to redraw the composer against.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds a way to replace a composed pose with painted art, and the importer that gets a PNG into that shape.
Every pose is composed in code, which is why one
sitcovers 28 coats and a new coat costs nine hex values instead of an art pass. The trade is that changing how the pet looks means editing geometry, and there was no way in for hand drawn or generated art at all.src/art-frames.jsis the escape hatch.How it fits together
src/art-frames.js(generated, empty by default) holds role-letter grids. Lookup runs coat name, then build name, then*, then the composer, so a pack of one frame is a valid pack and a half finished one still runs.posed()inrenderer.jsstamps a baked grid throughbuildSpriterather than around it, so it picks upoutlineHalo(), the eye boxes and the muzzle anchor exactly as a composed pose does. The halo is never authored, a patchy outline gets its gaps filled, anddrawCatneeds no special case. A grid that does not match the pose's canvas is ignored rather than trusted, because the layout maths around it is built on those constants.scripts/import-frames.jsturns painted PNGs into that table. It carries its own PNG decoder (colour types 0/2/3/4/6, every filter) rather than adding a dependency, the same callpet-sheet.jsmakes for its encoder. Each cell takes an area majority vote over the pixels covering it, so art that does not land exactly on the grid still imports.Named
<species>-<pose>.png, or<species>-<pose>--<key>.pngto target one coat or build.Held poses vs animation rigs
Only five poses are importable. The other six are parameterised rigs and a single still would freeze them mid swing, so the importer refuses them on purpose:
climbSpriteFor(i, hand, dir)pawSpriteFor(i, lift, out)PAW_STEPS8 by 4batSpriteFor(i, up, ph)Generated art for those is still worth having as a reference to redraw the composer against, which is how the dog was built in the first place.
Nothing is trusted on the way in
Every frame is checked before it is written, and a frame that fails is dropped with a reason:
eyeBox()splits on, or exactly one for the two profile poses. A face drawn off centre puts one eye in both boxes anddrawCatpaints the pupil as a bar across the muzzle. That has bitten this project twice.Test plan
npm test81 green, up from 69scripts/overlay-vm.js: a baked frame replaces the composed one, an unbaked coat keeps composing, the halo and outline are still regrown, both eye boxes survive, and a wrong sized grid is ignored.tRNS, and all five filter types.npm run lintcleannpm run test:bootgreen