Loading the page…
Loading the page…
Loading the page…
Steakhouse & restaurant hero section for React and Next.js. Maple, a filmed cartoon cow in a knitted scarf, follows your guest's cursor across six photographed steaks, smiles at their pick and has her say. Brass doneness probe, kitchen ticket, five palettes in light and dark.
by UpFork, built by Ramin ValadanComponentUpdated 22 Oct 2026
Before you buy
How this component gets from the preview into your project, and what buyers ask most.
How to use it
From the preview to your project
Try it in the preview
Switch between light and dark, and resize it to phone and tablet widths, before you decide.
Get it
Free products are yours with a free account. Paid ones settle in USDT on TRON, sent straight to the wallet on your order.
Install it
Components go into your project with one shadcn command, dependencies included. Everything else downloads with a checksum.
Make it yours
It's your code now: rename it, restyle it and wire in your real data.
Or hand it to your AI
Copy the prompt and let your coding assistant place it in your project, following your conventions.
Yes, a free one: it keeps your order, every payment you make for it and the files together. Free products need it too: without an account you can look and try the live preview, but not download, install or copy anything.
Send the price as a USDT transfer on TRON (TRC-20) to the wallet on your order, shown with its QR code, then paste the transaction ID on the order. It's checked on-chain, and the files unlock once it's confirmed. Paid less? You're asked for the rest.
Yes. The Standard License covers unlimited personal and commercial projects, client work included; just don't resell it on its own. Open-source licenses say so on the product.
Create a CLI token on your account page, put it in your project's .env.local, add UpFork to components.json once, and install with npx shadcn add: free and paid components alike.
Onto your order, in your account. Download links last ten minutes and can be made again.
Releases are scanned for malware and reviewed before anyone can download them, and every file shows its SHA-256 so you can check what you got.
Building with an AI assistant?
Copy a ready-made prompt with the code, its dependencies and a demo, and your assistant can put it in place for you.
Selling your own work?
Get approved once, then publish components, templates and mobile components, paid in USDT straight to your own wallet.
Components
npm packages
36 files · 1 package · 63 assets
The code comes with the Pro plan
The files above install into your project with one command, or download as a ZIP.
See the plansA hero section for a premium steakhouse. Maple, a cartoon Hereford cow in a chunky mustard scarf, stands at the right end of the counter and watches the board of steaks:
Around her: a doneness card with a cross-section lens, a brass probe rail and a kitchen ticket that prints out of a slot; six plates on a walnut counter with a brass rail; a live open/closed pill in New York time; five palettes, light and dark, that cross-fade (the scarf is recoloured live in WebGL).
The restaurant, Copperhorn, is invented. Every brand fact, price, count, address and phone number is marked
// PLACEHOLDER — replace with real data in src/components/maple-hero/hero-settings.ts.
pnpm install
pnpm dev # http://localhost:6101
pnpm build && pnpm start # http://localhost:6100
pnpm lint, pnpm typecheck, pnpm test (vitest), pnpm build.
Demo routes: / (Red Banquette, with the palette switcher), /butcher (Butcher Paper, fixed), /auto (follows the
system or a .dark class). Debug: ?debug (frame times and state on window.__maple), ?debug=mask (shows the
scarf mask), ?gl=0 (Canvas 2D fallback), ?tier=mobile / ?tier=desktop, ?sharp=0.6 and ?rim=0 (to compare the
sharpening and the rim light).
import { MapleHero } from "@/components/maple-hero/MapleHero";
import { SteakhouseJsonLd } from "@/components/maple-hero/SteakhouseJsonLd";
import { heroSettings } from "@/components/maple-hero/hero-settings";
<SteakhouseJsonLd settings={heroSettings} url="https://example.com" />
<MapleHero palette="banquette" units="F" onReserve={({ cut, doneness }) => openBooking(cut, doneness)} />
| Prop | |
|---|---|
palette | "banquette" (default), "butcher", "tribeca", "gramercy", "hudson", or "auto" (dark → Red Banquette, light → Butcher Paper; a .dark / .light class or data-theme on <html> wins over the system setting) |
settings | everything it says and shows (hero-settings.ts) |
units | "F" or "C" to start with |
onReserve | called by "Book a table" and "Reserve this cut"; when given, those links do not navigate |
The component is self-contained: plain CSS (maple-hero.css, every name prefixed mh-), its own fonts in fonts/
(Fraunces, Inter Tight, JetBrains Mono, self-hosted), motion for UI animation. Maple's frames and posters live in
public/maple/ and are named by the generated maple-manifest.ts.
All copy, the menu, the doneness table, Maple's lines, the palettes, the gaze calibration and every timing are in
hero-settings.ts. Nothing is hard-coded in the components.
null keeps the native mustard). Colours become --mh-* tokens; registered
colour properties make a switch cross-fade over 600 ms. If you add a scarf colour, run pnpm maple:frames so the
posters (shown before WebGL starts, and with reduced motion) carry it too.brand.timeZone; the status pill says "Open now · last seating 10:30 PM" or "Opens at
5 PM".An AI-generated video (1280×720, 24 fps, 361 frames) is turned into keyed, recolourable frames by
pnpm maple:frames (scripts/maple-frames/):
scripts/maple-frames/restore.mjs runs Real-ESRGAN on the region around her in every frame the
clips use (realesr-general-x4v3 blended half and half with its light-clean-up sibling, 4× up, then Lanczos back to
the source size) and pnpm maple:frames -- --frames <that folder> builds from it. Same size, same weight, much
crisper; about 45 min on a laptop CPU (Python with torch, spandrel and Pillow; the weights from
github.com/xinntao/Real-ESRGAN/releases).keyer.mjs, unit-tested): a flood fill from the border through clear background,
enclosed holes between the legs, the baked contact shadow grown away from the background in the floor zone, a
soft edge, colour decontamination that leans on the fur inside and caps the render's baked rim light, speck
removal, and a temporal median on still edges.src/components/maple-hero/maple-manifest.ts.--review writes contact sheets, face sheets (blink check), 400% crops and the scarf mask over every palette to
.review/maple-frames/. Keyed frames are cached in the temp folder, keyed by the video and the keyer's source.
| Clip | Source frames | Use |
|---|---|---|
lower | 31 → 91 | neutral → looking down at the board (intro) |
axis | 150 → 229 | the gaze axis, far left → slightly right, scrubbed |
rise | 229 → 301 | lifts the head into the smile; backwards it closes the smile |
| posters | 18, 320 | neutral (LCP image), smile (resting and reduced motion) |
At runtime (src/components/maple-hero/engine/, framework-free TypeScript):
frame-store.ts picks the tier, fetches atlases (axis, rise and lower coarse passes first, four at a time, after
load and in idle time) and keeps a device-sized budget of them decoded (160 / 96 / 48 MB), releasing those off
Maple's route first; until a frame is in, the nearest decoded one stands in. The intro's lowering is let go once
it has played (retire).controller.ts is the clip graph (idle, looking, smiling, transit). After the intro she lives on one track: the
gaze axis and the lift into the smile end to end. One critically damped spring with a top acceleration moves her
along it, so a look, a smile and the way back down start and end gently and pass from the turn into the lift
without stopping. The intro and approvals (a picked cut, a committed doneness) are scripts; input priority:
scripts, then a plate pointed at or focused, then the pointer over the board, then a smile after 450 ms above it.gaze.ts maps the angle from her muzzle to the pointer onto the axis through the measured yaw table.renderer-gl.ts (WebGL2) blends two exact neighbouring frames (each alone for the first and last quarter of the
way, a short crossfade between, so a turn never reads as a double image), sharpens them a little (contrast-adaptive,
never on the silhouette; render.sharpness, for screens at 125–150% that draw her larger than she is), recolours
the scarf (HSV mask plus a neighbour rule for its edges, keeping the knit's shading) and adds a rim light; renderer-2d.ts is the fallback without the
recolour and rim (every palette keeps the native mustard scarf there).runtime.ts runs one requestAnimationFrame loop, paused off-screen, in hidden tabs and while she rests (woken by
any input), and redraws only when the frame, the blend, the palette or the size changed. It also keeps her speech
beside her head, on whichever side has room (or above it on phones), clear of the copy column. No React state
changes per frame or per pointer move.Plates and doneness slices are photographs (see assets/photos/README.md), all twelve in: the plates shot at the
board's 45°, the slices cut from a doneness grid and lined up.
node scripts/photos/generate.mjs # makes the missing ones with the GapGPT tools (plates as edits of a template)
node scripts/photos/prompts.mjs # or prints the prompts, to make them elsewhere
pnpm photos:build # cuts out and exports them; writes photo-manifest.ts
A plate's cut-out is its gold rim: the key finds the plate, a circle is fitted to its outline and then moved onto
the gold line as an ellipse (findRim, ellipseFrom in keyer.mjs), because a white plate in shade keys away with a
grey background and its soft shadow clings to the rim. Until a photo exists, the hero draws a stand-in in SVG
(parts/PlateArt.tsx, parts/SliceArt.tsx).
<h1>; plates are buttons (aria-pressed) in a labelled group, and links to the menu without JavaScript;
the probe is a role="slider" with arrows, Home and End and a spoken value ("Medium rare, 135 degrees
Fahrenheit"); the ticket is a role="status"; Maple's canvas is hidden from assistive tech, with a hidden line in
its place; her lines go to a polite live region only when the guest caused them.parts/PillRing.tsx).prefers-reduced-motion: no intro, no scrubbing, no embers; the smile poster, her lines still show (beside the
poster's head), short fades.scripts/fonts-trim.py); 348 KB before.registry/ (38 files, 2 demos, 63 assets, 7.1 MB, no warnings) and its builder
makes the preview (ok, 596 kB).photo-manifest.ts).0 reviews · 0 bugs
Ship it0With fixes0Skip0· 0 reviews
0 bugs0 open0 fixed
Members who have it review it and report its bugs. Sign in
No reviews or bugs yet.