DS Racing Karts
Full e-commerce platform with 499+ go kart parts, Square payment integration, and a custom-built Canvas 2D racing mini-game.

Overview
DS Racing Karts is a comprehensive e-commerce platform built for one of Sydney's most experienced kart specialists — Dion Scott, a racer and engineer with nearly 40 years in the sport. The client needed a complete digital storefront to sell go kart parts, showcase services, and represent the brand online. C4 Studios delivered a full-stack e-commerce solution featuring 499+ products migrated from Square's catalogue via a custom 4-stage data pipeline (CSV import → category deduplication → image migration via Square Catalog API → AI-powered description generation with Claude Haiku). The platform includes a custom-built 'DSR Grand Prix' slot-car racing mini-game (2,291 lines of hand-written Canvas 2D code), GSAP ScrollTrigger-powered 3D scroll animations throughout, a full admin dashboard with CRUD product management, Sentry error tracking across three runtimes, and comprehensive security hardening including HSTS, CSP, rate limiting, and HMAC-SHA256 webhook verification. This is the largest and most technically ambitious project in the C4 Studios portfolio.
Screenshots
What I Delivered
- Complete e-commerce website — full design, development, and deployment
- Square payment integration with PCI-compliant card tokenisation and server-side payment processing
- 4-stage data migration pipeline — Square CSV → Supabase import (2-pass category/product) → category deduplication → image migration (Square Catalog API → Supabase Storage) → AI description generation
- Product catalogue system with 499+ go kart parts synced from Square
- Individual product pages with image gallery, SKUs, pricing, stock status indicators, breadcrumb navigation, and Product structured data schema
- Shopping cart with add/remove/quantity management, GST calculation, and localStorage persistence
- Custom checkout flow with Square Web Payments SDK, customer details, shipping address with Australian state dropdown
- Order confirmation system with auto-incrementing DSR-XXXXX numbers and branded Resend confirmation emails
- Category-based product filtering with hierarchical sidebar navigation (parent > child)
- Product search with PostgreSQL trigram matching (pg_trgm), autocomplete overlay with Ctrl+K hotkey, and rich results
- Product pagination (24 per page) with ellipsis and prev/next controls
- Sort functionality (newest, price ascending/descending, name A-Z)
- 7 detailed service pages — Kart Servicing, Engine Tuning, Chassis Setup, Engine Servicing, Race Preparation, Driver Coaching, Custom Racewear — each with included-items checklists and contextual enquiry CTAs
- Custom "DSR Grand Prix" slot-car racing mini-game — 2,291 lines of hand-written Canvas 2D code with physics engine, AI opponent, 4 tracks, F1-style countdown, and mobile touch controls
- GSAP ScrollTrigger-powered 3D scroll animations — history timeline, RPM tachometer, SVG race animation, 3D video container
- RPM tachometer-style animated statistics counter (500+ Parts, 40 Years, 1000+ Karts) with redline rev-limiter bounce
- Scroll-pinned SVG race animation — two detailed top-down karts with exhaust glow, kerbs, and finish-line flash
- Founder biography page with professional photo, racing history narrative, and career highlights
- Racing teams showcase with 9 team profiles (numbers 338, 43, 114, 5, 555, 272, 285, 22, 249) in modal carousel with swipe navigation
- Results/achievements timeline (2024 ERC Podiums, 2023 Endurance Victories, 2021 SEK Wins)
- "Know Your Chassis" educational content — Sprint, Endurance, and DSR Predator technical breakdowns
- Sponsor showcase with 19+ brand logos in dual-direction infinite CSS scroll carousel
- Contact form with dynamic subject prefills from service page CTAs, input validation, and HTML-escaped Resend email delivery
- Newsletter subscription system ("Stay in the Fast Lane") — Supabase upsert + optional Mailchimp double opt-in sync
- Cookie consent banner with Accept/Decline — localStorage persistence, GA4 conditionally loaded only on consent
- Google Analytics 4 integration with cookie-consent-gated loading
- Privacy Policy page (9 sections, Australian Privacy Principles compliant)
- Terms & Conditions page (10 sections, e-commerce focused)
- Custom racewear photo gallery with 12 product images in responsive grid with hover zoom
- "Built for Performance" workshop showcase section with cut-corner image design
- Responsive design (mobile + tablet + desktop) with mobile navigation overlay and body scroll lock
- Full SEO setup — per-page metadata, dynamic OG/Twitter/Apple icon generation (Edge runtime), sitemap.xml with all product slugs, robots.txt, LocalBusiness + Product structured data schemas
- AI-generated product descriptions — Claude Haiku 4.5 filled ~400 empty descriptions with dry-run mode and cost tracking
- Full admin dashboard with product/order/customer counts, recent orders table, and colour-coded low stock alerts
- Admin product editor — full CRUD for products including image upload/delete/set primary, variations, inventory, categories, SEO fields
- Admin category management with hierarchical table (parent bold, child indented with └) and product counts
- Admin customer list with search across name/email and pagination
- Admin order management with status badges, customer join, and pagination
- Supabase Auth with role-based admin access (admin/super_admin) and middleware redirect for unauthenticated requests
- 12 custom hand-drawn SVG category icons — steering wheel, chain links, brake disc, axle, stub axle, ball bearing, helmet, chequered grid, fuel can, wrench, tie rod, car silhouette
- Hero video section with autoplay detection, 12-second fallback timeout, and crossfade to cycling background images
- 3D perspective video container with scroll-driven rotation, red radial glow, and scanline overlay
- Sentry error tracking across client (10% traces, 100% error replays), server, and edge runtimes with global error boundary
- Security hardening — HSTS (2-year max-age + preload), CSP, X-Frame-Options DENY, X-Content-Type-Options nosniff, Permissions-Policy, rate limiting on all public API routes, HMAC-SHA256 webhook verification
- Square webhook handler for real-time order status updates (payment.updated → paid/cancelled)
- Lenis smooth scrolling (1.2s duration, exponential easing, 2× touch multiplier)
- PWA-ready web app manifest with standalone display mode and #e60012 theme colour
- Appointment-only modal popup system for workshop address clicks
- C4 Studios credit badge in header and footer with animated wordmark
- All page content writing and copywriting
- Loading skeleton states for shop page, product page, and admin products page
- Custom 404 page with racing-themed CTAs
- Search autocomplete overlay with keyboard navigation (↑/↓/Enter/Escape), Ctrl+K global hotkey, debounced API calls
Key Features
- Full e-commerce platform with 499+ go kart parts, synced from Square's product catalogue via a 4-stage migration pipeline
- Custom-built "DSR Grand Prix" slot-car racing mini-game — 2,291 lines of Canvas 2D code with curvature-based physics, 4-tier AI difficulty, 4 tracks including a "Campbelltown GP" local Easter egg, F1-style 5-light countdown with false start detection, persistent skid marks, and mobile touch controls
- Square payment integration — client-side PCI-compliant card tokenisation via Web Payments SDK, server-side createPayment() with idempotency keys and BigInt AUD amounts
- GSAP 3.14 + ScrollTrigger-powered 3D scroll animations — history timeline with SVG trunk growth, RPM tachometer with rev-limiter bounce, scroll-pinned SVG kart race, 3D perspective video container
- Animated RPM tachometer stats counter — realistic SVG face (0–16,000 RPM), scroll-driven needle with sinusoidal rev-limiter oscillation at redline, gold-to-red arc gradient, 3 counter-up stat cards
- Dynamic product catalogue with hierarchical category sidebar, stock filtering, sort (newest/price/name), 24-per-page pagination with ellipsis, and PostgreSQL trigram search
- Product detail pages with multi-image gallery, SKU display, variation selection, sale pricing, stock status indicators, breadcrumb navigation, sanitised HTML descriptions, and Product structured data (AggregateOffer)
- Shopping cart with React Context + localStorage persistence, quantity controls, line item management, GST (10%) calculation, and "Estimated Total" display
- Custom checkout flow — Square Web Payments SDK dynamically loaded, card tokenise → server price validation against DB → Square payment → Supabase order with auto-increment DSR-XXXXX → inventory decrement → Resend branded confirmation email
- 7-service showcase with expandable accordion cards, Lucide icon mapping, "What's Included" checklists (6 items each), and contextual "Enquire Now" CTAs that pre-fill the contact form subject
- Founder biography section — Dion Scott profile with 3:4 aspect portrait, racing-red corner accent, blockquote narrative spanning 1989 to present, career credits including Fastrack Experiences V8 coaching
- Racing teams grid — 9 teams (numbers 338, 43, 114, 5, 555, 272, 285, 22, 249) in full-screen modal carousel with decorative SVG patterns (CheckeredCorner, TireTrack, SpeedLines), keyboard/swipe/dot navigation
- Results timeline — chronological achievement display (2024 ERC Podiums, 2023 Endurance Victories, 2021 SEK Wins) with red left-border accent and Orbitron digital year labels
- "Know Your Chassis" educational content — technical breakdowns of Sprint (7 specifications), Endurance, and DSR Predator chassis types with specifications grid
- Custom racewear gallery — 12 product photos in responsive 2/3/4-column grid with hover-zoom transform and gradient overlay
- Sponsor showcase with 19+ partner logos in dual-direction infinite CSS scroll (35s linear, 3× duplication), gradient fade edges, and hover image-swap (700ms crossfade)
- Newsletter subscription system ("Stay in the Fast Lane") — POST to /api/newsletter → Supabase upsert + optional Mailchimp REST API sync with double opt-in (status: "pending"), rate limited 5/15min
- Cookie consent banner (custom, no external library) — Accept/Decline stored in localStorage as "dsr-cookie-consent", GA4 script tag conditionally rendered only when consent granted
- Google Analytics 4 — loaded via next/script afterInteractive strategy, zero Google scripts until explicit cookie Accept
- Contact form with dynamic subject pre-fills from service page CTAs (/contact?subject=Kart+Servicing), HTML-escaped output, Resend delivery to [email protected], rate limited 3/15min
- Appointment-only modal system — triggered from Footer address click, "private residential property" warning, Contact Us / Got It action buttons, backdrop blur dismiss
- "Shop by Category" homepage grid with custom SVG category icons linking to filtered shop views
- Latest Products carousel on homepage — 8 newest products with live pricing from Supabase, priority image loading for first 4
- History timeline section — 9 nodes with GSAP scroll-driven SVG trunk line growth, alternating left/right cards with fade-in/out on scroll, terminal dot with pulse animation, fullscreen image lightbox with Escape key dismiss
- Mobile-responsive hamburger navigation with slide-down overlay, body scroll lock, and cart icon with product count badge
- C4 Studios animated credit badge — GSAP wordmark animation in header and footer
- Facebook social integration link
- Email link integration ([email protected])
- Supabase Storage for product image hosting with Next.js Image optimisation (AVIF/WebP, 30-day edge cache)
- Admin dashboard — 5 parallel Supabase queries fetching product count, order count, customer count, recent 5 orders, and low stock items (≤3 quantity). Colour-coded stock thresholds (red ≤0, yellow ≤5, green >5)
- Admin product editor — full CRUD: name, description (HTML), SKU, status (active/draft/archived), visibility (visible/hidden/unavailable), variation management (name/SKU/price/sale price/stock qty), image upload to Supabase Storage with set-primary/delete, category tag selection, SEO title/description fields
- Supabase Auth with role-based access — email/password sign-in, admin_profiles table with admin/super_admin roles, middleware redirect for unauthenticated admin requests, API route-level auth checks
- 4-stage data migration pipeline — (1) import-square-csv.js: 2-pass CSV import (Pass 1: categories with dedup, Pass 2: products/variations/inventory), (2) merge-categories.cjs: cleanup duplicate categories, (3) migrate-images.js: Square Catalog API download → Supabase Storage upload, (4) generate-descriptions.cjs: Claude Haiku for ~400 products with dry-run mode and backup JSON
- Sentry error tracking — client (10% traces, 100% error replays), server, and edge runtimes; error.tsx captures exceptions via Sentry.captureException; global-error.tsx as root boundary fallback
- Security hardening — HSTS max-age=63072000 (2 years) with includeSubDomains + preload, Content-Security-Policy with script/style/img/connect/frame source whitelisting, X-Frame-Options DENY, X-Content-Type-Options nosniff, Referrer-Policy strict-origin-when-cross-origin, Permissions-Policy camera=()/microphone=()/geolocation=()
- Rate limiting on all public API routes — checkout (10 requests/5min), contact (3/15min), newsletter (5/15min) — in-memory Map with timestamp expiry
- Square webhook handler — payment.updated events with fail-closed HMAC-SHA256 signature verification using crypto.timingSafeEqual, maps COMPLETED→paid / FAILED→pending / CANCELLED→cancelled
- Lenis smooth scrolling wrapping entire application — duration 1.2s, easing function (1 - Math.pow(2, -10 * t)), touchMultiplier 2×, rAF loop with cleanup on unmount
- PWA-ready manifest — standalone display, #e60012 theme_color, #0a0a0a background_color
- Scroll-pinned SVG race animation — 300vh pin, two DetailedKart SVG components (body with shading, 4 wheels with tread, helmet with visor, number circle, animated exhaust glow), full track with grass/kerbs/asphalt/finish lines, Kart 1 surge at 75%, drift at 90%, finish flash at 98%
- 12 custom hand-drawn SVG category icons — SteeringWheelIcon, ChainIcon, BrakeDiscIcon, AxleIcon, StubAxleIcon, BearingIcon, HelmetIcon, ChequeredIcon, FuelCanIcon, WrenchIcon, TieRodIcon, CarIcon — all built as React components with SVG path data
- Hero video section — autoplay detection with canPlayThrough event, 12-second fallback timeout, crossfade to 4 cycling background images at 5-second intervals, DSR logo image, dual CTA buttons, animated scroll indicator with bounce
- 3D perspective video container — IntersectionObserver auto-play/pause, scroll-driven transforms (rotateX 0→-8°→0°, rotateY sinusoidal ±3°, scale 0.92→1.03→0.97, translateY -20→0→-10px), perspective: 1200px, red radial glow with sinusoidal intensity, "racing monitor" frame with accent corners and scanline overlay
- Dynamic SEO image generation — opengraph-image, twitter-image, icon (32×32 "DSR" in red), apple-icon (180×180) — all Edge runtime ImageResponse
- Dynamic sitemap.xml — fetches all active products from Supabase, outputs static pages + all product slug URLs + category URLs
- Search autocomplete overlay — Ctrl+K / Cmd+K global hotkey, 300ms debounced API calls, keyboard navigation (↑/↓/Enter/Escape), rich results with product images + category badges + prices, "No results" state
- Loading skeleton states — animated pulse placeholders for shop page, product page, and admin products page matching actual layout structure
- Product image gallery — thumbnail strip navigation, primary image display with Next.js Image optimization
- LocalBusiness structured data on homepage, Product (AggregateOffer) structured data on product pages
Stack & Tooling
- Next.js 14 (App Router)
- React 18
- TypeScript 5.7
- Tailwind CSS 3.4
- GSAP 3.14 + ScrollTrigger
- @gsap/react 2.1
- Lenis 1.3 (smooth scrolling)
- Square SDK 38.0 (Payments API — server-side)
- Square Web Payments SDK (client-side card tokenisation)
- Supabase JS 2.47 + SSR 0.5 (Postgres, Auth, Storage)
- PostgreSQL via Supabase (pg_trgm + uuid-ossp extensions)
- Resend 6.11 (transactional email)
- Sentry 10.49 (client, server, edge error tracking)
- Google Analytics 4 (cookie-consent-gated)
- Mailchimp REST API (newsletter sync, optional double opt-in)
- Canvas 2D API (custom game engine — zero external libraries)
- Lucide React 0.460 (icon library)
- clsx 2.1 + tailwind-merge 2.6 (class utilities)
- sanitize-html 2.17 (HTML sanitisation for product descriptions)
- Anthropic Claude Haiku 4.5 (build-time product description generation)
- csv-parse 5.6 (CSV processing for data migration)
- dotenv 16.4 (environment variable management)
- PostCSS 8.4 + Autoprefixer 10.4
- Node.js 22+
- Vercel (hosting)
Integrations & Backend
- Square Payments API — server-side paymentsApi.createPayment() in /api/checkout with card tokenisation, idempotency UUID, BigInt AUD amounts, buyer email, location ID
- Square Web Payments SDK — dynamically loaded client-side script, card.attach() to DOM ref, card.tokenize() for PCI-compliant card data, production/sandbox environment switching
- Square Catalog API — used in scripts/migrate-images.js to fetch all ITEM + IMAGE catalog objects for downloading and re-uploading product photos to Supabase Storage
- Square Webhooks — inbound payment.updated events at /api/webhooks/square, HMAC-SHA256 signature verification (notification URL + body hashed with webhook secret, timing-safe comparison), maps COMPLETED/FAILED/CANCELLED to Supabase order status
- Supabase Postgres — 12 tables, 15+ indexes (GIN tsvector + trigram for search), 19 RLS policies, GENERATED ALWAYS stock_status column, auto-incrementing DSR-XXXXX order numbers via PostgreSQL sequence + trigger, decrement_inventory() SECURITY DEFINER function
- Supabase Auth — email/password for admin panel, role-based access via admin_profiles table (admin/super_admin), middleware session refresh on every request, middleware redirect for unauthenticated admin requests
- Supabase Storage — product-images bucket, file upload from admin panel, public URLs served through Next.js Image with AVIF/WebP optimization and 30-day edge cache
- Resend — transactional email: (1) order confirmation emails with branded HTML template (racing red accents, item table, pricing breakdown), from [email protected]; (2) contact form submissions from [email protected] to [email protected] with reply-to sender
- Google Analytics 4 — loaded via next/script afterInteractive only after cookie consent granted, measurement ID from NEXT_PUBLIC_GA_MEASUREMENT_ID env var, zero scripts loaded on decline
- Mailchimp REST API — optional newsletter sync from /api/newsletter, extracts datacenter from API key, POST to /lists/{id}/members with status "pending" (double opt-in), graceful fallback if keys not configured
- Anthropic Claude API — Haiku 4.5 used in scripts/generate-descriptions.cjs for build-time product description generation (~400 products), dry-run mode for testing, backup JSON export, cost tracking per request
- Sentry — @sentry/nextjs 10.49, configured across client (10% tracesSampleRate, 0% session replays, 100% error replays), server (10% traces), and edge (10% traces) runtimes, source maps uploaded with hideSourceMaps: true
- Facebook — social media link to @dsracingkarts page from footer and contact page
- Next.js Image CDN — remote patterns for Supabase Storage (*.supabase.co) and Square S3 CDN, AVIF/WebP format support, 30-day minimumCacheTTL, custom deviceSizes and imageSizes
Performance / SEO / Accessibility
- Next.js Image component used throughout with AVIF/WebP formats, custom deviceSizes (640–1920), and 30-day edge cache TTL
- Google Fonts loaded with display: swap for FOUT prevention — Oswald (headings), Inter (body), Orbitron (digital/stats)
- Game loaded via next/dynamic with ssr: false — zero SSR cost, code-split, lazy-loaded on demand from GameTeaser
- Game state managed via useRef (not useState) in rAF loop to avoid React re-renders during gameplay
- Scenery generation uses seeded random (sin hash) for deterministic caching across frames
- Skid marks capped at 300 with batch purge of 50 to prevent memory accumulation
- Product pagination (24/page) prevents loading all 499+ products at once
- Loading skeleton states for shop, product, and admin pages to prevent CLS
- Supabase queries use select with specific columns (no SELECT *) for minimal payload
- Admin dashboard runs 5 parallel Supabase queries via Promise.all for fast dashboard load
- CSS infinite scroll animations use will-change: transform for GPU acceleration
- Lenis smooth scrolling with requestAnimationFrame loop and cleanup on unmount
- Sentry configured with 10% trace sampling to minimise performance overhead
- Sentry source maps hidden from users (hideSourceMaps: true)
- IntersectionObserver for video auto-play/pause to avoid unnecessary media decoding
- Dynamic imports for Square Web Payments SDK — only loaded on checkout page
- Product images served through Next.js Image optimization pipeline: Supabase Storage → CDN → client with responsive srcset
Challenges & Constraints
- Square catalogue migration — Building a 4-stage data pipeline to import 499+ products with categories, variations, pricing, inventory, and images from Square's CSV export format, handling escaped commas, "Name (SQUARE_ID)" notation, and "Parent > Child" category nesting
- E-commerce architecture without a platform — Constructing a complete shop experience (browse, filter, search, cart, checkout, payment, order management) on Next.js + Supabase without Shopify/WooCommerce, requiring custom cart context, price validation, inventory management, and order tracking
- Mini-game development in production — Designing and building a 2,291-line Canvas 2D racing game with physics, AI, and multiple tracks that runs smoothly alongside a content-heavy e-commerce site, using useRef patterns to avoid React re-render overhead in the animation loop
- 3D scroll animation performance — Orchestrating multiple simultaneous GSAP ScrollTrigger instances (history timeline, tachometer, race animation, video container) on a homepage that also loads product images and embeds a game, requiring careful GPU acceleration and intersection-observer gating
- Product image pipeline — Migrating hundreds of product images from Square's S3-hosted catalogue (via Catalog API) to Supabase Storage, then serving through Next.js Image with AVIF/WebP optimization and 30-day CDN caching
- PCI-compliant payment flow — Implementing Square's client-side card tokenisation + server-side payment processing with idempotency keys, BigInt currency handling, fail-closed webhook verification (HMAC-SHA256 with timing-safe comparison), and graceful order status management on payment failure
- AI description generation at scale — Using Claude Haiku to generate meaningful descriptions for ~400 products that had empty or minimal descriptions, with dry-run mode, backup JSON, cost tracking, and preservation of existing specification content
- Security hardening across the stack — Implementing comprehensive security headers (HSTS, CSP, X-Frame-Options), rate limiting on all public API endpoints, HTML sanitisation for user-generated content, input sanitisation for search queries, and role-based admin access with middleware protection
What I'd Improve Next
- Live inventory sync — Replace the current CSV-based import with Square's real-time inventory webhooks to keep stock levels automatically synchronised between Square POS and the website
- Product reviews and ratings — Add a customer review system with star ratings, moderation queue, and review-driven sort/filter to build social proof and improve product page SEO with Review structured data
- Related products and cross-selling — Implement "Customers also bought" and "You may also like" sections on product pages using category-based or purchase-history recommendations
- Shipping calculator — Integrate a shipping rate API (Australia Post, Sendle) to provide real-time shipping quotes at checkout instead of the current "quoted separately" approach
- Order tracking dashboard — Build a customer-facing order tracking page where buyers can check order status, view shipping updates, and access their order history without needing to contact support