feat(tui): the intro splash — mark, ring, and a tagline that types itself - #223
Open
plombeer31 wants to merge 2 commits into
Open
feat(tui): the intro splash — mark, ring, and a tagline that types itself#223plombeer31 wants to merge 2 commits into
plombeer31 wants to merge 2 commits into
Conversation
…self A first run opened on a list of three options with no product name on it anywhere. This is the screen before that: the mark inside a ring of smaller crosses, the `ATOMIC` wordmark, and the shipped tagline typing itself in at ~45ms/char. - `use-typewriter.ts` — one interval for the whole reveal. The first draft listed the revealed count in the effect deps, so every character tore the timer down and armed a new one; with Ink's frame commit in between, a 45ms/char reveal actually crawled at ~230ms/char. - `orbit-field.ts` — ring placement, pure. An ellipse, not a circle: a cell is ~2.2× taller than wide, so a circle drawn in cells reads as a wide oval. - `intro-art.ts` — composes mark + ring into one grid. The ring is sized by whichever runs out first, rows or columns, and is dropped entirely rather than resting a cross inside the mark's clear space. Ink 7 overlaps instead of clipping, so the grid never exceeds its row budget. - The mark steps down md → sm → none by the rows actually left over, not by the size tier alone, for the same reason. Any key finishes the reveal; a second key moves on. The splash claims Esc too — it must not skip setup from a screen that has not yet said setup is what comes next. `introSeenAt` is stamped as it is dismissed. Verified in a PTY at 100×30 (full ring), 86×26 (ring dropped for clear space, advisory in the footer) and 72×20 (sm mark, small ring, everything still on screen).
This was referenced Aug 21, 2026
A single radius threshold cannot express clearance around this mark. The ring is an ellipse and the mark is wider than it is tall, so one number is either too strict vertically or too loose horizontally — mine was the former, and silently dropped the ring at 100×30, the size the flow actually opens at, where it fits with four columns and two rows to spare. Checked per axis now, against the mark's own box. Pinned at 96×21 (the intro's usable area inside a 100×30 terminal) and at a wide-but-short window, where the rows are what runs out.
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.
Stacked on #222 (which is stacked on #220). Retarget as each merges.
Why
A first run opened on three unstyled option rows. The product's name appeared nowhere on the screen a new user meets first — the mark, the wordmark and the tagline all shipped in
logo.tsxand none of them were used until the operator was already inside the app.The screen
The mark inside a ring of smaller crosses,
ATOMIC(the first 23 columns of the shippedATOMIC AGENTwordmark), andTAGLINE— the string the codebase already carries — typing itself in at ~45 ms/char, then[ press any key to continue ].Three things worth reviewing
use-typewriter.tsruns one interval for the whole reveal. My first draft listed the revealed count in the effect's dependency array, so every character tore the timer down and armed a fresh one — with Ink's frame commit in between, a 45 ms/char reveal actually crawled at ~230 ms/char. The count advances inside the tick now and the timer stops itself on the last character. (Underink-testing-librarythe rate is bounded by its ~4 fps commits regardless, which is why the test asserts progress-then-settle on a short string rather than a duration.)The ring is an ellipse. A cell is ~2.2× taller than wide, so a circle drawn in cells reads as a wide oval.
orbit-field.tsderives the vertical radius fromCELL_ASPECT, clips to the viewport and to reserved bands, and dedupes cells that round onto each other.Nothing is allowed to outgrow its rows. Ink 7 overlaps rather than clips, so an art block one row too tall does not get cropped — it paints over the lines above.
intro-art.tstakes a row budget and sizes the ring by whichever runs out first, rows or columns; the mark steps md → sm → none by the rows actually left over rather than by the size tier; and the ring is dropped entirely if it cannot clear the mark's clear space (one arm width) instead of resting a cross against an arm.Interaction
Any key finishes the reveal, a second key moves on — an animation nobody can interrupt is a wait, and one that vanishes on the key meant to hurry it is a screen nobody reads. The splash claims Esc too: it must not skip setup from a screen that has not yet said setup is what comes next.
introSeenAtis stamped as the splash is dismissed, not at the end of the flow.Verified in a PTY
Tests
orbit-field.test.ts(ellipse ratio, viewport clipping, dedupe, reserved bands),intro-art.test.ts(mark centred, height never exceeds budget, ring present / dropped by clearance, crosses never overwrite the mark),use-typewriter.test.tsx(progresses, settles, skip lands on the full string, empty string is done), and four newonboarding-screen.test.tsxcases including "two keys off the splash" and "Esc does not skip from the splash".Full suite: 5169 passed; the two failures on this machine (
fs-glob-real,send-message-concurrency) fail identically onmain.