Canonical brand spec for Tejas's personal video content. Ground truth: MOTION_PHILOSOPHY.md (aesthetic) + assets/brand-tokens.css (tokens).
Quiet, modern, builder-voice. A CMU CS student who cares about craft. The aesthetic is warm monochrome (ivory on charcoal), shadcn-modern (Geist typography, thin borders, subtle backdrop-blur, rounded-lg corners), and spring-led (no hard cuts, no shader flourishes). It reads like a well-designed web app moving — not a motion-graphics reel, not an agency promo. Content is either him talking on camera, or him narrating over a technical visualization.
| Token | Hex | Role |
|---|---|---|
--tejas-canvas |
#0a0a09 |
Deepest black — full-bleed surfaces, dot-grid base |
--tejas-ink |
#0f0f0e |
Charcoal — primary background |
--tejas-surface |
#18181b |
Card fill, secondary surfaces (zinc-900) |
--tejas-border |
#27272a |
Card and divider borders (zinc-800) |
--tejas-border-strong |
#3f3f46 |
Emphasis borders (zinc-700) |
--tejas-muted |
#71717a |
Unspoken caption words, secondary text (zinc-500) |
--tejas-dim |
#a1a1aa |
Caption line at rest, meta copy (zinc-400) |
--tejas-soft |
#d4d4d8 |
Hover/active helper (zinc-300) |
--tejas-paper |
#fafaf6 |
Warm off-white — primary text, spoken captions, hero accents |
--tejas-paper-glow |
rgba(250,250,246,0.08) |
Soft glow, dot-grid pattern, inset highlights |
Discipline: no hue anywhere. Every "accent" moment uses brightness, weight, or scale to carry meaning. The only gradient allowed is a soft radial var(--tejas-paper-glow) → transparent for spotlighting.
- Geist Sans (Medium 500, Semibold 600, Bold 700, Extrabold 800, Black 900) — captions, headlines, body, stats, pull-quotes. Everything prose-y.
- Geist Mono (Medium 500, Bold 700) — code blocks, stat values, stat units, line numbers, letterspaced labels, terminal chips, URLs.
Pair them by context: prose runs in Sans, anything numeric or technical runs in Mono. Never use only one family in a scene that has both prose and data.
Conventions:
letter-spacing: -0.02emon anything ≥ 24px. Geist's default tracking is loose; tighten it.font-variant-numeric: tabular-numson every stat element — prevents digit-width jitter during count-ups.- Headline display weight is 800 or above. Body and caption weight is 700. Label weight is 500.
Loaded from jsDelivr. Fallbacks: Inter, system-ui (Sans); SF Mono, ui-monospace (Mono).
- Entrance and exit both allowed for overlay primitives. Exception: the face video has no exit — it simply ends.
- Easing palette:
back.out(1.2–1.3)— card/overlay entrances, mode swaps (the spring that makes it feel alive)power2.out— caption chunk fade-in, utility entrancesexpo.out— per-word color/scale arrival (0.22s), pull-quote reveal (0.55s)power2.in— all exits (caption chunk, overlay cards)sine.inOut— ambient loops (Ken Burns, slow drifts)- No
elastic.out— reserved exclusively for click events in interactive UIs, not video compositions.
- Duration bands: snap entrances 0.18–0.36s; hero reveals 0.48–0.55s; mode swap 0.42s; ambient loops 2–4s.
- Mode swap: face ↔ PIP uses elastic scale swap (
back.out(1.2), 0.42s) on both face wrapper and canvas simultaneously. Author signals intent viadata-tejas-mode="talking-head"ordata-tejas-mode="technical-pip"on the scene wrapper. - Text: per-word color and scale tweens fire at each word's
startandendtimestamps from thenpx hyperframes transcribeJSON output.
| Scene change | Transition | Duration | Ease |
|---|---|---|---|
| Mode 1 → Mode 2 (face → PIP) | Elastic scale swap | 0.42s | back.out(1.2) |
| Mode 2 → Mode 1 (PIP → face) | Elastic scale swap | 0.42s | back.out(1.2) |
| Caption chunk → chunk | Cross-fade with gap | exit 0.22s / gap / enter 0.18s | power2.in / power2.out |
| Overlay card in / out | Spring in, fade out | in 0.32s / out 0.22s | back.out(1.3) / power2.in |
| Pull-quote reveal | Mask + fade | 0.55s | expo.out |
No shader transitions. No whip-streaks. No flash-through-white. Transitions are CSS-only spring and fade. The motion system should be invisible — it carries the edit, not the performance.
Phrase-chunk model: 3–5 words per chunk, hard maximum 5. Chunks break on punctuation (, . ? ! ;) and on pauses ≥ 300ms. One chunk is visible at a time — the outgoing chunk's exit fully completes before the next enters. No stacking. No bleed.
Container: a Geist card anchored at bottom: 240px on the 1080×1920 frame, full-width minus 48px side padding. background: rgba(10,10,9,0.78), backdrop-filter: blur(14px) saturate(1.1), border: 1px solid var(--tejas-paper-glow), border-radius: 12px.
Words start at var(--tejas-muted). On their start timestamp, tween to var(--tejas-paper) + scale(1.04) in 0.22s expo.out. Keyword words get scale(1.10) + an underline scaleX(0→1) draw-in at transform-origin: left center.
Full spec: MOTION_PHILOSOPHY.md §3.2 and the tejas-captions skill.
No logo, no end-card, no branded sting. Tejas delivers the CTA in voiceover.
When referencing his work externally — on a lower-third, a corner chip, or a screenshot callout — use plain text: tejasjb.dev or @tejasjb in Geist Mono 500, color: var(--tejas-paper). No custom mark.
- No hue anywhere. Ivory + charcoal + zinc grays only. Highlight mechanisms are brightness, weight, and scale — not color.
- No templated stat badges. Design each stat reveal per beat. See the
tejas-overlaysskill gallery and design spec §6.2 for the eight bespoke shapes. - No shader-block transitions. No whip-pan, cinematic-zoom, flash-through-white, cross-warp-morph, swirl-vortex, or any registry shader block.
- No chrome-gradient text. That is the Infinite Payments aesthetic. Use plain
var(--tejas-paper)on dark. - No outro CTA card. CTA lives in the voiceover. The video ends on the face or the last technical beat.
- No other fonts. Geist Sans and Geist Mono only. No Inter, Roboto, Montserrat, or system fonts in any visible element.
- No overlapping caption chunks. The exit animation must complete — including visibility-hide — before the next chunk's enter begins.
- No
Math.random()orDate.now()in any composition. Renders must be deterministic. Use a seeded PRNG if randomness is needed. - No face-video dimension animation. Wrap
<video>in a<div>and animate the wrapper — animating a<video>element'swidth,height,top, orleftfreezes frames.
assets/brand-tokens.css— the:rootvars imported by every Tejas compositionMOTION_PHILOSOPHY.md— aesthetic bible; read before brainstorming any Tejas composition.claude/skills/tejas-captions/— caption authoring skill (phrase-chunk model, Geist card, timing rules).claude/skills/tejas-overlays/— overlay primitives and bespoke stat-reveal gallerydocs/superpowers/specs/2026-04-21-video-editing-overhaul-design.md— full design spec with rationale