Add SAFTA nomination: award band, project badge, filmography tag
Summertide nominated for Best Achievement in Visual Effects - TV at the 19th South African Film and Television Awards (2026). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+5
-1
@@ -1,9 +1,11 @@
|
||||
import AwardBand from "@/components/AwardBand";
|
||||
import Filmography from "@/components/Filmography";
|
||||
import Hero from "@/components/Hero";
|
||||
import ProjectCard from "@/components/ProjectCard";
|
||||
import Reveal from "@/components/Reveal";
|
||||
import SectionLabel from "@/components/SectionLabel";
|
||||
import {
|
||||
awards,
|
||||
filmography,
|
||||
projects,
|
||||
services,
|
||||
@@ -40,8 +42,10 @@ export default function Home() {
|
||||
<>
|
||||
<Hero />
|
||||
|
||||
{awards[0] && <AwardBand award={awards[0]} />}
|
||||
|
||||
{/* Filmography */}
|
||||
<section id="filmography">
|
||||
<section id="filmography" className="scroll-mt-16">
|
||||
<div className="mx-auto max-w-7xl px-5 py-24 md:px-8 md:py-36">
|
||||
<SectionLabel index="01">Filmography</SectionLabel>
|
||||
<div className="mb-14 flex flex-col gap-6 md:flex-row md:items-end md:justify-between">
|
||||
|
||||
@@ -2,7 +2,8 @@ import type { Metadata } from "next";
|
||||
import Link from "next/link";
|
||||
import { notFound } from "next/navigation";
|
||||
import Frame from "@/components/Frame";
|
||||
import { projects, site } from "@/content/site";
|
||||
import Laurel from "@/components/Laurel";
|
||||
import { awardFor, projects, site } from "@/content/site";
|
||||
|
||||
export const dynamicParams = false;
|
||||
|
||||
@@ -38,6 +39,7 @@ export default async function ProjectPage({ params }: PageProps<"/work/[slug]">)
|
||||
if (index === -1) notFound();
|
||||
const project = projects[index];
|
||||
const next = projects[(index + 1) % projects.length];
|
||||
const award = awardFor(project.slug);
|
||||
|
||||
const meta = [
|
||||
{ k: "Client", v: project.client },
|
||||
@@ -55,6 +57,17 @@ export default async function ProjectPage({ params }: PageProps<"/work/[slug]">)
|
||||
← All work
|
||||
</Link>
|
||||
<h1 className="mt-8 font-display text-5xl leading-[0.9] font-thin uppercase md:text-8xl">{project.title}</h1>
|
||||
{award && (
|
||||
<div className="mt-8 inline-flex items-center gap-4 border border-accent/40 bg-accent/[0.06] py-3 pr-6 pl-3">
|
||||
<Laurel className="h-12 w-12 shrink-0 text-accent" />
|
||||
<div>
|
||||
<p className="font-mono text-[10px] tracking-[0.25em] text-accent uppercase">
|
||||
{award.edition} {award.body} · {award.result}
|
||||
</p>
|
||||
<p className="mt-1 text-sm md:text-base">{award.category}</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="mx-auto mt-12 max-w-7xl px-5 md:px-8">
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
import Link from "next/link";
|
||||
import Laurel from "./Laurel";
|
||||
import PlayReel from "./PlayReel";
|
||||
import Reveal from "./Reveal";
|
||||
import type { Award } from "@/content/site";
|
||||
|
||||
// Full-bleed award callout over a still from the nominated work.
|
||||
export default function AwardBand({ award }: { award: Award }) {
|
||||
return (
|
||||
<section className="relative overflow-hidden border-y border-line">
|
||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||
<img src={award.image} alt="" className="absolute inset-0 h-full w-full object-cover object-[70%_40%] opacity-60" />
|
||||
<div className="absolute inset-0 bg-gradient-to-r from-ink via-ink/75 to-transparent" />
|
||||
<div className="relative mx-auto grid max-w-7xl items-center gap-12 px-5 py-20 md:grid-cols-[auto_1fr] md:gap-16 md:px-8 md:py-28">
|
||||
<Reveal>
|
||||
<div className="relative mx-auto flex h-52 w-52 items-center justify-center text-accent md:h-64 md:w-64">
|
||||
<Laurel className="absolute inset-0 h-full w-full" />
|
||||
<div className="text-center">
|
||||
<p className="font-mono text-[10px] tracking-[0.3em] text-muted uppercase">{award.edition}</p>
|
||||
<p className="mt-1 font-display text-4xl font-light tracking-[0.15em] text-fg md:text-5xl">{award.body}</p>
|
||||
<p className="mt-1 font-mono text-[10px] tracking-[0.3em] uppercase">{award.result}</p>
|
||||
</div>
|
||||
</div>
|
||||
</Reveal>
|
||||
<Reveal delay={120}>
|
||||
<p className="font-mono text-xs tracking-[0.3em] text-accent uppercase">
|
||||
{award.result} · {award.year}
|
||||
</p>
|
||||
<h2 className="mt-5 font-display text-4xl leading-tight font-thin uppercase md:text-6xl">
|
||||
{award.category}
|
||||
</h2>
|
||||
<p className="mt-6 max-w-xl text-base leading-relaxed text-muted md:text-lg">
|
||||
Our creature and simulation work on <span className="text-fg">{award.title}</span> was nominated at the{" "}
|
||||
{award.longName}.
|
||||
</p>
|
||||
<div className="mt-10 flex flex-wrap items-center gap-6">
|
||||
{award.reel && <PlayReel src={award.reel} poster={award.image} label="Watch the breakdown" />}
|
||||
{award.project && (
|
||||
<Link
|
||||
href={`/work/${award.project}/`}
|
||||
className="font-mono text-xs tracking-[0.2em] text-muted uppercase transition-colors hover:text-fg"
|
||||
>
|
||||
See the project →
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
</Reveal>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import Reveal from "./Reveal";
|
||||
import { filmography } from "@/content/site";
|
||||
import { awardFor, filmography } from "@/content/site";
|
||||
|
||||
export default function Filmography() {
|
||||
return (
|
||||
@@ -23,6 +23,11 @@ export default function Filmography() {
|
||||
Upcoming
|
||||
</span>
|
||||
)}
|
||||
{awardFor(c.slug) && (
|
||||
<span className="bg-fg px-1.5 py-0.5 font-mono text-[9px] tracking-[0.2em] text-ink uppercase">
|
||||
{awardFor(c.slug)!.body} {awardFor(c.slug)!.result}
|
||||
</span>
|
||||
)}
|
||||
{c.network && (
|
||||
<span className="bg-black/70 px-1.5 py-0.5 font-mono text-[9px] tracking-[0.2em] text-fg uppercase backdrop-blur-sm">
|
||||
{c.network}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
// Laurel wreath: a left branch of leaves curving from the bottom up the side,
|
||||
// mirrored for the right. SVG angles run clockwise from +x (90° = bottom).
|
||||
const R = 40;
|
||||
const C = 50;
|
||||
const leaves = Array.from({ length: 8 }, (_, i) => {
|
||||
const deg = 112 + i * 18; // bottom-left round to top-left
|
||||
const a = (deg * Math.PI) / 180;
|
||||
return { x: C + R * Math.cos(a), y: C + R * Math.sin(a), deg };
|
||||
});
|
||||
|
||||
function Branch() {
|
||||
const start = leaves[0];
|
||||
const end = leaves[leaves.length - 1];
|
||||
return (
|
||||
<g>
|
||||
<path
|
||||
d={`M${start.x.toFixed(2)} ${start.y.toFixed(2)} A${R} ${R} 0 0 1 ${end.x.toFixed(2)} ${end.y.toFixed(2)}`}
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="1"
|
||||
/>
|
||||
{leaves.map((l, i) => {
|
||||
// Outer and inner leaf at each node, angled toward the top of the wreath.
|
||||
const tangent = l.deg + 90;
|
||||
return (
|
||||
<g key={i} transform={`translate(${l.x.toFixed(2)} ${l.y.toFixed(2)})`}>
|
||||
<ellipse cx="0" cy="-5" rx="2.4" ry="5.5" fill="currentColor" transform={`rotate(${tangent - 35})`} />
|
||||
<ellipse cx="0" cy="-5" rx="2.4" ry="5.5" fill="currentColor" transform={`rotate(${tangent + 35})`} opacity="0.75" />
|
||||
</g>
|
||||
);
|
||||
})}
|
||||
</g>
|
||||
);
|
||||
}
|
||||
|
||||
export default function Laurel({ className = "" }: { className?: string }) {
|
||||
return (
|
||||
<svg viewBox="0 0 100 100" className={className} aria-hidden="true">
|
||||
<Branch />
|
||||
<g transform="matrix(-1 0 0 1 100 0)">
|
||||
<Branch />
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
+34
-1
@@ -65,6 +65,39 @@ export const studioStills = [
|
||||
"/capabilities/penguin-box.jpg",
|
||||
];
|
||||
|
||||
export type Award = {
|
||||
body: string;
|
||||
longName: string;
|
||||
edition: string;
|
||||
year: number;
|
||||
result: "Nominee" | "Winner";
|
||||
category: string;
|
||||
title: string;
|
||||
// Filmography slug and/or project slug this award belongs to.
|
||||
credit?: string;
|
||||
project?: string;
|
||||
image: string;
|
||||
reel?: string;
|
||||
};
|
||||
|
||||
export const awards: Award[] = [
|
||||
{
|
||||
body: "SAFTA",
|
||||
longName: "19th South African Film and Television Awards",
|
||||
edition: "19th",
|
||||
year: 2026,
|
||||
result: "Nominee",
|
||||
category: "Best Achievement in Visual Effects – TV",
|
||||
title: "Summertide",
|
||||
credit: "summertide",
|
||||
project: "summertide",
|
||||
image: "/work/summertide/award-bg.jpg",
|
||||
reel: "/reel/summertide-reel.mp4",
|
||||
},
|
||||
];
|
||||
|
||||
export const awardFor = (slug: string) => awards.find((a) => a.credit === slug || a.project === slug);
|
||||
|
||||
export type Credit = {
|
||||
slug: string;
|
||||
title: string;
|
||||
@@ -105,7 +138,7 @@ export const stats = [
|
||||
{ value: `${yearsActive}+`, label: "Years in production" },
|
||||
{ value: String(filmography.length), label: "Film & series credits" },
|
||||
{ value: String(filmography.filter((c) => c.network === "Netflix").length), label: "Netflix titles" },
|
||||
{ value: "PTA", label: "Pretoria, South Africa" },
|
||||
{ value: "SAFTA", label: "2026 VFX nominee" },
|
||||
];
|
||||
|
||||
export type Project = {
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 65 KiB |
Reference in New Issue
Block a user