Python Guides — Level Personification Design
Date: 2026-06-23 Status: Approved, ready for implementation planning Scope: Visual only. No teaching content is rewritten in this phase.
Summary
Turn the three Python reading levels (Beginner / Intermediate / Deep Dive) into three named guides with personalities and avatars. The learner "picks a guide" during onboarding, and from then on every recap callout (<CharacterMessage>) in the Python course speaks as that guide — its avatar and name reflect the selected guide, while the recap's existing topic title is preserved as a sub-label.
The guides reuse the personas from the existing /persona-preview test (Crooked Orbit crew): Juno (beginner), Ace (intermediate), Sol (deep dive).
This is a deliberately contained, visual-only change. The bubble body text is not rewritten in this phase — only the speaker identity (avatar + name) and a topic eyebrow are added.
Goals
- Personify the three levels as guides with avatar + name + one-line personality.
- "Pick your guide" onboarding flow (reuse the existing WelcomeModal level step).
- Every Python recap callout shows the selected guide's avatar and name, live-updating when the learner switches guide.
- Keep each recap's existing topic title (currently in the
nameattribute) visible as a sub-label so nothing is lost. - Zero markdown content edits across the ~370 existing
<CharacterMessage>callouts.
Non-Goals
- Rewriting any teaching content or recap body text (future phase).
- Adding per-guide voice/tone to the bubble copy (future phase).
- Applying guides to the How AI Works track or any non-Python pages.
- Changing the
bughouseproject page, which has its own named characters.
Key Context (verified)
- Level state lives in
docs/.vitepress/theme/composables/useDocPrefs.tsaslevel: 'beginner' | 'intermediate' | 'advanced', persisted to localStorage and global. showLevel: truefrontmatter is present on exactly the 13 leveled Python chapters (and their localized copies underes/,pt/, etc.). It is not present onhow-ai-works/*orpython/bughouse.md. This makes it a clean, Python-only signal for "guide mode."CharacterMessage.vuecurrently picks an avatar by: explicitcharprop →CHARACTER_CHARSname lookup (only Juno/Ace/Sol mapped) → hash of thenamestring. In leveled Python chapters,nameholds the recap topic (e.g. "Storing a value"), so today each recap shows a topic title + a hash-random avatar.- Named-character bubbles (
Cass,Dex,Pip,Zee,Orla) appear only inpython/bughouse.md, which has noshowLevel, so they are naturally excluded from guide mode and remain unchanged. - The three guide avatars already exist:
docs/public/pixel_chars/f468.webp(Juno)docs/public/pixel_chars/f704.webp(Ace)docs/public/pixel_chars/f509.webp(Sol)
- The existing onboarding entry point is
WelcomeModal.vue(first-visit modal asking language + level + theme). Level pickers also live inFloatingDocPrefs.vueandDocLevelBadge.vue.
Design
1. Guide config — single source of truth
New file: docs/.vitepress/theme/composables/guides.ts.
Exports a map keyed by DocLevel:
| level | name | pronouns | bars | avatar | blurb |
|---|---|---|---|---|---|
beginner | Juno | she/her | 1 | /pixel_chars/f468.webp | Onboarding lead. Warm and patient. |
intermediate | Ace | they/them | 2 | /pixel_chars/f704.webp | Systems engineer. Practical, build-first. |
advanced | Sol | she/her | 3 | /pixel_chars/f509.webp | Chief engineer. Dry, jaded, kind underneath. |
Each entry also carries the existing level label string (Beginner / Intermediate / Deep Dive) so the pickers can drop their duplicated label lists. Type the map as Record<DocLevel, Guide> and export a Guide interface.
All consumers (CharacterMessage, WelcomeModal, FloatingDocPrefs, DocLevelBadge) import from here. No level→label or level→avatar data is duplicated anywhere else after this.
2. CharacterMessage.vue — guide mode
Add awareness of guide mode:
- Import
useData(forfrontmatter),useDocPrefs(forlevel), andGUIDES. - Compute
guideMode = frontmatter.value.showLevel === true. - When
guideModeis true:- Speaker name =
GUIDES[level].name(rendered in the existing.cm__namestyle). - Avatar =
GUIDES[level].avatar. - The incoming
nameprop is rendered as a topic eyebrow beneath the guide name (new small, muted label). - Reactive: switching level re-renders all bubbles live.
- Speaker name =
- When
guideModeis false: behavior is unchanged —nameis the speaker, avatar viacharprop →CHARACTER_CHARS→ hash fallback. This preserves bughouse and how-ai-works.
Rendered layout in guide mode:
[Juno avatar] JUNO
STORING A VALUE <- topic eyebrow (was the `name` attr)
A variable is a labelled box you... <- existing slot bodyThe char prop still works as an explicit override if ever needed; an explicit char should take precedence even in guide mode (escape hatch), though no current page uses it.
3. "Pick your guide" surfaces
All read guides.ts:
WelcomeModal.vue— rename the "Your level" section to "Pick your guide". Each option becomes a card showing the guide avatar, name, level label (with bars), and the one-line blurb. Selecting a card setsselectedLevelexactly as today. Confirm/skip logic unchanged.FloatingDocPrefs.vue— the level chips show the guide name with the level (e.g. "Beginner · Juno"). Keep theLevelBarsicon. Selection logic and URL-variant sync unchanged.DocLevelBadge.vue— show the active guide's name (and optionally avatar) alongside the level label, sourced fromguides.ts. Tooltip copy can reference "your guide."
4. Scope guard
Guide mode is gated solely on frontmatter.showLevel === true. Today that is exactly the leveled Python chapters and their translations. No route checks needed. How AI Works, bughouse, and other pages are untouched. Localized Python pages inherit guide mode automatically: guide names are proper nouns, and the topic eyebrow uses the already- translated name value.
Affected files
- New:
docs/.vitepress/theme/composables/guides.ts - Edit:
docs/.vitepress/theme/components/CharacterMessage.vue - Edit:
docs/.vitepress/theme/components/WelcomeModal.vue - Edit:
docs/.vitepress/theme/components/FloatingDocPrefs.vue - Edit:
docs/.vitepress/theme/components/DocLevelBadge.vue - No markdown content edits.
Risks / edge cases
- A leveled Python chapter that intentionally wants a real named character in a bubble would be overridden by guide mode. None exist today (verified: named characters are bughouse-only). The explicit
charoverride plus a possible futureas/fixedprop is the escape hatch if this ever comes up. useData()frontmatter access inside a deeply nested component: already proven safe —DocLevelBadge.vuedoes exactly this.- SSR: guide name/avatar depend on the level ref, which defaults to
beginneron the server and hydrates from localStorage on the client (same pattern as today's level system).
Future phases (out of scope)
- Rewrite recap body copy in each guide's voice (the persona-preview demonstrates this).
- Extend guides to the How AI Works track.

