01Concept
The sea as a tasting menu. Marée (French for tide) is a Breton–Copenhagen hybrid: Noma's discipline, Finistère's weather. Everything on the page obeys the tide — the hero is literal water, sections hand over to each other across undulating wave lines, and the menu is read course by course, the way it is eaten. The register is hushed and saline: short bilingual copy, generous negative space, one coral accent used like a single drop of sauce.
Palette
Typography
Fraunces — La mer, en sept services.
Fraunces (variable optical size, 300–600, roman + italic) for display, wordmark, course names and the decorative ampersands; Figtree Light for body and UI labels. High-contrast serif warmth against cool, quiet sans — a degustation card, not a website template.
02Assets — GPT Image 2
Six images, generated with gpt-image-2 (quality high) via the shared gen_image.py pipeline. Each was inspected at full size and kept only if it read as genuinely Michelin-grade. Actual prompts:
"Aerial top-down photograph of an overcast North Atlantic ocean surface, deep slate-teal water the color of dark petrol #16323B, gentle long swell with fine silvery foam lace threading across the surface, moody diffused grey daylight, no sun, muted desaturated palette with subtle grey-green specular highlights, fine-art editorial seascape shot straight down from above on medium format, texture like hammered pewter, hypnotic and calm, no land, no boats, no birds, no text, no watermark"
"Michelin-starred fine-dining plating, dark editorial food photography in the style of the Relae cookbook: one pristine oyster on the half shell topped with three amber sea-buckthorn gel pearls and a single tiny oyster-leaf, resting on a wet dark granite stone, deep charcoal-teal seamless background, low-key dramatic mood, soft directional window light from upper left, 100mm macro lens, shallow depth of field, palette of oyster grey, slate and one coral-orange accent, Scandinavian restraint, generous negative space, no text, no watermark"
"Michelin-starred fine-dining plating, dark editorial food photography in the style of the Relae cookbook: kelp-cured raw scallop sliced into translucent glistening coins arranged in an overlapping ring, brushed with kelp oil, two tiny fragments of sea lettuce and a dusting of dried seaweed powder, on a dark grey-green stoneware plate, deep shadow background, single soft directional light, macro detail on the wet sheen, muted seafoam and kelp green palette, quiet and precise, no text, no watermark"
"Michelin-starred fine-dining plating, dark editorial food photography: a pearlescent tranche of wild turbot with glossy beurre blanc, dotted with tiny white butter-sauce pearls and a few drops of deep-green kelp oil, one small coral nasturtium petal, served on a handmade off-white stoneware plate with rough rim, dark slate-grey linen tablecloth, moody low-key light from one soft window, 45-degree angle, shallow depth of field, restrained negative space, new-Nordic French coastal cuisine, no text, no watermark"
"Extreme macro fine-art photograph of dark North Atlantic seawater surface: swirling deep slate-teal water the colour of petrol #16323B meeting delicate white foam lace and fine bubbles, abstract close-up detail, matte overcast light with soft silvery grey-green specular sheen, no sun, muted desaturated Scandinavian palette, hammered-pewter texture, meditative and precise, shot straight down from above, shallow depth of field, editorial seascape, square composition, no land, no horizon, no text, no watermark"
"Interior photograph of a small coastal fine-dining restaurant at blue-hour dusk: one floor-to-ceiling window wall looking onto a grey-teal Atlantic sea and rocky Brittany headland, bare oak tables set with handmade pale ceramics and single low candles, warm candlelight glow against cool deep-blue dusk light from outside, lime-washed off-white walls, Scandinavian-Breton minimalism, empty room, no people, editorial architecture photography, cinematic and hushed, wide angle but not distorted, no text, no watermark"






