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:
@@ -6,6 +6,7 @@ import { FONT } from "../lib/fonts";
|
||||
import { useLayout } from "../lib/aspect";
|
||||
import { getBlock } from "../scenes/registry";
|
||||
import { withDefaults, clampDuration } from "../scenes/types";
|
||||
import { FinishPass, GRADE_FILTER } from "../scenes/chrome";
|
||||
|
||||
/**
|
||||
* FlexStory — the scene sequencer. A template is `scenes: SceneInstance[]`; this
|
||||
@@ -78,7 +79,7 @@ export const FlexStory: React.FC<Props> = (props) => {
|
||||
});
|
||||
|
||||
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}
|
||||
|
||||
{scenes.map((sc, i) => {
|
||||
@@ -101,6 +102,9 @@ export const FlexStory: React.FC<Props> = (props) => {
|
||||
</Sequence>
|
||||
))
|
||||
: null}
|
||||
|
||||
{/* Cinematic finish over every scene — the shared quality floor. */}
|
||||
<FinishPass colors={colors} />
|
||||
</AbsoluteFill>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -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%)" }} />
|
||||
);
|
||||
|
||||
/**
|
||||
* 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 }) => (
|
||||
<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) => (
|
||||
|
||||
Reference in New Issue
Block a user