TypeScript Survival Guide

Design Guide — TypeScript Survival Guide System

This is the system that keeps the course from becoming a picture book.

The problem we solved

Table of contents was a slew of shit, then a bunch of imagery. TypeScript is first, pictures are supporting. Two TOCs were rendering the same Day 1–5 bullets (static syllabus + side itinerary), and deck headers had no reserved real estate for image, use case, and hands-on — so each surface invented its own. Inception.

Single source, single TOC, reserved zones everywhere else.

The 4-zone standard

Every deck — whether in the syllabus list or at the top of its lesson section — reserves the same four zones, in the same order. If data is missing, the zone still holds space (skeleton), so layout never shifts.

  1. Media — 16:9 reserved. Syllabus list uses a 48×48 supporting thumb (not a hero) with aspect-ratio:16/9 and background: sunk. Deck header uses a 320-wide figure floated inline, not full-bleed. Troop roster uses 56×56 and 40×40 avatars, not giant portraits. All <img> have explicit width/height, loading=lazy, decoding=async.

  2. Use case — one line, always boxed left-accent border-left:2px solid accent with <strong>Use case:</strong> label, Surface-overlay 92% wash. Never italic muted. Appears directly under media, before bullets.

  3. Bullets — exhaustive 5 per deck from DECK_BULLETS (single source assets/typescript/src/ds/course-doc.ts:161). No high-level placeholders. Grouped Day 1–5: Foundations & Type System (Day 1), Functions/Classes/Generics (Day 2), Advanced Types (Day 3), Async & Architecture (Day 4), Testing/Best Practices/Capstone (Day 5).

  4. Hands-on — footer row with two pills: Try It → Lab: <name> (inline datacouch-tryit) and VS Code → Code: <path> (open lab folder, npm install, npx tsc --noEmit, Run & Debug to inspect shapes). Separated by border-top:1px dashed from bullets, pill buttons border-radius:999px.

Where each zone lives

  • Syllabus (static Hugo, layouts/page/course-decks.html:ts-syllabus) — the single table of contents. Compact grid minmax(280px,1fr), 48×48 thumbs left of title, boxed use case, 5 bullets, pill footer. Printable on one letter page at 6.5pt. The side ts-itinerary is hidden on this page to kill duplication (body:has(.ts-syllabus) .ts-side {display:none}); the syllabus is the TOC.

  • Deck header (JS datacouch-course-doc shadow DOM doc-deck) — after doc-scout (180px avatar, why-line), inserts doc-figure (320-wide, 16/9, lazy, max-width:320px, floated), doc-usecase box, doc-bullets list, doc-codelinks pill row + — open lab folder in VS Code… hint. Shadow styles use inline style + aspect-ratio so the figure reserves space before the image loads.

  • Lesson slides (slide-with-figure) — per-slide figures are 200px slide-figure (max 240, 16:9 cap), not full-page. Only used when a slide’s frontmatter declares image: {src:'/img/troop/...', alt}. Otherwise no zone, no shift.

  • Troop rails (ts-troop below the outline, not above it) — three guides as 56×56 avatars with why line, then two <details> collapsed by default: 40 scouts as 40×40 mini-cards and 23 illustrations as 40×40 thumbs. Grid verifies /img/troop parity without making the course look like a look-at-our-pictures course.

Image placement rules

  • Never full-bleed in TOC. Syllabus and side nav never use 640×360. Deck headers use 320×180 at most, floated, text wraps.
  • Reserved before load. Every image has width+height + CSS aspect-ratio:16/9 + sunk background so CLS stays 0.
  • Alt is the use case. e.g., Aaliyah checking the safety circle paper plate — Primer manners use case where SafetyCircle must be valid before any Match is struck. No PII in pixels.
  • Thumbs are supporting, not banners. If you remove the image, the card still reads as TypeScript — title + use case + 5 bullets + hands-on remains.

TypeScript first

Order is fixed: title (deck name + lesson count) → use case → 5 bullets (TypeScript concepts) → hands-on. Imagery sits beside title, not above bullets. The syllabus ts-syllabus__lede now states the contract: Image · use case · 5 bullets · hands-on Try It + VS Code lab per deck — reserved real estate, every zone utilized — but image gets 48px, TypeScript gets 5 lines.

Inception fixed

Before: ts-syllabus cards duplicated ts-itinerary side nav (same Day 1–5, same bullets, same 75 lines) plus doc-deck repeated them again. Now ts-side is hidden when ts-syllabus is present, ts-body collapses to single column, and ts-syllabus is the sole TOC. Deep links still work via history.replaceState scroll into datacouch-course-doc shadow.

Verifying

Headless Chromium (playwright) asserts in one pass: 15 syllabus cards, 15 ts-syllabus__thumb at 48×48 16/9, 15 boxed 2px solid use cases, 30 pills (15 labs + 15 code), and 15 shadow deck headers each with doc-figure img at 320×180 16/9, doc-usecase, doc-bullets, doc-codelinks, doc-drill; then screenshots at 375/1024/1920 + full.

This style guide is linked from every course footer as Design Guide so future edits have a hold on where each zone lives and what size it reserves.

Ark / Park UI + Panda CSS — token → component → object

This course is Panda CSS at the token layer, Ark UI headless at the component layer, and Park UI recipes at the object layer — all build-time, no runtime.

  • Tokens (primitive → semantic): assets/design-system/src/tokens/primitive/{color,scale}.ts and semantic/{elevation,index}.ts define the source. Primitive ink #1c2230 / paper #ffffff / plum #5e41a2 / ember #ff9900 become semantic page / prose / link / wash / surface-* / border / focus-ring via {colors.paper} _dark:{colors.ink}. Panda codegen (panda.config.ts → styled-system/, pinned) emits them as CSS variables — like a lockfile. No style props with raw hex; every color/spacing/radius flows from tokens.

  • Components (Ark headless → Park recipes): Ark provides the accessible behavior (Dialog aria-modal, Tabs aria-controls, Slider aria-valuenow, Dialog focus trap, Esc to close) — we mirror that in datacouch-course-doc shadow (role="main", aria-labelledby, slide-deck prev/next aria-label). Park UI recipes would be cva({ base, variants }) for card (syllabus), avatar (56/40), button (Try It pill min-height:44px), dialog (mobile .ts-side.is-open). Even where we hand-write ts-* classes for Hugo, the values are var(--datacouch-*) tokens, and the structure matches Park’s card/avatar anatomy so a future parkPreset swap is mechanical.

  • Objects (Panda patterns + cva): hstack/vstack/grid patterns and cva recipes are the object layer (e.g., syllabus grid: repeat(auto-fit, minmax(280px,1fr)), deck float:right 320px with aspect-ratio 16/9 reserved, ts-text-scale group). One token change (e.g., --ts-scale) cascades through all objects without touching markup — scalable, repeatable, styled in full.

Check panda.config.ts pinned styled-system/ and assets/design-system/src/tokens/ as the source of truth — no ad-hoc hex in layouts/.