P R O J E C T SC O N T A C T

[16]

FERMENT

TIER C · YEAR 2026 · STATUS: LIVE · LANGUAGES: TYPESCRIPT

A store with its own visual character and real commerce on edge functions

[FIG. 1] MISSION

I design products with their own visual character instead of a generic store template: FERMENT got a retro-pixel aesthetic — a boot screen straight out of an old terminal, the bitmap VCR OSD Mono font, a pixel vortex and a spinning 3D coin as a GLB model. Under that layer I implement real commerce: Stripe checkout with payment intents and a signature-verified webhook, order creation and a full order lifecycle, an admin panel for products and orders. I also integrate a local logistics operator, not just global APIs — the Polish courier Furgonetka quotes and tracks shipments. All money and shipping logic runs in edge functions on Deno (Supabase Edge Functions): five functions behind the wall, so the Stripe secrets and the Furgonetka token never reach the browser. I built the product through a generative agent (Lovable) on the full Supabase stack, and learned along the way to diagnose when a failure is configuration rather than code — an entirely different repair path. It is also the visual source of this portfolio's whole VCR/boot-terminal language. The scale is unassuming only on the surface: 23 SQL migrations with 40 RLS policies, 11 Deno Edge Functions, and the home page is not a product list but a mosaic of four tile types (product / style / animation / game) sized 1×1 to 4×4 — all inserted through a single admin form.

[FIG. 2] ARCHITECTURE

hover a block to see its description

[FIG. 3] CHALLENGES

[+][CH-01]

I designed the payments on a zero-trust-in-the-client principle: the price is computed server-side (never read off the DOM), the payment intent is created in an edge function with the amount from the database, and the Stripe webhook verifies its signature before closing the order. I also took a real incident on the chin — the Stripe webhook pointed at an old Vercel URL from an earlier project iteration, so orders weren't closing despite successful payments; I documented the diagnosis and fix (rerouting to Supabase) in .lovable/plan.md. Ever since, webhook routing is my first suspect.

[+][CH-02]

Shipping turned out to be a series of ambushes on two fronts at once. The Furgonetka API needed non-standard authentication — the working variant is OAuth with Basic auth of client credentials plus grant_type=password, and the correct parcel format (InPost's fixed 'size B' as a universal dimension for clothing) before pricing returned anything at all. Meanwhile the InPost map widget returned the chosen point's postal code in a random field — postCode, post_code, postalCode, zip — or not at all, sometimes only inside a descriptive address. The readout is now defensively bulletproof: it concatenates a dozen candidate fields into one string, runs a \d{2}-\d{3} regex, and as a last resort scans the whole object via JSON.stringify. Eight commits of mounting desperation in their names ('read' → 'parse' → 'extract' → 'improve') taught me never to assume the shape of someone else's data.

[+][CH-03]

I wired a complete, playable retro arcade game into the shop — 'FERMENT RUN', a self-contained 3,194-line vanilla-JS canvas file with no game framework. The engine has its own bitmap font (each glyph a 5×7 grid encoded as a string, rendered pixel by pixel), a delta-time loop making speed independent of the device's frame rate, and a virtual keyboard for mobile — refined across fixes, because touch 'released' the arrows differently than a keyboard. The leaderboard is server-side: having no supabase-js client, the game hits the Supabase REST API directly with the anon key, and a ten-plays limit lives in a cookie (honestly: a UX barrier, not security). The game tile opens a fullscreen iframe with a four-phase CRT shutdown animation — if terminal aesthetics, then all the way.

[+][CH-04]

Instead of static photos, some products are rotating 3D models — and the whole pipeline had to be operable by a non-technical admin. The insert form accepts a GLB/GLTF file, uploads it to Supabase Storage and exposes twelve transform controls: scale, position and initial rotation per axis plus independent auto-spin toggles on each of the three axes — with a live preview. In the shop grid, react-three-fiber reads those parameters and spins the model in useFrame with delta-time, while a preloader fetches all models ahead of time so the grid doesn't stutter on first render; the 3D component itself is lazy-loaded, so a client with no models never pays for three.js. Mobile needed its own round of fixes — WebGL on phones forgives far less.

[FIG. 4] AI LAYER

No model runs at runtime — AI built the shop itself: the entire development was driven by the Lovable agent (683 of 685 commits), with planning artifacts in the repo, including a Stripe-webhook diagnosis that ended in a configuration fix rather than a code change. For me it's the second AI-native working mode practiced alongside Claude Code — and a lesson in how the two harnesses differ in practice.

[FIG. 2A] SECRETS BEHIND THE WALL

BROWSER

0 SECRETS

Vite/React only ever sees the public anon key and display prices.

EDGE FUNCTIONS (DENO)

hover a function to see what it does behind the wall

[FIG. 5] GALLERY

FERMENT — fig 5
[FIG. 5] 01/12
FERMENT — fig 6
[FIG. 6] 02/12
FERMENT — fig 7
[FIG. 7] 03/12
FERMENT — fig 8
[FIG. 8] 04/12
FERMENT — fig 9
[FIG. 9] 05/12
FERMENT — fig 10
[FIG. 10] 06/12
FERMENT — fig 11
[FIG. 11] 07/12
FERMENT — fig 12
[FIG. 12] 08/12
FERMENT — fig 13
[FIG. 13] 09/12
FERMENT — fig 14
[FIG. 14] 10/12
FERMENT — fig 15
[FIG. 15] 11/12
FERMENT — fig 16
[FIG. 16] 12/12

[FIG. 6] STACK & LINKS

VITEREACTTYPESCRIPTSUPABASE EDGE FUNCTIONS (DENO)STRIPEFURGONETKA APISHADCN/UITAILWINDGLB/3D
CAPABILITIES IN THIS PROJECT: STRIPE · SUPABASE · DENO · 3D/GLB