mirror of
https://github.com/tiennm99/tiennm99bot.git
synced 2026-10-14 10:18:59 +00:00
docs(renderer): record adaptive label rollout
This commit is contained in:
1 parent
440ec899d2
commit
dfd20b699a
11 files changed
+598
No files matched your search
@@ -0,0 +1,34 @@
|
||||
---
|
||||
date: 2026-07-15
|
||||
session: readable-adaptive-wheel-labels-brainstorm
|
||||
---
|
||||
|
||||
# Journal: 2026-07-15 — Readable Adaptive Wheel Labels
|
||||
|
||||
## Context
|
||||
|
||||
The label `Chiều nay uống CraneTea` remains a single 9px line on a 512px wheel. The current layout wraps only when text reaches the 8px hard minimum, so it treats technical fit as sufficient even when the result is difficult to read.
|
||||
|
||||
## What Happened
|
||||
|
||||
- Reframed the issue as a readability-threshold problem rather than simply a newline problem.
|
||||
- Approved 14px as the preferred readable font-size threshold.
|
||||
- Agreed to wrap labels into two or three balanced lines when slice geometry safely permits.
|
||||
- Preserved the complete smaller label as the intentional fallback for dense wheels where multiline text would overlap adjacent slices.
|
||||
- No code was implemented during this brainstorm.
|
||||
|
||||
## Reflection
|
||||
|
||||
The existing 8px rule protects against overflow but not readability. Separating the 14px preferred threshold from the 8px hard minimum makes the intended behavior explicit: use available vertical space when geometry permits, while acknowledging that dense wheels cannot provide large text, full content, and non-overlap simultaneously.
|
||||
|
||||
## Decisions Made
|
||||
|
||||
| Decision | Rationale | Impact |
|
||||
|---|---|---|
|
||||
| Use 14px as the preferred threshold | Fixes the unreadable 9–13px one-line range | Medium-length labels wrap sooner |
|
||||
| Wrap only when two or three lines fit | Prevents adjacent-slice overlap | Layout remains bounded across supported densities |
|
||||
| Preserve full smaller text for dense wheels | Avoids truncation and API changes | Complete labels remain visible when geometry cannot support wrapping |
|
||||
|
||||
## Next Steps
|
||||
|
||||
- Create a tests-first implementation plan with `/ck:plan --tdd` using the approved brainstorm report.
|
||||
@@ -0,0 +1,34 @@
|
||||
---
|
||||
date: 2026-07-15
|
||||
session: readable-adaptive-wheel-labels
|
||||
---
|
||||
|
||||
# Journal: 2026-07-15 — Readable Adaptive Wheel Labels
|
||||
|
||||
## Context
|
||||
|
||||
The repeated example `Chiều nay uống CraneTea` remained on one line and shrank too far to read. The existing layout wrapped only when text reached the hard 8px minimum, so a one-line 9px fit bypassed wrapping despite available slice height.
|
||||
|
||||
## What Happened
|
||||
|
||||
- Used strict TDD: nine targeted regressions failed first, then all 22 focused tests passed after the layout change.
|
||||
- Separated the preferred 14px readability threshold from the hard 8px fallback. Text below 14px now wraps only when slice geometry can contain the extra lines.
|
||||
- Confirmed adaptive output for the example: 19px across three lines at 2 and 8 entries; 14px across two lines at 12 and 16 entries; complete 9px one-line fallback at 24 and 32 entries.
|
||||
- Full verification passed: lint, typecheck, 41 tests, render smoke, exact Vietnamese visual inspection, independent review at 9.8/10, and the ClaudeKit artifact gate.
|
||||
- Kept the API, Remotion composition, and wheel geometry unchanged. Temporary GIF and PNG verification artifacts were cleaned up.
|
||||
|
||||
## Reflection
|
||||
|
||||
A hard rendering minimum is not a readability target. Treating 14px as a preference and 8px as a last-resort floor lets roomy wheels use multiline labels while dense wheels retain complete text without overlap.
|
||||
|
||||
## Decisions Made
|
||||
|
||||
| Decision | Rationale | Impact |
|
||||
|----------|-----------|--------|
|
||||
| Prefer 14px before accepting a smaller one-line fit | 9–13px text can technically fit but remain hard to read | Long labels wrap earlier when space permits |
|
||||
| Gate wrapping by available slice geometry | Dense wheels cannot safely contain multiple readable lines | 24–32-entry wheels retain the complete bounded fallback |
|
||||
| Preserve existing public and rendering contracts | This is a label-layout correction | No API, composition, or geometry migration required |
|
||||
|
||||
## Next Steps
|
||||
|
||||
- Retain the Vietnamese phrase and 9–13px boundary cases as regression coverage.
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
---
|
||||
phase: 1
|
||||
title: Tests First and Implementation
|
||||
status: completed
|
||||
priority: P1
|
||||
dependencies: []
|
||||
effort: small
|
||||
---
|
||||
|
||||
# Phase 1: Tests First and Implementation
|
||||
|
||||
## Overview
|
||||
|
||||
Lock the desired readability behavior in failing unit regressions, then make the smallest layout-helper change that separates preferred readability from hard minimum fit.
|
||||
|
||||
## Context Links
|
||||
|
||||
- [Approved brainstorm](../reports/260715-1301-readable-adaptive-wheel-labels-brainstorm.md)
|
||||
- [Completed wrapping plan](../260715-1047-bold-wrapped-wheel-labels/plan.md)
|
||||
- [Project README](../../README.md)
|
||||
|
||||
## Requirements
|
||||
|
||||
- Functional: prefer 14px; wrap below that threshold when `maxLines >= 2`; keep full text at the 8px hard fallback when only one line fits safely.
|
||||
- Functional: the 512px example wraps for 2–16 options when geometry permits; 24–32 options stay bounded and complete.
|
||||
- Non-functional: deterministic output; Unicode-safe breaks; no public contract, theme, or geometry change.
|
||||
|
||||
## Architecture
|
||||
|
||||
Keep decision-making inside `getRadialLabelLayout`. Compute one-line fit first, compare it with a named 14px preferred threshold, and call the existing deterministic `getLabelLines` path only when geometry allows multiple lines. Continue sizing from the longest chosen line and bounding height by tangential arc availability. Do not add renderer state or a second wrapping implementation.
|
||||
|
||||
## Related Code Files
|
||||
|
||||
| Action | Absolute path | Purpose |
|
||||
|---|---|---|
|
||||
| Modify | `C:\Users\miti99\Workspaces\tiennm99\wheelofnames\test\wheel-label-layout.test.js` | Add failing threshold, boundary, Unicode, short-label, and dense-layout regressions. |
|
||||
| Modify | `C:\Users\miti99\Workspaces\tiennm99\wheelofnames\src\remotion\wheel-label-layout.js` | Separate 14px preferred readability from the 8px hard minimum and geometry-gate wrapping. |
|
||||
| Conditional modify | `C:\Users\miti99\Workspaces\tiennm99\wheelofnames\src\remotion\WheelComposition.jsx` | Only if implementation proves new layout metadata is required; otherwise leave unchanged. |
|
||||
|
||||
## Implementation Steps
|
||||
|
||||
### Tests Before
|
||||
|
||||
1. Add a table-driven regression for `Chiều nay uống CraneTea` at size 512 and representative supported counts across 2–16. Assert multiple lines only when computed geometry permits, full text reconstruction, bounded height, and wrapped `fontSize >= 14`.
|
||||
2. Add targeted cases whose current one-line fit lands at 9, 10, 11, 12, and 13px. Assert they no longer remain one line when `maxLines >= 2`.
|
||||
3. Run `pnpm test -- test/wheel-label-layout.test.js`; record that new regressions fail against the current 8px-only trigger for the intended reason.
|
||||
|
||||
### Refactor
|
||||
|
||||
4. Introduce a named preferred label font size of 14px beside the existing 8px minimum; keep their responsibilities separate.
|
||||
5. Change the wrap decision from equality with the hard minimum to `singleLineFontSize < preferredLabelFontSize && maxLines >= 2`.
|
||||
6. Reuse `getLabelLines`, longest-line sizing, content width, and height bounding. Avoid API changes and avoid touching `WheelComposition.jsx` unless metadata is strictly necessary.
|
||||
7. Run the focused test file until the tests-before regressions pass.
|
||||
|
||||
### Tests After
|
||||
|
||||
8. Add or refine boundary coverage: exactly 14px remains one line; 13px wraps when permitted; one-line-only geometry preserves full text at the smaller fallback.
|
||||
9. Retain regressions for 384px/512px short labels on one line, 24–32 dense layouts bounded, whitespace normalization, unbroken tokens, and Vietnamese/emoji grapheme reconstruction without broken segments.
|
||||
10. Assert no selected layout exceeds available tangential height and all selected lines fit padded `contentWidth` under the estimator.
|
||||
|
||||
### Regression Gate
|
||||
|
||||
11. Run `pnpm test -- test/wheel-label-layout.test.js`.
|
||||
12. Run `pnpm typecheck` and `pnpm lint` before phase completion.
|
||||
|
||||
## Todo List
|
||||
|
||||
- [x] Tests-before cases fail for the existing 9–13px blind spot.
|
||||
- [x] Preferred and hard-minimum constants have distinct roles.
|
||||
- [x] Geometry-gated wrapping passes exact example and boundary tests.
|
||||
- [x] Unicode, short-label, and dense fallback regressions pass.
|
||||
- [x] Focused tests, typecheck, and lint pass.
|
||||
|
||||
## Success Criteria
|
||||
|
||||
- [x] `Chiều nay uống CraneTea` wraps at 512px for 2–16 options whenever `maxLines >= 2`, reconstructs exactly, and targets at least 14px.
|
||||
- [x] Short labels remain one line at supported sizes.
|
||||
- [x] 24–32 option layouts preserve full text at the smaller fallback and remain height-bounded.
|
||||
- [x] Vietnamese graphemes and existing unbroken-token behavior remain intact.
|
||||
- [x] No API/schema, theme, geometry, or winner metadata code changes.
|
||||
- [x] Focused tests, typecheck, and lint pass.
|
||||
|
||||
## Risk Assessment
|
||||
|
||||
- Risk: a hard 14px trigger may wrap labels that are only marginally smaller. Mitigation: exact 13/14px boundary tests and short-label fixtures.
|
||||
- Risk: wrapping at 16 options may exceed tangential space. Mitigation: derive `maxLines` from existing arc height and assert the final box stays bounded.
|
||||
- Risk: width estimation can split Vietnamese incorrectly. Mitigation: preserve `Intl.Segmenter` and assert exact grapheme-safe reconstruction.
|
||||
|
||||
## Security Considerations
|
||||
|
||||
No new input, I/O, authentication, or external dependency surface. Existing request validation remains unchanged.
|
||||
|
||||
## Next Steps
|
||||
|
||||
Proceed to renderer verification only after the regression gate is green.
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
---
|
||||
phase: 2
|
||||
title: Renderer Verification
|
||||
status: completed
|
||||
priority: P1
|
||||
dependencies:
|
||||
- 1
|
||||
effort: small
|
||||
---
|
||||
|
||||
# Phase 2: Renderer Verification
|
||||
|
||||
## Overview
|
||||
|
||||
Run the full project gates and produce a targeted Vietnamese rendering witness that confirms readable wrapping without clipping or adjacent-slice overlap.
|
||||
|
||||
## Context Links
|
||||
|
||||
- [Approved brainstorm](../reports/260715-1301-readable-adaptive-wheel-labels-brainstorm.md)
|
||||
- [Project README](../../README.md)
|
||||
- [Render benchmarks](../../docs/render-benchmarks.md)
|
||||
|
||||
## Requirements
|
||||
|
||||
- Functional: verify exact Vietnamese text visually at 512px and low/medium supported density.
|
||||
- Non-functional: all repository gates pass; public API contracts remain unchanged; no generated GIF remains in version control or the worktree.
|
||||
|
||||
## Architecture
|
||||
|
||||
Verification exercises the pure layout helper through Vitest and the existing Remotion render pipeline through project scripts. Prefer changing only a Vietnamese fixture input to include the exact phrase; do not add a new renderer path. API compatibility is established through existing schema/route tests and diff inspection.
|
||||
|
||||
## Related Code Files
|
||||
|
||||
| Action | Absolute path | Purpose |
|
||||
|---|---|---|
|
||||
| Verify | `C:\Users\miti99\Workspaces\tiennm99\wheelofnames\src\remotion\wheel-label-layout.js` | Confirm final threshold and geometry logic. |
|
||||
| Verify | `C:\Users\miti99\Workspaces\tiennm99\wheelofnames\test\wheel-label-layout.test.js` | Confirm all targeted and regression cases. |
|
||||
| Conditional modify | `C:\Users\miti99\Workspaces\tiennm99\wheelofnames\scripts\render-fixtures.js` | Smallest fixture-input-only change needed to render `Chiều nay uống CraneTea`. |
|
||||
| Verify only | `C:\Users\miti99\Workspaces\tiennm99\wheelofnames\src\remotion\WheelComposition.jsx` | Confirm bold rendering consumes existing `lines`, `fontSize`, and bounded height unchanged. |
|
||||
| Cleanup | `C:\Users\miti99\Workspaces\tiennm99\wheelofnames\fixtures\*.gif` | Remove generated visual artifacts after inspection. |
|
||||
|
||||
## Implementation Steps
|
||||
|
||||
1. Run `pnpm lint`, `pnpm typecheck`, and `pnpm test`; require zero failures.
|
||||
2. Run `pnpm render:smoke` to protect the 384px renderer, bundle reuse, and GIF output path.
|
||||
3. Render a 512px Vietnamese witness containing `Chiều nay uống CraneTea`. Prefer the existing `vietnamese` fixture with the smallest input-only edit; run `pnpm render:fixtures` when that fixture path is used.
|
||||
4. Inspect the witness at a stable frame: exact graphemes present, bold text, two/three balanced lines where geometry permits, font visually readable, no radial clipping, and no adjacent-slice overlap.
|
||||
5. Confirm dense behavior through unit cases for 24–32 options; render an additional dense witness only if unit bounds or visual inspection are ambiguous.
|
||||
6. Run existing route/schema tests as part of `pnpm test`; inspect the diff to confirm no `/api` request/response schema, response headers, themes, or wheel geometry changed.
|
||||
7. Remove all generated GIFs and temporary render artifacts. Run `git status --short` and confirm only intended source/test/optional fixture input and plan files remain.
|
||||
8. Re-run any gate affected by cleanup or fixture edits.
|
||||
|
||||
## Todo List
|
||||
|
||||
- [x] Full lint, typecheck, and test suite pass.
|
||||
- [x] `render:smoke` passes.
|
||||
- [x] Vietnamese 512px witness passes visual inspection.
|
||||
- [x] Dense 24–32 fallback remains bounded and complete.
|
||||
- [x] API/schema/theme/geometry contracts remain unchanged.
|
||||
- [x] Generated artifacts are removed.
|
||||
|
||||
## Success Criteria
|
||||
|
||||
- [x] `pnpm lint`, `pnpm typecheck`, and `pnpm test` pass.
|
||||
- [x] `pnpm render:smoke` produces a valid GIF.
|
||||
- [x] Targeted Vietnamese visual evidence confirms readable wrapping and intact graphemes without clipping/overlap.
|
||||
- [x] 24–32 dense layouts retain complete labels within computed height.
|
||||
- [x] Winner metadata and `/api` behavior remain covered and unchanged.
|
||||
- [x] No generated GIF or temporary renderer artifact remains.
|
||||
|
||||
## Risk Assessment
|
||||
|
||||
- Risk: visual verification is subjective. Mitigation: pair it with numeric font-size, width, reconstruction, and height assertions.
|
||||
- Risk: full fixture rendering is slow. Mitigation: use the existing targeted fixture and avoid adding redundant fixtures.
|
||||
- Risk: generated outputs get committed. Mitigation: cleanup plus final `git status --short` inspection.
|
||||
|
||||
## Security Considerations
|
||||
|
||||
No security behavior changes. Verification must not expose tokens or persist environment files; production API authentication tests remain untouched.
|
||||
|
||||
## Next Steps
|
||||
|
||||
Mark the plan complete only after both automated and visual gates pass and artifacts are clean.
|
||||
@@ -0,0 +1,62 @@
|
||||
---
|
||||
title: Readable Adaptive Wheel Labels
|
||||
description: >-
|
||||
Wrap medium-length wheel labels at a preferred 14px readability threshold
|
||||
while preserving bounded full-text fallback for dense wheels.
|
||||
status: completed
|
||||
priority: P2
|
||||
branch: main
|
||||
tags:
|
||||
- bugfix
|
||||
- frontend
|
||||
- renderer
|
||||
- tdd
|
||||
blockedBy: []
|
||||
blocks: []
|
||||
created: '2026-07-15T06:29:40.959Z'
|
||||
createdBy: 'ck:plan'
|
||||
source: skill
|
||||
---
|
||||
|
||||
# Readable Adaptive Wheel Labels
|
||||
|
||||
## Overview
|
||||
|
||||
Fix the 9–13px readability blind spot in radial wheel labels. Keep 8px as the hard full-text fallback, but prefer deterministic two/three-line wrapping when the one-line result is below 14px and slice geometry permits. Preserve short-label behavior, Vietnamese graphemes, API contracts, themes, and wheel geometry.
|
||||
|
||||
Approved design: [Readable Adaptive Wheel Labels Brainstorm](../reports/260715-1301-readable-adaptive-wheel-labels-brainstorm.md).
|
||||
|
||||
## Phases
|
||||
|
||||
| Phase | Name | Status |
|
||||
|-------|------|--------|
|
||||
| 1 | [Tests First and Implementation](./phase-01-tests-first-and-implementation.md) | Completed |
|
||||
| 2 | [Renderer Verification](./phase-02-renderer-verification.md) | Completed |
|
||||
|
||||
## Dependencies
|
||||
|
||||
- Cross-plan dependencies: none. The completed [Bold Wrapped Wheel Labels](../260715-1047-bold-wrapped-wheel-labels/plan.md) plan is implementation history, not a blocker.
|
||||
- Runtime: existing JavaScript + JSDoc, React, Remotion, and CSS renderer stack.
|
||||
- Quality gates: Node.js 24, `pnpm lint`, `pnpm typecheck`, `pnpm test`, `pnpm render:smoke`, and Vietnamese visual evidence.
|
||||
|
||||
## Scope
|
||||
|
||||
- Primary touchpoints: `src/remotion/wheel-label-layout.js` and `test/wheel-label-layout.test.js`.
|
||||
- Fixture input may change only when needed for the Vietnamese visual witness.
|
||||
- `WheelComposition.jsx` changes only if layout metadata is proven necessary.
|
||||
- No API/schema, theme, wheel geometry, truncation, custom font, or curved-text changes.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- At 512px, `Chiều nay uống CraneTea` wraps for 2–16 options whenever geometry permits; wrapped text targets at least 14px.
|
||||
- Ordinary short labels remain one line.
|
||||
- 24–32 option layouts remain bounded and preserve complete text at the smaller fallback size.
|
||||
- Vietnamese grapheme clusters remain intact.
|
||||
- No API/schema, theme, winner metadata, or wheel geometry changes.
|
||||
- Full automated gates and visual renderer evidence pass; generated artifacts are removed.
|
||||
|
||||
## Risks
|
||||
|
||||
- Estimated width may differ from browser glyph width. Mitigate with exact unit boundaries plus rendered Vietnamese evidence.
|
||||
- Threshold changes can over-wrap short labels. Mitigate with 384px and 512px one-line regressions.
|
||||
- Dense slices cannot satisfy large text and non-overlap simultaneously. Mitigate with an explicit bounded full-text fallback.
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"decision": "PASS",
|
||||
"disprovenClaims": [],
|
||||
"unverifiedClaims": [],
|
||||
"missingProof": [],
|
||||
"reachableRegressions": [],
|
||||
"evidence": [
|
||||
"The finalize artifact gate requires this file even though no separate high-risk adversarial review was otherwise warranted.",
|
||||
"Strict threshold boundaries, all supported sizes, representative densities, maximum-length candidate complexity, combining marks, emoji graphemes, API metadata tests, and Remotion smoke output were independently checked."
|
||||
]
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"skill": "ck:code-review",
|
||||
"mode": "review",
|
||||
"task": "Independent review of readable adaptive wheel labels",
|
||||
"acceptanceCriteria": [
|
||||
"at 512px the exact Vietnamese phrase wraps for 2, 8, 12, and 16 options when at least two lines fit, with wrapped font size at least 14px",
|
||||
"ordinary short labels remain one line, including the prior 384px alpha, beta, gamma, and delta regression cases",
|
||||
"at 24 and 32 options the exact phrase remains complete, one-line, width-fitting, and height-bounded at the smaller fallback size",
|
||||
"Vietnamese and unbroken Unicode input preserve text and grapheme boundaries",
|
||||
"radial coordinates, track width, content width, padding, and height bounds remain unchanged",
|
||||
"WheelComposition, GIF route, winner metadata, API schemas, themes, geometry, environment, and public contracts remain unchanged"
|
||||
],
|
||||
"touchpoints": [
|
||||
"src/remotion/wheel-label-layout.js",
|
||||
"test/wheel-label-layout.test.js",
|
||||
"src/remotion/WheelComposition.jsx",
|
||||
"src/routes/gif.js"
|
||||
],
|
||||
"publicContracts": [
|
||||
"POST /api/gif request and response behavior remains unchanged",
|
||||
"X-Wheel-Winner-Index and X-Wheel-Winner metadata remain unchanged",
|
||||
"getRadialLabelLayout continues returning the same presentation metadata shape"
|
||||
],
|
||||
"blastRadius": [
|
||||
"one-line versus multiline selection for wheel labels whose fitted one-line size is 9 through 13px",
|
||||
"Remotion text rendering across supported 384px, 480px, and 512px sizes and 2 through 32 options"
|
||||
],
|
||||
"scoutSummary": "The pending implementation changes one decision predicate inside getRadialLabelLayout: wrapping is now selected below a named 14px preferred threshold when geometry permits multiple lines. Existing deterministic word/grapheme splitting, longest-line sizing, 8px hard floor, radial coordinates, content width, height bounding, and WheelComposition consumption are reused unchanged. The diff adds focused threshold, Vietnamese, short-label, and dense-fallback tests; no API, schema, route, theme, geometry, environment, or composition file is modified."
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"decision": "PASS",
|
||||
"score": 9.8,
|
||||
"criticalCount": 0,
|
||||
"warningCount": 0,
|
||||
"suggestionCount": 1,
|
||||
"criticals": [],
|
||||
"warnings": [],
|
||||
"suggestions": [
|
||||
"If product requirements later demand every allowed 40-character label be visually complete on dense 384px wheels, define a separate truncation, sub-8px, or larger-canvas policy; that pre-existing geometry trade-off is outside this threshold fix."
|
||||
],
|
||||
"acceptanceCoverage": [
|
||||
"the 14px preferred threshold is separate from the unchanged 8px hard minimum and uses strict less-than semantics, so exactly 14px remains one line",
|
||||
"the exact 512px Vietnamese phrase wraps at counts 2 and 8 into three 19px lines and at counts 12 and 16 into two 14px lines",
|
||||
"the exact phrase remains complete, one-line, width-fitting, and height-bounded at 9px for counts 24 and 32",
|
||||
"ordinary short labels remain one line, including alpha, beta, gamma, and delta at 384px",
|
||||
"word and Intl.Segmenter grapheme paths are unchanged; text reconstruction, combining-mark, emoji, and Vietnamese checks preserve content",
|
||||
"radial x/y coordinates, rotation, track width, padded content width, line-height estimator, and available-height bounding are unchanged",
|
||||
"WheelComposition, GIF route, winner headers, request schema, themes, geometry, environment handling, and public API files have no pending diff"
|
||||
],
|
||||
"regressionProof": [
|
||||
"fresh lint and JSDoc typecheck pass",
|
||||
"all 41 tests pass",
|
||||
"the supplied TDD red state had exactly 9 intended failures and the green state has 22 of 22 focused tests passing",
|
||||
"a fresh supported-size and density probe confirms all requested threshold and short-label outputs",
|
||||
"fresh Remotion smoke render completes with the canonical 407905-byte GIF",
|
||||
"the supplied exact Vietnamese visual witness confirms bold three-line rendering at 19px with intact diacritics and no clipping or overlap",
|
||||
"git diff inspection confirms only the layout helper and its test are implementation changes"
|
||||
],
|
||||
"contractStatus": "OK",
|
||||
"blockingReasons": [],
|
||||
"sideEffects": [
|
||||
"9 through 13px one-line candidates now become balanced multiline labels when geometry permits",
|
||||
"exactly 14px remains one line by design",
|
||||
"low-density examples use three lines while medium-density examples use two lines, derived from the existing arc-height estimator",
|
||||
"dense 24 and 32 option examples retain the existing complete one-line 9px fallback",
|
||||
"line-candidate work increases for newly wrapped labels but remains bounded by 40 input characters and three lines; a 1000-iteration worst-case probe took 1496.33ms"
|
||||
]
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"highRisk": false,
|
||||
"reasons": [
|
||||
"the production diff is a one-line presentation decision change plus one named constant",
|
||||
"the 8px hard floor, three-line cap, Unicode segmentation, track coordinates, and renderer contract are unchanged",
|
||||
"candidate generation remains bounded by the existing 40-character request limit and three-line maximum",
|
||||
"fresh unit, static, matrix, performance, and Remotion smoke evidence cover the affected path"
|
||||
],
|
||||
"autoStopRequired": false,
|
||||
"humanApproved": true,
|
||||
"largeDiff": false,
|
||||
"sideEffects": [
|
||||
"labels whose one-line fitted size is 9 through 13px now wrap when slice geometry allows at least two lines",
|
||||
"a one-line fit of exactly 14px intentionally remains one line",
|
||||
"dense slices that cannot support two lines intentionally retain the existing smaller complete-string fallback",
|
||||
"the existing 8px hard floor can still make arbitrary maximum-length dense labels wider than the content box; this limitation predates and is not expanded by the threshold-only source change"
|
||||
]
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
{
|
||||
"commands": [
|
||||
{
|
||||
"command": "pnpm lint",
|
||||
"status": "pass",
|
||||
"exitCode": 0,
|
||||
"timestamp": "2026-07-15T14:34:24.0775388+07:00",
|
||||
"summary": "Fresh ESLint run completed without errors."
|
||||
},
|
||||
{
|
||||
"command": "pnpm typecheck",
|
||||
"status": "pass",
|
||||
"exitCode": 0,
|
||||
"timestamp": "2026-07-15T14:34:24.0775388+07:00",
|
||||
"summary": "Fresh TypeScript JSDoc checking completed without errors."
|
||||
},
|
||||
{
|
||||
"command": "pnpm test",
|
||||
"status": "pass",
|
||||
"exitCode": 0,
|
||||
"timestamp": "2026-07-15T14:34:24.0775388+07:00",
|
||||
"summary": "All 5 test files and 41 tests passed, including 22 focused wheel-label tests and 4 GIF route metadata tests."
|
||||
},
|
||||
{
|
||||
"command": "node --input-type=module -e <requested Vietnamese, dense-fallback, 384px short-label, and Unicode boundary probe>",
|
||||
"status": "pass",
|
||||
"exitCode": 0,
|
||||
"timestamp": "2026-07-15T14:34:24.0775388+07:00",
|
||||
"summary": "The exact 512px Vietnamese phrase produced three lines at 19px for counts 2 and 8, two lines at 14px for counts 12 and 16, and one complete width-fitting line at 9px for counts 24 and 32. The 384px alpha, beta, gamma, and delta cases remained one line, combining-mark and emoji inputs reconstructed exactly, and the command reported zero failures. A separate exploratory matrix documented the pre-existing 8px width-floor limit for unrelated arbitrary maximum-length dense labels."
|
||||
},
|
||||
{
|
||||
"command": "node --input-type=module -e <1000-iteration worst-case line-candidate timing probe>",
|
||||
"status": "pass",
|
||||
"exitCode": 0,
|
||||
"timestamp": "2026-07-15T14:34:24.0775388+07:00",
|
||||
"summary": "One thousand 40-character, three-line candidate layouts completed in 1496.33ms; request limits cap candidates and the measured cost does not indicate a renderer blocker."
|
||||
},
|
||||
{
|
||||
"command": "pnpm render:smoke",
|
||||
"status": "pass",
|
||||
"exitCode": 0,
|
||||
"timestamp": "2026-07-15T14:34:24.0775388+07:00",
|
||||
"summary": "Fresh Remotion smoke render produced a 407905-byte GIF in 2498ms; the generated GIF was removed after verification."
|
||||
},
|
||||
{
|
||||
"command": "git diff --check",
|
||||
"status": "pass",
|
||||
"exitCode": 0,
|
||||
"timestamp": "2026-07-15T14:34:24.0775388+07:00",
|
||||
"summary": "No whitespace errors were reported."
|
||||
}
|
||||
],
|
||||
"tddEvidence": {
|
||||
"red": "Before the source predicate changed, 9 intended readability regressions failed while 13 existing focused tests passed.",
|
||||
"green": "After the source predicate changed, all 22 focused tests passed."
|
||||
},
|
||||
"visualEvidence": {
|
||||
"exactPhrase": "Chiều nay uống CraneTea",
|
||||
"result": "A supplied 512px repeated-phrase witness rendered bold text on three balanced lines at 19px with intact diacritics and no clipping, overlap, or boundary breach.",
|
||||
"bytes": 542174,
|
||||
"durationMs": 2667
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
---
|
||||
title: "Readable Adaptive Wheel Labels Brainstorm"
|
||||
date: 2026-07-15
|
||||
status: approved
|
||||
mode: markdown
|
||||
tags: [brainstorm, renderer, typography, ux]
|
||||
---
|
||||
|
||||
# Readable Adaptive Wheel Labels Brainstorm
|
||||
|
||||
## Summary
|
||||
|
||||
Approved direction: treat 14px as the preferred readability threshold. Attempt one-line fit first; when it falls below 14px and slice height permits, wrap deterministically into two or three balanced lines. For dense wheels that cannot safely fit multiple lines, preserve the complete label at the existing smaller fallback size.
|
||||
|
||||
## Problem-First Analysis
|
||||
|
||||
### 1. Solution-Jumping Diagnosis
|
||||
|
||||
The request is not fundamentally “add more newlines.” The observed failure is that the current wrapping trigger models technical fit at the 8px hard floor, not practical readability.
|
||||
|
||||
### 2. Underlying Problem
|
||||
|
||||
Users cannot comfortably read medium-length option labels even when the slice has enough vertical space to display them across multiple lines.
|
||||
|
||||
### 3. Assumption Challenges
|
||||
|
||||
| Assumption | Risk if wrong | Validation |
|
||||
|---|---|---|
|
||||
| 8px is a sufficient wrapping threshold | Text technically fits but remains unreadable | Probe and render 9–13px labels |
|
||||
| Every long label can wrap | Dense slices overlap adjacent labels | Derive maximum lines from slice arc height |
|
||||
| Character count predicts readability | Wide/narrow glyphs and Vietnamese marks vary | Continue using estimated rendered width |
|
||||
| Full text must always remain visible | Dense wheels may force unreadably small type | Preserve full text as explicit dense fallback |
|
||||
|
||||
### 4. Problem Statement
|
||||
|
||||
- Users: GIF API consumers rendering descriptive wheel entries.
|
||||
- Context: supported 384px, 480px, and 512px wheels with 2–32 options.
|
||||
- Struggle: a phrase such as `Chiều nay uống CraneTea` remains one line at 9px on a 512px wheel.
|
||||
- Cause: wrapping only activates when the one-line fit reaches exactly 8px.
|
||||
- Consequence: available slice height goes unused and labels are difficult to read.
|
||||
- Success: medium-length labels wrap at readable sizes whenever geometry permits, without overlap or API changes.
|
||||
|
||||
### 5. Alternative Framings
|
||||
|
||||
1. Threshold problem: the 8px trigger is too late; use a preferred readable size.
|
||||
2. Geometry problem: allocate lines from both radial width and tangential slice height.
|
||||
3. Information-density problem: dense wheels cannot simultaneously preserve full text, large type, and non-overlap.
|
||||
|
||||
### 6. Evidence Status
|
||||
|
||||
Medium. The user supplied a concrete production-style Vietnamese label, and direct layout probes reproduce the issue across all option counts at 512px. Existing tests cover only the 8px boundary, not the unreadable 9–13px range.
|
||||
|
||||
### 7. Validation Plan
|
||||
|
||||
- Add exact layout cases for `Chiều nay uống CraneTea` at every supported size.
|
||||
- Cover low, medium, and dense option counts.
|
||||
- Assert preferred font size when wrapping is possible and bounded height when it is not.
|
||||
- Render a Vietnamese fixture and visually check boldness, clipping, line balance, and adjacent-slice separation.
|
||||
- Kill the design if 14px wrapping causes overlap at supported counts where the helper reports multiple lines.
|
||||
|
||||
### 8. Stakeholder Message
|
||||
|
||||
We will improve readability without changing the API: labels below the preferred 14px one-line size will wrap when the slice has room. Dense wheels will continue showing complete text at a smaller size because enlarging it would overlap neighboring slices.
|
||||
|
||||
## Evaluated Approaches
|
||||
|
||||
### A. Fixed Readability Threshold — Approved
|
||||
|
||||
Trigger wrapping when one-line fit is below 14px and at least two lines fit safely.
|
||||
|
||||
- Pros: predictable UX; directly fixes 9–13px blind spot; easy to test; keeps current geometry model.
|
||||
- Cons: 14px is a product decision; dense wheels still require small text.
|
||||
- Example at 512px: `Chiều / nay uống / CraneTea` for low counts; two balanced lines when only two fit.
|
||||
|
||||
### B. Relative Threshold
|
||||
|
||||
Wrap when one-line fit falls below a percentage of the computed base font size.
|
||||
|
||||
- Pros: scales with wheel and option density.
|
||||
- Cons: harder to explain; may still allow unreadably small absolute sizes; more boundary churn.
|
||||
|
||||
### C. Always Wrap Multiword Labels
|
||||
|
||||
Prefer two or three lines for every multiword entry.
|
||||
|
||||
- Pros: maximizes font size for phrases.
|
||||
- Cons: over-wraps short labels, increases visual noise, and repeats the regression already caught for ordinary names.
|
||||
|
||||
## Approved Design
|
||||
|
||||
1. Keep deterministic, Unicode-safe word/grapheme splitting.
|
||||
2. Compute one-line size against padded content width.
|
||||
3. Define a preferred readable threshold of 14px, separate from the existing 8px hard minimum.
|
||||
4. If one-line size is at least 14px, preserve one line.
|
||||
5. If it is below 14px and `maxLines >= 2`, choose the most balanced two/three-line layout and size from its longest line.
|
||||
6. If geometry allows only one line, preserve the complete label using the existing 8px minimum behavior.
|
||||
7. Keep bold weight, radial track footprint, rotations, API schemas, themes, and winner metadata unchanged.
|
||||
|
||||
## Exact Requirements
|
||||
|
||||
- Expected output: updated Remotion label layout behavior plus focused tests and visual render evidence.
|
||||
- Acceptance: the example phrase wraps at 512px for 2–16 options when geometry permits; resulting wrapped text targets at least 14px; ordinary short labels remain one line; 24–32 option layouts remain bounded and preserve full text; Vietnamese graphemes remain intact.
|
||||
- Out of scope: truncation, tooltips, larger API sizes, curved SVG text, API/schema changes, theme redesign.
|
||||
- Constraints: Node.js 24, JavaScript + JSDoc, existing React/Remotion/CSS patterns, deterministic output.
|
||||
- Touchpoints: `src/remotion/wheel-label-layout.js`, `test/wheel-label-layout.test.js`, and renderer fixture/smoke evidence; `WheelComposition.jsx` only if new layout metadata is required.
|
||||
|
||||
## Risks and Mitigations
|
||||
|
||||
| Risk | Mitigation |
|
||||
|---|---|
|
||||
| 14px bold estimate still clips | Measure against padded content width and visually render fixtures |
|
||||
| Dense wheels remain small | Document as intentional geometry fallback; keep full text |
|
||||
| New threshold re-wraps short names | Regression-test 384px smoke labels and 512px short labels |
|
||||
| Vietnamese split corruption | Preserve `Intl.Segmenter` grapheme fallback and add accented-text tests |
|
||||
|
||||
## Success Metrics
|
||||
|
||||
- Example phrase no longer renders as a 9px single line where two/three lines fit.
|
||||
- No supported-size regression for short one-line labels.
|
||||
- No label box exceeds its computed tangential height.
|
||||
- Lint, typecheck, tests, `render:smoke`, and a Vietnamese visual fixture pass.
|
||||
- Public API contracts remain unchanged.
|
||||
|
||||
## Unresolved Questions
|
||||
|
||||
None. Dense-wheel fallback and 14px threshold are approved.
|
||||
|
||||
## Next Step
|
||||
|
||||
Create a tests-first implementation plan because this changes existing label layout behavior with established regression coverage.
|
||||
Reference in new issue
Block a user