Skip to content

Split the face designer into steps, and fix what the phone showed - #388

Merged
drehtuer merged 8 commits into
feature/designer-material-and-roundnessfrom
feature/designer-steps
Oct 5, 2026
Merged

drehtuer merged 8 commits into
feature/designer-material-and-roundnessfrom
feature/designer-steps

Conversation

@drehtuer

@drehtuer drehtuer commented Oct 5, 2026

Copy link
Copy Markdown
Owner

Answers the owner's face-designer feedback from the Pixel 10a: three bugs fixed, a body colour, an edge-rounding slider, and the designer split into three steps.

Based on #387 (fix/shader-plate-checks), stacked as .claude/CLAUDE.md asks.

Bugs, each with a regression test

  • "Rolling from the face designer adds numbers to the die."
    • Cause: every face was printed, and the artwork was laid over the print by its alpha (decision 59), so any clear part of a drawing showed the set's number through it.
    • Fix: a face is now drawn or printed, never both. The decoded atlas says once which cells hold anything (AtlasImage.drawnCells, AtlasCoverage). The renderer leaves those cells out of the printed numbers (Stage.drawnCells, DieNumbers.fieldOf(drawn), PrintedDice keyed by die and drawn faces). Undrawn faces keep their numbers.
    • This also changes third-party sets whose artwork leaves gaps around a printed number; they now show the artwork alone. Decision 96, and docs/dice-sets.md is updated.
  • "The rendered spinning die only shows blank faces."
    • Cause: the Solid view deliberately left every pen stroke out.
    • Fix: strokes are now drawn as the shapes their ink covers (StrokeOutline), projected onto the turning die, and the eraser paints the body colour.
  • "Loading an image has no effect." There is no image-loading option in the designer.
    • What it was: the guide toggle, drawn with the prototype's framed-landscape glyph. In the dark theme the guide was pale grey on white paper, so it looked like it did nothing.
    • Fix: the guide is drawn in whichever of black or white reads on the paper (PaperInk), and the switch now says Guide, as in the prototype.
    • Putting a photo on a face would be a new feature.
  • "Edges 1–4 only make sense for the d4."
    • Not the solver: every shape but the d4 gets the full radius.
    • Cause 1: the designer always drew its turning die sharp, so the steps changed nothing on screen.
    • Cause 2: how much rounding shows depends on the shape. Over 1.5–12 % a d4's corners move 2 mm, a d20's 0.5 mm. The table is in docs/face-designer.md.

New

  • Body colour (decision 97):
    • A die-level colour from the pen's twelve or the shared ColourPicker.
    • Numbers switch automatically to black or white so they read on it.
    • Written as the existing per-die color / number_color keys, so the format and the validator are unchanged.
    • The canvas, strip and turning die are all drawn on it.
  • Edges slider (decision 98, amending 94):
    • Covers 1.5–12 % in 0.5 % steps, and says the share and the millimetres, which TalkBack reads too.
    • The turning die is drawn rounded (RoundedSolid).
    • The range is still the set file's: the phone runs that would measure it were not made. See the open box in docs/TODO.md 4.6.
  • Three steps (decision 99): Shape → Material → Faces.
    • One screen and one presenter, with a step bar under the title that goes to any step.
    • The footer has Back and Next on the first two steps, and Back, Save to set and Roll it on the last.
    • The draft is written whenever a step is left.
    • A route that names a die (quick mode, the way back from a test throw) opens on Faces.
    • The phone's Back leaves the designer from any step, as before.
  • Docs and design:
    • The prototype design/dInfinityPhone.dc.html shows the steps, the colour row and the slider.
    • Updated: design/README.md, the README feature line, docs/face-designer.md, docs/architecture.md decisions 96–99, docs/physics-and-rendering.md ("How round a die may be"), docs/STATUS.md and docs/TODO.md.

Tests and coverage

  • New test files: StrokeOutlineTest, RoundedSolidTest, PaperInkTest, DesignerGuideTest and DesignerStepsTest.
  • Extended: tests in designer, feature/designer, render/filament, core/model and app.
  • New device test: AtlasTextureTest.theStageSaysWhichFacesTheUploadedAtlasDrawsOn. It compiles but has not been run yet.
Module Function Branch
designer 97.4 → 98.0 % 88.0 → 88.7 %
feature/designer 98.1 → 98.7 % 65.7 → 66.1 %
render/filament 76.6 → 76.6 % 73.3 → 73.6 %
core/model unchanged unchanged

Locally in the devcontainer:

  • ./gradlew build test coverageReport lint detekt ktlintCheck is green.
  • The Documentation job's mermaid and markdownlint checks pass: 21 diagrams parse, 0 lint errors.

Not done: needs the phone

  • The edge-rounding range. The harness and FairnessTest runs at 1.5 %, 3 % and 12 % on d4, d6 and d20 were not made; the commands are in docs/TODO.md 4.6. The permission settings blocked the agent's attempt.
  • For the owner to judge:
    • Walk the three steps.
    • Roll a die drawn on some faces only.
    • Try a dark body colour.
    • Watch the pen's lines on the Solid tab.
    • Toggle Guide in the dark theme.
    • Drag the slider on a d6 and on a d20.

🤖 Generated with Claude Code

drehtuer and others added 8 commits October 5, 2026 08:55
Rolling a die from the face designer showed the set's number through every
clear part of every drawn face. Every face was printed and the atlas was laid
over the printing by its alpha (decision 59), so a drawing that did not cover
its face edge to edge let the label through.

