Creative North Star: "The Terminal Canvas"
The visual language of a coding environment abstracted into motion graphics. Colors echo syntax highlighting. White space is generous. Every element earns its place on screen; nothing is decorative filler.
Each frame is a composed canvas, not a scrolling page. Timing follows a breath rhythm: entrance (12-16f) → pause (14-18f) → deliberate reveal. Transitions are part of the narrative.
Explicitly rejects: corporate video aesthetics, SaaS landing-page clichés, PPT-style transitions.
Restrained palette. One dominant accent per frame, at most two when semantically distinct (e.g. course-blue + exam-pink). Accents occupy ≤15% of any frame. Neutrals carry 85%+ of surface area.
Five accent families derived from syntax highlighting, each with a semantic role:
| Family | Role |
|---|---|
| Blue | 课程学习, primary actions, progress |
| Violet | 实操训练, labs, secondary charts |
| Pink | 考试考核, CTF, high-contrast highlights |
| Green | 能力评估, success, completion |
| Amber | 教学管理, warnings, tags |
Within each family, use a single saturated hex. Do not mix multiple blues or multiple pinks on the same frame. Green is reserved for success states only.
| Level | Use |
|---|---|
| Canvas | Page background — cool off-white, no warm tint |
| Surface | Card/container background — pure white |
| Border | Card borders, dividers — near-white, neutral-cool |
| Ink | Primary text — near-black with cool undertone |
| Muted | Secondary text, labels, descriptions — mid-gray meeting 4.5:1 on white |
- No warm-tinted backgrounds. The system is cool-neutral. No cream, sand, beige, paper-tones.
- Gray text on colored background is wrong. Use a darker shade of the background's own hue, or a transparency of the text/ink color.
- Multiple accents coexist only with a clear information-design reason. Syntax-highlighted terminal output is the one context where the full palette appears together deliberately.
- Display/body: GoogleSans (Inter fallback) — a single sans family carries both roles at different weights
- Data labels: Inter (system-ui fallback)
- Mono: SF Mono, Menlo, Monaco, Consolas — terminal output, code, technical labels only
| Role | Weight | Size range | Use |
|---|---|---|---|
| Display | 600-800 | 36-60px | Scene titles, hero text |
| Headline | 600 | 20-34px | Card headings, section labels |
| Body | 400-500 | 14-20px | Descriptions, list items, chat |
| Label | 400-600 | 9-13px | Data labels, captions, metadata |
- Floor at 9px. No text below 9px, even for captions.
- One family carries the project. A second display font adds noise. Mono signals "code" — it's a semantic category, not a design alternative.
- Vertical writing mode (
writing-mode: vertical-rl) is valid for tall narrow containers with Chinese text.
- Center everything. Primary content is centered via
position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%). - Scene canvas: 1920×1080. Vignette depth via
radial-gradient(ellipse, accent at 4% opacity, transparent 55%). - Card style:
background: #ffffff; border: 1px solid #eef0f5; border-radius: 12-16px. - No nesting cards inside cards. Use spacing and alignment for hierarchy within.
- No side-stripe borders. Use full borders, background tints, or leading icons instead.
- Default:
Easing.out(Easing.ease), 12-16 frames - Stagger between items: 5-7 frames
- Items enter along their natural axis — text slides up, side panels slide inward, arcs fly in radially
transformproperties only (translate, scale, rotate, opacity). No animatingheight,max-height, orwidth
- Default config:
{ damping: 14, stiffness: 90 } - Use for moments that need personality: brand reveals, emphasis pops, focal elements
- Not the default entrance — easeOut is
- Scenes fade out over final 8 frames
- Within a scene, elements can hard-cut or opacity-fade; no slide-out exits unless narratively motivated
- Blur is an entrance mechanic (
blur(12px → 0), synchronized with opacity/scale), not a persistent style - The only persistent soft element is the background vignette
Reusable components in src/templates/. Each exports a component and a get*Duration function.
- BrandOpen — brand name + subtitle hero
- CinematicTitle — cinematic text reveal
- HandDrawnOpen — hand-drawn sketch style
- EnergeticIntro — high-energy opener
- SideBySide — two-panel comparison (left + right, with title)
- Carousel — horizontal card carousel with auto-advance
- FeatureCards — stacked feature cards with spring entrance, optional transparent mode
- TrapezoidSplice — trapezoid strips assemble into rectangle, compress, reveal brand
- FlowChart — horizontal flow chart with node cards
- Callout — single media + text callout
- ChatBubbles — animated chat conversation
- StepGuide — numbered step guide
- CodeWindow — code window with syntax highlights
- BigNumber — large animated number display
- Spotlight — spotlight highlight effect
- AnnotatedUI — annotated UI screenshot
- Constellation — constellation/network graph visualization
- ActionCTA — heading + subtitle + CTA button
- SloganCTA — slogan + CTA layout
- CameraMotion — perspective transform wrapper for camera keyframe animation
- Use
Easing.out(Easing.ease)for all entrances. Spring is for moments, not everything. - Reserve 8f at scene start for transition overlap. No key content in the first 8 frames.
- Use accent colors to identify module types at a glance: Blue for courses, Violet for labs, Pink for exams, Green for assessments.
- Keep backgrounds cool off-white. The terminal aesthetic is in accents and typography, not dark mode.
- Let UI frames speak for themselves. The visuals are the message.
- Use
OffthreadVideo/Imgfrom Remotion for all media assets. - Wrap
public/paths instaticFile().
- Over-use gradient text — save it for signature hero moments only
- Use shadows heavier than
rgba(15,23,42,0.10). This is a flat system. - Animate layout properties (
height,width,max-height,padding). Usetransforminstead. - Let any scene run faster than 12f per beat. Flash text must hold ≥14 frames.
- Use warm-tinted backgrounds
- Use
<video>or<img>tags directly — use Remotion'sOffthreadVideoandImg - Use
Sequenceinside flex containers — it usesposition: absoluteinternally and breaks layouts