03Techniques
WebGL water hero (three.js, custom GLSL)
A 420×300 plane (220×160 segments) displaced in the vertex shader by four crossing sine "swell trains" — a cheap gerstner impression. The fragment shader re-derives the height field (plus three octaves of value-noise ripple that never touch the geometry) by finite differences to get normals, then lights it with one low silvery half-lambert + Blinn specular, an overcast-sky fresnel, faint crest foam and horizon haze. Tuned to look like hammered pewter, not a pool. The canvas fades in over the generated still, which remains as the no-WebGL / reduced-motion fallback.
float swell(vec2 p, vec2 dir, float freq, float speed, float amp) {
return sin(dot(p, dir) * freq + uTime * speed) * amp;
}
float bigHeight(vec2 p) {
float h = swell(p, normalize(vec2( 1.0, .35)), .055, .42, 1.15);
h += swell(p, normalize(vec2(-0.7, 1.0)), .082, .35, .65);
h += swell(p, normalize(vec2( 0.2,-1.0)), .14, .55, .30);
h += swell(p, normalize(vec2( 1.0,-0.6)), .23, .70, .14);
return h;
}
Tide dividers
Every section handover is an SVG "tide line": two stacked wave paths (one at 35% opacity for depth) whose points are re-sampled every frame from three superposed sines with per-divider phase offsets. They drift at swell speed — slow enough that you feel them rather than watch them. Paused when offscreen via IntersectionObserver, frozen under prefers-reduced-motion.
The seven services
The tasting menu is a stage, not a list: one visual panel (crossfading, slow-zooming imagery) and one text panel with seven absolutely-stacked courses. Roman-numeral tabs, arrows, arrow keys and touch swipe all drive setCourse(), which swaps is-active classes, advances a seafoam progress line and updates the "I / VII" counter. Non-plated courses (III, V, VI, VII) return to a dedicated macro of the sea itself — the menu literally returns to the water between dishes.
Micro-motion
- Lenis smooth scroll driven by the GSAP ticker; anchor links ride the same easing.
- Word-by-word masked reveal on the philosophy lede (spans clipped by overflow, staggered 28 ms).
- Slow parallax: dining-room photo scrubs ±9% through its overscanned frame; ghost ampersands drift counter-scroll.
- Scroll-spy nav: an IntersectionObserver lights the section you're reading; the framed course visual sways almost imperceptibly on a 17s loop.
- SVG-noise film grain overlay at 5% opacity, stepped 3-frame shuffle.
- Date-strip reservation UI (visual only): closed days struck through, covers stepper, staged confirmation line.
- Decorative Fraunces italic ampersands as outlined ghost glyphs behind the philosophy and chef sections.
Accessibility & fallbacks
prefers-reduced-motion: water renders a single frozen frame, dividers freeze, Lenis/GSAP reveals are skipped.- WebGL failure removes the canvas; the generated hero still shows through.
- Roman-numeral rail is a proper
tablist; date chips and slots carryaria-pressedand full French labels.
04Process — three passes
Pass 1 — completeness & first light
Audited the interrupted build. The seven-course experience referenced a sea-detail.webp for four courses that had never been generated — a broken image on more than half the menu. Generated a dedicated macro of dark Atlantic foam to fill it, so the non-plated courses "return to the water" as intended. Hardened the reduced-motion path for the masked word-reveal, and added a ?static=1 QA mode so lower sections can be inspected without the smooth-scroll hijack.
Pass 2 — rhythm, mobile & life
Walked every section at 375 px and 1280 px. Layouts held: the course stage collapses to a single column, the reservation date-strip scrolls horizontally without pushing the page, no overflow anywhere. Added two touches of life: a scroll-spy that lights the current section in the nav, and a barely-perceptible 17s "sway" on the framed course visual so the dish is never fully still.
Pass 3 — polish & accuracy
Tightened the hero's secondary lines for legibility over moving water, cache-versioned the assets, and brought this guide into line with what was actually built — six generated images (not five plus a crop), the real sea-detail prompt, and the true process above. Final desktop + mobile passes: screenshots clean, console silent on / and /guide.
05Ship it
Static files, no build step. Deploy from the site directory:
npx wrangler pages deploy . --project-name maree