fix(text): draw word-granularity units with the tracking they were laid out with - #208
Merged
Conversation
The cell alpha oscillated over 0.10..1.00, so a cell never actually went out. A lattice whose cells only dip to a tenth still reads as a fixed field of permanent dots, just dimmer — which is not what an animated texture is for. 0.5 + 0.5 * sin gives the full 0 → 1 → 0. The phase still comes from each cell's own hash, or the whole field blinks in unison. The test pins the range rather than the fact that something moves: it samples 400 instants and asserts the floor goes under 0.01 and the ceiling over 0.99. "It animates" and "it reaches zero" are different claims.
…t a corner Measured on a reference piece, over 15 frames (0.5 s): the right and top edges stay pinned to the frame while the left travels 2160 -> 0 and the bottom 1480 -> 2152. Both moving edges advance at once, and the incoming scene sits still behind the growing window — it is uncovered, not pushed. None of the thirteen existing types expresses that. wipe_* moves a single full-width band on one axis, iris is a circle, and slide translates both frames together. The closest approximation, a dissolve, loses the whole gesture. `corner` selects which two edges are pinned: top_right (the measured default), top_left, bottom_right, bottom_left. It is inert for every other type. Five tests pin the geometry rather than describe it: the anchored edges never move, the travelling ones open monotonically in the direction the corner names, the ends are empty and full, each corner anchors its own pair, and out-of-range progress clamps instead of inverting the rectangle — an inverted rect clips to nothing and the transition would silently look like a cut.
…id out with
A word-granularity char animation advances its cursor by the width measured
*with* letter-spacing, but apply_text_anim_preset drew every unit at 0.0. With
negative tracking the glyphs then overrun their slot by |tracking| * (chars-1)
and eat into the following space:
letter-spacing: -2, 54 px, granularity: word
"without a maintenance window" -> "withouta maintenancewindow"
The overrun is a fixed number of pixels, so it only shows once it approaches a
space's width: invisible on 143 px display type, fatal at 54 px. Isolated by
rendering the same string five ways — neither word granularity nor negative
tracking does it alone, only the pair.
The character path passes 0.0 explicitly: a single character has no internal
tracking, and stating it keeps the two branches from drifting apart.
Also adds rules/terminal-product-register.md, the measured visual register this
was found while reproducing.
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
A word-granularity char animation advances its cursor by the width measured with letter-spacing, but
apply_text_anim_presetdrew every unit at0.0. With negative tracking the glyphs overrun their slot by|tracking| * (chars - 1)and eat into the following space.How it hides
The overrun is a fixed number of pixels, so it only shows once it approaches the width of a space:
Which is why the same register renders correctly on display type and breaks on the smaller opening line.
Isolated by rendering one string five ways — no animation at tracking 0 and −2, word granularity at 0 and −2, and a plain
fade_inat −2. Only the pair (word granularity × negative tracking) reproduces it.Fix
Thread the tracking into
apply_text_anim_presetand draw with it. The character path passes0.0explicitly rather than by omission: a single character has no internal tracking, and saying so keeps the two branches from drifting apart.What I could not do
I have no automated test for this. I wrote three, and all three passed in both the fixed and the broken state — a test that cannot fail on the bug it targets is worse than none, so I removed it rather than ship advertised coverage that does not exist. The overall ink span does not move (the cursor positions are unchanged), and the inter-word gap measurement I tried could not separate word gaps from letter gaps reliably at this size. The fix is verified visually, on a five-case probe, in both directions.
Worth a follow-up by someone who knows the text pixel-test helpers better than I do.
Also in this PR
rules/terminal-product-register.md— the measured visual register this was found while reproducing: palette, the two type scales (with the stem-to-cap method for picking a weight, which is what caught a wrong reading here), the composed terminal pane, beat proportions, and the traps collected along the way.cargo test --workspacegreen,cargo fmt --checkandcargo clippy --all-targets -- -D warningsclean.