mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-07 18:26:17 +00:00
Second PR in the Studio storyboarding stack. Adds the top-level toggle between the storyboard and the timeline/preview stage, behind the flag. - STUDIO_STORYBOARD_ENABLED flag (VITE_STUDIO_ENABLE_STORYBOARD, default off) now gates the UI. - ViewModeContext: timeline|storyboard state mirrored to the ?view= query param, so it survives reloads and an agent can deep-link ?view=storyboard. - Segmented Storyboard|Preview control in StudioHeader (flag-gated). - StudioApp swaps the whole center stage for a full-width StoryboardView when storyboard mode is active. - useStoryboard hook + StoryboardView shell: global-direction header, loading/error/empty states. The frame contact-sheet grid lands in PR3. - Extract StudioOverlays from App.tsx to stay within the 600-line studio decomposition budget. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
119 lines
4.4 KiB
TypeScript
119 lines
4.4 KiB
TypeScript
export type StudioFeatureFlagEnv = Record<string, boolean | string | undefined>;
|
|
|
|
const STUDIO_PREVIEW_MANUAL_DRAGGING_ENV = "VITE_STUDIO_ENABLE_PREVIEW_MANUAL_DRAGGING";
|
|
const STUDIO_INSPECTOR_PANELS_ENV = "VITE_STUDIO_ENABLE_INSPECTOR_PANELS";
|
|
const TRUTHY_ENV_VALUES = new Set(["1", "true", "yes", "on", "enabled"]);
|
|
const FALSY_ENV_VALUES = new Set(["0", "false", "no", "off", "disabled"]);
|
|
|
|
export function resolveStudioBooleanEnvFlag(
|
|
env: StudioFeatureFlagEnv,
|
|
names: string[],
|
|
fallback: boolean,
|
|
): boolean {
|
|
for (const name of names) {
|
|
const value = env[name];
|
|
if (typeof value === "boolean") return value;
|
|
if (typeof value !== "string") continue;
|
|
|
|
const normalized = value.trim().toLowerCase();
|
|
if (!normalized) continue;
|
|
if (TRUTHY_ENV_VALUES.has(normalized)) return true;
|
|
if (FALSY_ENV_VALUES.has(normalized)) return false;
|
|
}
|
|
|
|
return fallback;
|
|
}
|
|
|
|
// `import.meta.env` is a Vite-only extension. In non-Vite ESM hosts
|
|
// (Next.js / Turbopack, Node, jest in some configs) it's undefined,
|
|
// and downstream `env[name]` reads would crash. Fall back to `{}` so
|
|
// every flag resolves to its declared default outside Vite. Direct
|
|
// property access keeps Vite's compile-time transform happy.
|
|
//
|
|
// When the studio is served as a pre-built SPA by the embedded Hono server,
|
|
// `import.meta.env` values were baked at build time. The server injects
|
|
// `window.__HF_STUDIO_ENV__` with any `VITE_STUDIO_*` env vars from the
|
|
// user's shell, so runtime overrides take precedence over baked defaults.
|
|
const runtimeEnv =
|
|
typeof window !== "undefined"
|
|
? ((window as Window & { __HF_STUDIO_ENV__?: StudioFeatureFlagEnv }).__HF_STUDIO_ENV__ ?? {})
|
|
: {};
|
|
const env = { ...(import.meta.env ?? {}), ...runtimeEnv } as StudioFeatureFlagEnv;
|
|
|
|
export const STUDIO_PREVIEW_MANUAL_EDITING_ENABLED = resolveStudioBooleanEnvFlag(
|
|
env,
|
|
[STUDIO_PREVIEW_MANUAL_DRAGGING_ENV, "VITE_STUDIO_PREVIEW_MANUAL_EDITING_ENABLED"],
|
|
true,
|
|
);
|
|
|
|
export const STUDIO_INSPECTOR_PANELS_ENABLED = resolveStudioBooleanEnvFlag(
|
|
env,
|
|
[STUDIO_INSPECTOR_PANELS_ENV, "VITE_STUDIO_INSPECTOR_PANELS_ENABLED"],
|
|
true,
|
|
);
|
|
|
|
export const STUDIO_BLOCKS_PANEL_ENABLED = resolveStudioBooleanEnvFlag(
|
|
env,
|
|
["VITE_STUDIO_ENABLE_BLOCKS_PANEL", "VITE_STUDIO_BLOCKS_PANEL_ENABLED"],
|
|
true,
|
|
);
|
|
|
|
export const STUDIO_GSAP_PANEL_ENABLED = resolveStudioBooleanEnvFlag(
|
|
env,
|
|
["VITE_STUDIO_ENABLE_GSAP_PANEL", "VITE_STUDIO_GSAP_PANEL_ENABLED"],
|
|
true,
|
|
);
|
|
|
|
export const STUDIO_COLOR_GRADING_ENABLED = resolveStudioBooleanEnvFlag(
|
|
env,
|
|
["VITE_STUDIO_ENABLE_COLOR_GRADING", "VITE_STUDIO_COLOR_GRADING_ENABLED"],
|
|
false,
|
|
);
|
|
|
|
export const STUDIO_KEYFRAMES_ENABLED = resolveStudioBooleanEnvFlag(
|
|
env,
|
|
["VITE_STUDIO_ENABLE_KEYFRAMES", "VITE_STUDIO_KEYFRAMES_ENABLED"],
|
|
false,
|
|
);
|
|
|
|
export const STUDIO_RAZOR_TOOL_ENABLED = resolveStudioBooleanEnvFlag(
|
|
env,
|
|
["VITE_STUDIO_ENABLE_RAZOR_TOOL", "VITE_STUDIO_RAZOR_TOOL_ENABLED"],
|
|
true,
|
|
);
|
|
|
|
// Storyboard view: a top-level, toggleable view that renders STORYBOARD.md as a
|
|
// contact sheet of live HTML frame tiles, replacing the timeline/preview stage.
|
|
// Opt-in / off by default until the experience is ready for broad exposure.
|
|
// VITE_STUDIO_ENABLE_STORYBOARD=1 npx hyperframes preview
|
|
export const STUDIO_STORYBOARD_ENABLED = resolveStudioBooleanEnvFlag(
|
|
env,
|
|
["VITE_STUDIO_ENABLE_STORYBOARD", "VITE_STUDIO_STORYBOARD_ENABLED"],
|
|
false,
|
|
);
|
|
|
|
// When disabled (the default), drag/resize/rotate commits always take the CSS
|
|
// persist path instead of being intercepted into GSAP script keyframe
|
|
// mutations. The keyframe intercept rewrites timeline tweens from drag
|
|
// gestures and is opt-in until its recording path is hardened.
|
|
export const STUDIO_GSAP_DRAG_INTERCEPT_ENABLED = resolveStudioBooleanEnvFlag(
|
|
env,
|
|
["VITE_STUDIO_ENABLE_GSAP_DRAG_INTERCEPT", "VITE_STUDIO_GSAP_DRAG_INTERCEPT_ENABLED"],
|
|
true,
|
|
);
|
|
|
|
export const STUDIO_PREVIEW_SELECTION_ENABLED = STUDIO_INSPECTOR_PANELS_ENABLED;
|
|
|
|
// Stage 7 Step 3b: shadow dispatch parity mode — dispatches ops to the SDK
|
|
// session alongside the server patch path and logs mismatches via telemetry.
|
|
// Default on: server stays authoritative (no user-visible change), so we want
|
|
// the sdk_shadow_dispatch parity signal from all traffic. Disable via
|
|
// VITE_STUDIO_SDK_SHADOW_ENABLED=false.
|
|
export const STUDIO_SDK_SHADOW_ENABLED = resolveStudioBooleanEnvFlag(
|
|
env,
|
|
["VITE_STUDIO_SDK_SHADOW_ENABLED"],
|
|
true,
|
|
);
|
|
|
|
export const STUDIO_MANUAL_EDITING_DISABLED_TITLE = "Manual editing is temporarily disabled";
|