mirror of
https://github.com/jakejarvis/sofa.git
synced 2026-08-29 01:35:39 -04:00
Add dynamic color theming from poster art using node-vibrant
Extract dominant colors from movie/TV poster images server-side and use them to create per-title atmospheric effects on detail pages — tinted backdrop gradients, ambient glow orbs, and colored poster shadows. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
import { eq } from "drizzle-orm";
|
||||
import { Vibrant } from "node-vibrant/node";
|
||||
import { db } from "@/lib/db/client";
|
||||
import { titles } from "@/lib/db/schema";
|
||||
import { tmdbImageUrl } from "@/lib/tmdb/image";
|
||||
|
||||
export interface ColorPalette {
|
||||
vibrant: string | null;
|
||||
darkVibrant: string | null;
|
||||
lightVibrant: string | null;
|
||||
muted: string | null;
|
||||
darkMuted: string | null;
|
||||
lightMuted: string | null;
|
||||
}
|
||||
|
||||
export async function extractAndStoreColors(
|
||||
titleId: string,
|
||||
posterPath: string | null,
|
||||
): Promise<ColorPalette | null> {
|
||||
const url = tmdbImageUrl(posterPath, "w300");
|
||||
if (!url) return null;
|
||||
|
||||
try {
|
||||
const palette = await Vibrant.from(url).getPalette();
|
||||
|
||||
const colors: ColorPalette = {
|
||||
vibrant: palette.Vibrant?.hex ?? null,
|
||||
darkVibrant: palette.DarkVibrant?.hex ?? null,
|
||||
lightVibrant: palette.LightVibrant?.hex ?? null,
|
||||
muted: palette.Muted?.hex ?? null,
|
||||
darkMuted: palette.DarkMuted?.hex ?? null,
|
||||
lightMuted: palette.LightMuted?.hex ?? null,
|
||||
};
|
||||
|
||||
await db
|
||||
.update(titles)
|
||||
.set({ colorPalette: JSON.stringify(colors) })
|
||||
.where(eq(titles.id, titleId))
|
||||
.run();
|
||||
|
||||
return colors;
|
||||
} catch (err) {
|
||||
console.error(`Failed to extract colors for title ${titleId}:`, err);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function parseColorPalette(raw: string | null): ColorPalette | null {
|
||||
if (!raw) return null;
|
||||
try {
|
||||
return JSON.parse(raw) as ColorPalette;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user