feat(remotion): shared FinishPass cinematic grade (quality floor) + @remotion/lottie

The single highest-ROI quality lift — one finish applied at the FlexStory level
lifts all 12 blocks at once, no per-block change:
- GRADE_FILTER: a headless-safe colour grade (contrast/saturation/lift) applied as
  a CSS `filter` on the content root — backdrop-filter does NOT render in headless
  Chrome, so the grade lives on the content, not an overlay.
- FinishPass: split-tone (cool-shadows multiply + warm-highlights screen) + a soft
  brand duotone + top light-bloom, layered over each scene.
- Installed @remotion/lottie@4.0.290 (artist-made animations — next lever).

Verified: visible richer/graded look on CharacterScene + Slideshow, subtle enough
to suit the muted palette, consistent across blocks.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
soroush.asadi
2026-06-24 23:35:08 +03:30
parent 8f34c3175f
commit b1a51cb01b
2 changed files with 27 additions and 1 deletions
@@ -6,6 +6,7 @@ import { FONT } from "../lib/fonts";
import { useLayout } from "../lib/aspect"; import { useLayout } from "../lib/aspect";
import { getBlock } from "../scenes/registry"; import { getBlock } from "../scenes/registry";
import { withDefaults, clampDuration } from "../scenes/types"; import { withDefaults, clampDuration } from "../scenes/types";
import { FinishPass, GRADE_FILTER } from "../scenes/chrome";
/** /**
* FlexStory — the scene sequencer. A template is `scenes: SceneInstance[]`; this * FlexStory — the scene sequencer. A template is `scenes: SceneInstance[]`; this
@@ -78,7 +79,7 @@ export const FlexStory: React.FC<Props> = (props) => {
}); });
return ( return (
<AbsoluteFill style={{ backgroundColor: colors.backgroundColor, fontFamily: FONT }}> <AbsoluteFill style={{ backgroundColor: colors.backgroundColor, fontFamily: FONT, filter: GRADE_FILTER }}>
{music ? <Audio src={resolveAudio(music)} loop volume={musicVolume} /> : null} {music ? <Audio src={resolveAudio(music)} loop volume={musicVolume} /> : null}
{scenes.map((sc, i) => { {scenes.map((sc, i) => {
@@ -101,6 +102,9 @@ export const FlexStory: React.FC<Props> = (props) => {
</Sequence> </Sequence>
)) ))
: null} : null}
{/* Cinematic finish over every scene — the shared quality floor. */}
<FinishPass colors={colors} />
</AbsoluteFill> </AbsoluteFill>
); );
}; };
+22
View File
@@ -79,6 +79,28 @@ export const Vignette: React.FC = () => (
<AbsoluteFill style={{ pointerEvents: "none", background: "radial-gradient(125% 108% at 50% 42%, transparent 56%, rgba(30,38,58,0.16) 100%)" }} /> <AbsoluteFill style={{ pointerEvents: "none", background: "radial-gradient(125% 108% at 50% 42%, transparent 56%, rgba(30,38,58,0.16) 100%)" }} />
); );
/**
* FinishPass — a shared cinematic colour grade applied over the whole composited
* frame: a contrast/saturation/lift grade (backdrop-filter), a subtle duotone tint
* pulled from the brand palette, and a soft top light-bloom. Layered ON TOP of the
* blocks' own grain/vignette so it lifts every block at once. One component = the
* quality floor for the whole catalogue.
*/
export const FinishPass: React.FC<{ colors: SceneColors; intensity?: number }> = ({ colors, intensity = 1 }) => (
<>
{/* split-tone: cool shadows (multiply) + warm highlights (screen) — headless-safe */}
<AbsoluteFill style={{ pointerEvents: "none", mixBlendMode: "multiply", opacity: 0.18 * intensity, background: `linear-gradient(160deg, ${mixHex(colors.secondaryColor, "#1a2030", 0.45)}, ${mixHex(colors.backgroundColor, "#2a2238", 0.3)})` }} />
<AbsoluteFill style={{ pointerEvents: "none", mixBlendMode: "screen", opacity: 0.16 * intensity, background: `radial-gradient(120% 90% at 50% 8%, ${mixHex(colors.accentColor, "#ffffff", 0.4)}, transparent 60%)` }} />
{/* soft brand duotone + top light bloom */}
<AbsoluteFill style={{ pointerEvents: "none", mixBlendMode: "soft-light", opacity: 0.32 * intensity, background: `linear-gradient(135deg, ${colors.accentColor} 0%, transparent 50%, ${colors.secondaryColor} 100%)` }} />
<AbsoluteFill style={{ pointerEvents: "none", background: `radial-gradient(130% 92% at 50% -15%, ${hexToRgba("#ffffff", 0.16 * intensity)}, transparent 55%)` }} />
</>
);
/** The headless-safe colour grade — applied as a CSS `filter` on the content root
* (backdrop-filter does NOT render in headless Chrome). Pair with <FinishPass>. */
export const GRADE_FILTER = "contrast(1.08) saturate(1.14) brightness(1.01)";
export const ProgressDots: React.FC<{ index: number; total: number; colors: SceneColors; L: Layout }> = ({ index, total, colors, L }) => ( export const ProgressDots: React.FC<{ index: number; total: number; colors: SceneColors; L: Layout }> = ({ index, total, colors, L }) => (
<div style={{ position: "absolute", bottom: L.vmin(44), left: 0, right: 0, display: "flex", justifyContent: "center", gap: L.vmin(8) }}> <div style={{ position: "absolute", bottom: L.vmin(44), left: 0, right: 0, display: "flex", justifyContent: "center", gap: L.vmin(8) }}>
{Array.from({ length: total }).map((_, k) => ( {Array.from({ length: total }).map((_, k) => (