← back to Prestige Car Wash Video
src/story.ts
86 lines
import durations from './durations.json';
import dims from './dims.json';
export const FPS = 30;
export const WIDTH = 1920;
export const HEIGHT = 1080;
const CYAN = '#38bdf8';
const AMBER = '#f5b301';
const GREEN = '#34d399';
const VIOLET = '#a78bfa';
const D: Record<string, number> = durations as any;
// frames for a narrated scene = (voice length + pad), floored to a minimum
const nf = (id: string, pad = 1.1, min = 2.2) =>
Math.max(Math.round(((D[id] || 0) + pad) * FPS), Math.round(min * FPS));
export interface Scene {
type: 'card' | 'clip' | 'fcfs' | 'cam' | 'tips' | 'shot';
id: string;
narr?: string;
frames: number;
accent: string;
// card
act?: string; title?: string; sub?: string;
// clip / option
name?: string; price?: string; category?: string; blurb?: string; clip?: string;
// shot
file?: string; w?: number; h?: number; url?: string;
}
const OPTIONS: Array<[string, string, string, string, string]> = [
// name, price, category, blurb, clipfile(without ext maps to narr opt-<x>)
['Express Exterior Wash', '$19', 'Wash', 'Foam bath, spot-free rinse, and a hand dry. In and out — no upsell pressure.', 'express-wash'],
['Full-Service Wash', '$39', 'Wash', 'Exterior hand wash, interior vacuum, dash wipe, windows, and tire dressing.', 'full-service'],
['Premium Hand Wash', '$79', 'Wash', 'Two-bucket, foam-cannon hand wash — no tunnel, no swirl marks. Safe for ceramic, matte & wraps.', 'hand-wash'],
['Wax & Ceramic Seal', '$49', 'Protection', 'Triple-foam polish plus a hydrophobic ceramic seal that shields clear coat from UV & road.', 'wax-seal'],
['Interior Express Detail', '$120', 'Detail', 'Deep interior: seats, carpets, dash, vents & door jambs. Pet-hair extraction and shampoo.', 'interior-detail'],
['Complete Detail', '$499', 'Detail', 'Full inside-and-out restoration: wash, clay bar, polish, wax, interior shampoo & engine bay.', 'complete-detail'],
['Ceramic Coating · 9H', 'from $999', 'Protection', 'Iron decon, clay bar, one-step polish, and a 9H nano-ceramic coating — 1–3 years of protection.', 'ceramic-coating'],
['Headlight Restoration', '$89', 'Restore', 'Sand, polish, and seal foggy, yellowed headlights back to clear — better night visibility.', 'headlight'],
];
const ADMIN: Array<[string, string]> = [
['overview', 'Overview'], ['competitors', 'Competitors'], ['best-post', 'Best Times to Post'],
['best-market', 'Best Times to Market'], ['holidays', 'Holiday-Driven'], ['services', 'Services'],
['suggestions', 'Grow the Business'], ['ads', 'Online Ads'], ['directories', 'Directories'],
['google', 'Google Business'], ['leads', 'Leads'], ['credentials', 'Credentials'],
];
const catAccent: Record<string, string> = { Wash: CYAN, Protection: GREEN, Detail: AMBER, Restore: VIOLET };
export const SCENES: Scene[] = [
{ type: 'card', id: 'intro', narr: 'intro', frames: nf('intro', 1.2), accent: CYAN,
act: 'San Fernando Valley', title: 'Prestige Car Wash', sub: 'Hand wash · Detail · Ceramic' },
{ type: 'fcfs', id: 'model', narr: 'model', frames: nf('model', 1.0), accent: CYAN },
{ type: 'card', id: 'options', narr: 'options', frames: nf('options', 1.2, 3), accent: AMBER,
act: 'The Menu', title: 'Every Option', sub: 'Flat pricing · no upsell pressure' },
...OPTIONS.map(([name, price, category, blurb, key]): Scene => ({
type: 'clip', id: `opt-${key}`, narr: `opt-${key}`, frames: nf(`opt-${key}`, 1.0),
accent: catAccent[category] || CYAN, name, price, category, blurb, clip: `media/svc-${key}.mp4`,
})),
{ type: 'cam', id: 'livecam', narr: 'livecam', frames: nf('livecam', 1.0), accent: GREEN },
{ type: 'tips', id: 'tips', narr: 'tips', frames: nf('tips', 1.2), accent: AMBER },
{ type: 'card', id: 'act2', narr: 'admin', frames: nf('admin', 1.0), accent: AMBER,
act: 'Behind the scenes', title: 'Growth Center', sub: 'How we keep the business sharp' },
...ADMIN.map(([key, title]): Scene => {
const dk = 'admin-' + key;
return { type: 'shot', id: dk, frames: Math.round(3.3 * FPS), accent: AMBER,
file: `shots/${dk}.png`, w: (dims as any)[dk]?.w, h: (dims as any)[dk]?.h,
title, url: 'prestigecarwash.com/admin', act: 'Admin · Growth Center', sub: title };
}),
{ type: 'card', id: 'outro', narr: 'outro', frames: nf('outro', 1.4, 4), accent: GREEN,
act: 'Prestige Car Wash', title: 'First Come, First Served', sub: 'No appointment · 6 lines · come see us' },
];
export const TOTAL = SCENES.reduce((a, s) => a + s.frames, 0);