A face is now printed or drawn, never both. The decoded atlas already knew
which cells were empty (the validator's AtlasCellsEmpty warning); its
complement is worked out once per upload for every catalogue face count
(AtlasCoverage), the renderer asks the stage about it before adding a die
(Stage.drawnCells) and leaves those cells out of the number field
(DieNumbers.fieldOf, PrintedDice keyed by die and drawn faces). Undrawn faces
keep their numbers, so a die drawn on one face is still readable; a number
wanted on a drawn face is stamped into the drawing.

Decision 96 records the change; dice-sets.md, physics-and-rendering.md and
face-designer.md say the new rule.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Solid tab left every stroke of the pen out, on the grounds that a line of
one width over a tilted face is not the line on the die. On the phone that was
a die drawn with the pen turning with blank faces.

A stroke is now handed to the stage as the shapes its ink covers
(StrokeOutline): a disc at every dot, for the canvas's round caps and joins,
and a band half a nib either side of every segment, all wound one way. Those
project exactly like any other ring and are filled as their union under the
non-zero rule, so the line is foreshortened as its face is rather than drawn at
one width. The eraser is drawn in the face's paper, as on the canvas. Dots
closer than a quarter of the nib are dropped first to keep a spinning die
cheap.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The owner reported that the designer's option for loading an image had no
effect. There is no such option: the switch was the guide toggle, drawn with
the prototype's #ic-image glyph (a framed landscape), which reads as "add a
picture". And it really did appear to do nothing in a dark theme, because the
guide was drawn in the page's ink at a third of its strength — pale grey on
the white paper the canvas always uses.

The guide is now drawn in black or white, whichever reads on the paper
(PaperInk), and the switch says "Guide", as the prototype's checkbox does.
The unused #ic-image glyph goes from DesignerIcons.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With rounded edges a face no longer fills its side, so a die coloured by
bucket-filling every face kept the set's bone colour at its edges and corners.
The owner asked for a configurable base colour.

The die's finish now carries its body colour and the colour its undrawn faces
are printed in. The body is chosen beside the material from the pen's twelve
colours and the shared ColourPicker past them; the number colour follows it,
near-black on a light body and white on a dark one (PaperInk), because its
only job is to be read. Both go into the package as the existing per-die
color and number_color keys, and into the draft as two optional integers: a
finish written before them read as the bone die it described.

The canvas, the eraser, the face strip and the turning die are all drawn on
the body colour, so the canvas is the die. Decision 97.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The owner found that the four Edges steps only made sense for the d4 and
asked for a slider. The steps did not fail in the solver — every shape but
the d4 gets the full radius at every value — but the designer drew the sharp
polyhedron whatever was chosen, and how much rounding shows depends on the
solid: a corner stands in by r(|m|-1) and an edge band is r*tan(theta/2) wide,
so across the whole range a d20 moves half a millimetre where a d4 moves two.

Edges is now a slider over the set file's range, 1.5-12 % in half per cents
(EdgeRounding), said under it as the share and as the millimetres the solver
gives this die. The turning die is drawn rounded by that radius
(RoundedSolid): flat parts, edge bands, corner patches and an outline round
the rounded corners, so moving the slider is visible before a throw.

The bounds stay decision 94's: the phone runs that would test them could not
be made in this change, and physics-and-rendering.md lists them. Decision 98.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The owner asked for the design process in steps instead of everything on one
screen: geometry, then material and base colour, then the faces. One screen
was the base-die chooser, the canvas, six rows of tools, the material and the
edges all scrolling past each other.

The designer is now Shape (the dice, with the die turning above them),
Material (the turning die, the material menu, body colour and edges slider)
and Faces (the drawing, its Face/Solid tabs and the face strip). A segmented
step bar under the title says where the player is and goes anywhere; Back and
Next walk the steps, Next being the filled button until the last step, where
Roll it and Save to set are. It stays one screen and one presenter: the steps
are views of one draft, which is written down as a step is left. The menu
opens on Shape; quick mode and the way back from a test throw know the die
and open on Faces (DesignerStep.openingFor).

The phone prototype shows the same steps, design/README.md maps them, and
face-designer.md's Flow says it. Decision 99.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Function and branch coverage must not sink in a change. The new pieces left
gaps: the bends and pieces of the stage built with their defaults, the
artwork a stage reads coverage from, the body colour picker's two answers,
undo and redo on the last step, and the skip branches Compose generates for
small composables handed the whole designer state.

The artwork and the question "which faces does it draw on" move into plain
Kotlin (DieArtwork, generic in the texture) so a JVM test asks them;
Stage.drawnCells has no default, so every stage answers it on purpose. The
small composables that take the whole state are non-restartable, as OptionBox
is: a state that changes on every stroke is one they could never skip on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The edge-rounding slider's range is still the set file's, unmeasured; the
harness and FairnessTest runs that would narrow it are now the first box of
step 4.6, and the owner's judgements on the three steps follow it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@sonarqubecloud

sonarqubecloud Bot commented Oct 5, 2026

Copy link
Copy Markdown

Base automatically changed from fix/shader-plate-checks to feature/designer-material-and-roundness October 5, 2026 07:28
@drehtuer
drehtuer merged commit 5cd650f into feature/designer-material-and-roundness Oct 5, 2026
9 checks passed
@drehtuer
drehtuer deleted the feature/designer-steps branch October 5, 2026 07:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant