feat(udg): fit: slice — 9-slice presses, so a frame stops distorting #149
No reviewers
Labels
No labels
build-dist
priority
P1
priority
P2
priority
P3
priority
P4
bug
duplicate
enhancement
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
Toilville/toilville-design!149
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/udg-press-fit-slice"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Stacked on #148 — base is
feat/udg-press-tier, so this diff is only thefit: slicework. Retarget tomainonce #148 merges.A frame plate's thickness is filled geometry, so stretching it to a non-square panel scales bar weight anisotropically. At 860×190 the verticals come out roughly 4× the weight of the horizontals, with the hand-drawn wobble pulled into coarse teeth.
fit: sliceholds the corners rigid and repeats the edges at native scale.Both spelwork frame pulls now use it:
Scope
fit: slicejoinsstretch·contain·cover·tile— andfitis now a checked enum, so a typo fails by name instead of emitting a dead value.Two knobs on the plate, deliberately separate. Collapsing them is what makes 9-slice look wrong in practice:
slice: 12%slice_width: 20pxLeft coupled (
mask-border-width: auto) this plate renders a 59px band that swamps anything but a tall panel. px, not%: percentage border widths resolve against width for the left/right edges and height for top/bottom, so they go visibly asymmetric on any non-square box. Both live on the plate inassets.yml, not per press — corner size belongs to the drawing.Three things make it work, each found by rendering rather than by reading a support table:
-webkit-mask-box-image-*longhands. The shorthand silently yields an empty mask, which floods the panel with raw pigment — the same failure mode as the:roothandle bug in #148.fithandle deliberately has none (viewBox-only +preserveAspectRatio="none", which is what makesfitmean anything at all). Emitted only for plates that declare an inset.mask-border; without this it would lose the mask entirely rather than degrade to the stretch version.Testing
just check— green. Block count still 33.python -m pytest generator/tests/— 218 pass, 9 new: the enhancement handles, the fallback mask surviving,fit: sliceagainst a plate with no inset, thefitenum, non-slice pulls emitting no slice handles (an undefined var is what makes the longhands fall through), the sliceable registry reading the manifest rather thandist/, and the variant keeping intrinsic size while the ordinary handle keepsPAR=none.sliceandslice_widthvalues were chosen by rendering sweeps (8/12/16/22/30% and auto/28/20/14px/6%), not picked.Impact Statement
Additive and opt-in.
fitgains a value; every existing pull keeps its behaviour. Only plates declaringslice:get the second export, soplates.cssgrows for the frame plate alone (277KB → 456KB; the two line plates are untouched).dist/churn stays confined to spelwork plus the shared plate bundle.Progressive enhancement, not a dependency. Blink and WebKit get 9-slice; Firefox degrades to the stretch mask it already had. Nothing regresses anywhere.
Reversibility: high. Remove
slice:from a plate and it stops being sliceable; set a pull back tofit: stretchand it renders as before.What this does not settle. Corner + edge plates remain the fully portable alternative and are still the better answer where corner and edge artwork must differ — 9-slice re-uses one drawing's own corners and cannot express that. Which approach the brand wants is still ville's call; this makes one of the two options real and measurable rather than hypothetical.
Unchanged from #148: a pull still covers its whole element — no anchor or extent — so a rule that should sit at one edge cannot yet be expressed.
A frame plate's thickness is filled geometry, so stretching it to a non-square panel scales bar weight anisotropically: at 860x190 the verticals come out ~4x the weight of the horizontals, with the hand-drawn wobble pulled into coarse teeth. `fit: slice` holds the corners rigid and repeats the edges at native scale. Measured at 3x magnification it restores equal bar weight and keeps the wobble on every edge. Three things make it work, each found by rendering rather than by reading a support table: - the -webkit-mask-box-image-* LONGHANDS. The shorthand silently yields an empty mask, which floods the panel with raw pigment. - a second, intrinsically-sized plate export. Slice percentages resolve against intrinsic size, and the ordinary `fit` handle deliberately has none (viewBox-only + preserveAspectRatio="none", which is what makes `fit` mean anything at all). - the plain mask emitted ALONGSIDE it as the fallback. Firefox has no mask-border; without this it would lose the mask entirely rather than degrade to the stretch version. Two knobs, deliberately separate — collapsing them is what makes 9-slice look wrong in practice: - `slice` picks WHICH artwork is the corner (12% here, matching the drawn band). Too large and the corner art dominates; it also clamps unpredictably on small boxes, which is why an exploratory 46% looked fine. - `slice_width` picks how thick the band DRAWS (20px). Left at auto it inherits the slice size — 59px for this plate, which swamps a short panel. px, not %: percentage border widths resolve against width for left/right and height for top/bottom, so they go asymmetric on any non-square box. Both live on the PLATE in assets.yml, not per press: corner size belongs to the drawing. A press naming `fit: slice` against a plate with no inset is rejected by name, and `fit` itself is now a checked enum. The review artifact's comparison now drives the SHIPPED handles rather than an ad-hoc variant, which let the one-off builder go. Both spelwork frame pulls use fit: slice, and the docs' §4 recipe was re-rendered verbatim to confirm it is still copy-paste. Corner + edge plates remain the portable alternative, and are still the better answer where corner and edge artwork must DIFFER — 9-slice re-uses one drawing's own corners and cannot express that. Verified: just check green, 218 tests pass (9 new).Decision: 9-slice. One drawing per frame — no separate corner and edge plates, at least to start.
The corner+edge route buys the ability to make a corner look like something other than its edge. Nothing in the system needs that yet:
plate.ui.rectangleis the only frame plate, and it is one hand-drawn rectangle whose corners and edges already come from the same hand. Splitting it would produce two drawings that have to be kept in agreement, to express a difference nobody has asked for.One drawing is also one thing to draw, one thing to keep consistent, and one thing to get wrong.
What would reverse this
A drawing whose corner must differ from its edge — a frame with a mark, a seal or a join at one corner. 9-slice cannot express that, and the moment such a plate is wanted, corner+edge is the right answer for it. That is a per-plate call, not a system-wide one, so this decision does not have to be undone to make it.
Why it costs little to pick
Firefox degrades to the stretch mask it already had, so choosing 9-slice takes nothing away where it isn't supported. And
slice/slice_widthliving on the plate rather than the press is the right split — corner size is a property of the drawing, and putting it at the call site would invite four frames at four corner sizes.The anisotropy numbers are the argument for the feature itself: verticals at roughly 4× the weight of the horizontals at 860×190 is not a frame, it is two different frames sharing a box.