LGTM
This commit is contained in:
parent
9248e26af2
commit
f2a2651b8a
95 changed files with 3993 additions and 1471 deletions
|
|
@ -6,101 +6,19 @@ function requiredEnv(name: string): string {
|
|||
return value;
|
||||
}
|
||||
|
||||
function requiredNumberEnv(name: string): number {
|
||||
const value = Number(requiredEnv(name));
|
||||
if (!Number.isFinite(value)) {
|
||||
throw new Error(`${name} must be a finite number`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
// Environment-only knobs. Per-storyboard tuning (aspect, fps, bitrate,
|
||||
// voice, prompts, brand…) lives on the Storyboard object itself — see
|
||||
// src/storyboard.ts.
|
||||
|
||||
export const APP_URL = requiredEnv("APP_URL");
|
||||
export const DASHBOARD_PATH = "/dashboard";
|
||||
export const APP_URL = requiredEnv('APP_URL');
|
||||
export const DASHBOARD_PATH = '/dashboard';
|
||||
|
||||
// Per-target storage state. render.sh sets AUTH_STATE_FILE to auth.local.json
|
||||
// or auth.prod.json so a stale local token can't be reused against prod.
|
||||
export const AUTH_STATE_PATH = process.env.AUTH_STATE_FILE ?? "auth.json";
|
||||
export const OUTPUT_DIR = "output";
|
||||
|
||||
const aspect = requiredEnv("ASPECT");
|
||||
if (aspect !== "16x9" && aspect !== "9x16") {
|
||||
throw new Error("ASPECT must be '16x9' or '9x16'");
|
||||
}
|
||||
export const VIEWPORT =
|
||||
aspect === "9x16"
|
||||
? { width: 1080, height: 1920 }
|
||||
: { width: 1920, height: 1080 };
|
||||
export const CAPTURE_SCALE = Math.max(1, requiredNumberEnv("CAPTURE_SCALE"));
|
||||
export const VIDEO_SIZE = {
|
||||
width: VIEWPORT.width,
|
||||
height: VIEWPORT.height,
|
||||
};
|
||||
export const WEBM_BITRATE = requiredEnv("WEBM_BITRATE");
|
||||
|
||||
// Cold-open prompt. Punchy version of the user's intent, short enough to type
|
||||
// on camera without making the opening scene drag.
|
||||
export const PROMPT_TEXT = requiredEnv("PROMPT_TEXT");
|
||||
|
||||
// Filters returned by the AI stub. Keys MUST match real feature names from
|
||||
// /api/features (verified against the running server's schema).
|
||||
export const STUBBED_FILTERS: Record<string, [number, number] | string[]> = {
|
||||
"Property type": ["Flats/Maisonettes", "Terraced"],
|
||||
"Estimated current price": [175000, 450000],
|
||||
"Serious crime per 1k residents (avg/yr)": [0, 55],
|
||||
"Noise (dB)": [50, 68],
|
||||
};
|
||||
|
||||
// Travel-time filters returned by the AI stub. Slug matches the real
|
||||
// /api/travel-destinations?mode=transit response.
|
||||
export const STUBBED_TRAVEL_TIME_FILTERS: {
|
||||
mode: "transit" | "car" | "bicycle" | "walking";
|
||||
slug: string;
|
||||
label: string;
|
||||
min?: number;
|
||||
max?: number;
|
||||
}[] = [
|
||||
{
|
||||
mode: "transit",
|
||||
slug: "manchester",
|
||||
label: "Manchester city centre",
|
||||
max: 35,
|
||||
},
|
||||
];
|
||||
|
||||
// The travel-time card we'll drag manually after AI applies. The Filters
|
||||
// component renders each travel-time entry with `data-filter-name="tt_${i}"`,
|
||||
// and our stub only sets one entry, so it's tt_0.
|
||||
export const TT_CARD_SELECTOR = '[data-filter-name="tt_0"]';
|
||||
export const TT_SLIDER_MAX = 120;
|
||||
export const TT_DRAG_FROM_MIN = 35; // matches AI stub max above
|
||||
export const TT_DRAG_TO_MIN = 20;
|
||||
|
||||
// Cold-open zoom: how aggressively to magnify the AI box.
|
||||
// 2.4 fills most of the viewport with the prompt card without blowing up text.
|
||||
export const AI_ZOOM_SCALE = requiredNumberEnv("AI_ZOOM_SCALE");
|
||||
|
||||
// Initial map view used while we navigate. The AI scene zooms in on the
|
||||
// sidebar so this only matters once we zoom out.
|
||||
export const INITIAL_MAP_VIEW = {
|
||||
lat: 53.4795,
|
||||
lon: -2.2451,
|
||||
zoom: 11.5,
|
||||
};
|
||||
|
||||
// Verification guard only. The renderer does not use this as an editing cap:
|
||||
// if the storyboard needs more than 15 seconds to avoid jumps, keep the frames.
|
||||
export const MAX_DURATION_S = requiredNumberEnv("MAX_DURATION_S");
|
||||
export const MIN_DURATION_S = requiredNumberEnv("MIN_DURATION_S");
|
||||
|
||||
// Target fps of the FINAL output.
|
||||
export const OUTPUT_FPS = requiredNumberEnv("OUTPUT_FPS");
|
||||
export const AUTH_STATE_PATH = process.env.AUTH_STATE_FILE ?? 'auth.json';
|
||||
export const OUTPUT_DIR = 'output';
|
||||
|
||||
// Frames of head-room kept in front of sceneStart when trimming. Shared by
|
||||
// the video trim and the narration manifest so cue offsets line up with the
|
||||
// trimmed timeline.
|
||||
// trimmed timeline. Not tuned per storyboard — same lead-in for any cut.
|
||||
export const LEAD_IN_S = 0.12;
|
||||
|
||||
// Brand strings for the outro card.
|
||||
export const BRAND_NAME = "Perfect Postcode";
|
||||
export const BRAND_TAGLINE = "Find where you actually want to live.";
|
||||
export const BRAND_URL = "https://perfect-postcode.co.uk";
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue