Skip to content

Repository files navigation

Racerz — Premium Motorcycle Showroom & Telemetry Cockpit

Racerz is a production-grade, full-stack web application for discovering, comparing, and experiencing premium motorcycles. Built for riders and enthusiasts in mind, it combines a curated showroom catalog backed by PostgreSQL with high-fidelity browser-synthesized engine acoustics, a side-by-side telemetry comparison cockpit, an interactive 3D rider profile, and a retrieval-augmented (RAG) AI concierge that answers questions with zero API keys — fully local and free.

The application is engineered as a single deployable unit: a server-rendered React frontend (TanStack Start + React Router), type-safe server functions, Supabase for database and authentication, pgvector for vector search, and Cloudflare Workers as the edge runtime.


Table of Contents


What is Racerz?

Racerz is not a typical listing site. It is a high-fidelity, interactive experience designed to feel like an active racing garage rather than an e-commerce catalog. Visitors can:

  • Browse a curated catalog of six motorcycle categories — sports, naked, adventure, cruisers, electric, and scooters.
  • "Start the engine" on any machine and hear a procedurally synthesized exhaust note generated in the browser via the Web Audio API (no audio files, no latency).
  • Compare up to four superbikes head-to-head across four-and-a-half dozen telemetry specs, with radar charts and auto-badged winners.
  • Open an interactive 3D rider-license ID card with parallax tilt and tachometer rings.
  • Ask the built-in AI concierge — R Assistant — questions about the catalog and get answers grounded in real showroom data, running entirely locally.

The project is intentionally dependency-light at runtime: the AI layer runs embeddings and retrieval completely offline, meaning the app has no recurring API costs for its flagship concierge feature.


Key Features

1. Procedural DSP Engine Sound Synthesizer

  • No audio assets. Exhaust sounds are synthesized in real time with the Web Audio API, removing bulky media files from the bundle.
  • Engine-type-specific acoustics, each modeled with distinct oscillator and waveform designs:
    • Sports (superbike) — detuned parallel sawtooth oscillators for a high-frequency inline-four / V4 scream.
    • Cruisers — an ultra-low-frequency V-twin "potato-potato" thump modulated by a custom 6.5 Hz LFO.
    • Naked — a throaty, performance-tuned triple/quad exhaust note.
    • Electric — clean sine/triangle pitch-sweep emulating an EV motor wind-up.
  • Tachometer rev sweeps — a circular speed-dial visualizer; hovering or dragging across the gauge sweeps synthesizer frequency up to 12,000 RPM.
  • 60fps equalizer visualizer — a canvas AnalyserNode drawing real-time frequency heights via requestAnimationFrame.

2. Telemetry Comparison Cockpit (/compare)

  • Compare up to 4 motorcycles simultaneously with sticky, scroll-locked column headers.
  • Fuzzy search with instant autocomplete and cached recent searches.
  • 14 telemetry specifications compared: displacement, power, torque, top speed, curb weight, seat height, fuel capacity, fuel consumption, transmission, and more.
  • Recharts radar spider charts overlaying Touring, Comfort, Speed, and Range.
  • A "Differences only" filter hides identical rows to surface distinct specs, and winner badges auto-highlight the lightest, cheapest, fastest, and most powerful machines.

3. 3D Rider License Trackpass ID (ProfileScene3D)

  • Apple/Threads-style parallax card that tilts in 3D based on cursor position using Framer Motion springs.
  • Interactive SVG tachometer rings that rev and redline on hover, framing the rider avatar.

4. R Assistant — RAG AI Chatbot Concierge

  • Semantic retrieval over a Supabase pgvector index with HNSW-accelerated cosine similarity.
  • 100% local and free embeddings via @huggingface/transformers (Xenova/all-MiniLM-L6-v2, 384-dim ONNX). No API keys, no payments, no external LLM calls.
  • Hybrid retrieval — Reciprocal Rank Fusion (RRF) merges local vector search with a keyword + prefix-semantic matcher.
  • Conversation-aware — follow-up turns are normalized into standalone queries.
  • Retrieval-grounded answers — bike quotes return real showroom specs from the indexed catalog; out-of-scope questions gracefully hand off to a human.
  • Crawler + indexer — a background sync crawls static routes and custom_bikes records, chunking content and upserting embeddings idempotently.
  • TanStack Router-safe markdown — links in chat resolve through the client router without full-page reloads.
  • Admin index console — authorized users can trigger a manual KB crawl from the chat header with toast status feedback.

Technology Stack

Layer Technology Role
Meta-framework TanStack Start Full-stack SSR + type-safe server functions
Routing TanStack Router File-based, type-safe client routing
UI framework React 19 Component rendering & interactions
Styling Tailwind CSS 4 Utility-first styling system
Data fetching TanStack Query Server state & caching on the client
Database & Auth Supabase PostgreSQL, RLS policies, email auth
Vector search pgvector 384-dim embedding similarity (HNSW)
Embeddings (local) @huggingface/transformers ONNX feature extraction, no API cost
Animations Framer Motion Cinematic micro-interactions & 3D parallax
Charts Recharts Radar/spider telemetry visualizations
Audio synthesis Web Audio API Procedural engine sound synthesis
UI primitives Radix UI Accessible, unstyled component primitives
Forms & validation react-hook-form + Zod Schema-validated forms
Runtime Cloudflare Workers Edge serverless deployment
Build tool Vite Dev server & production bundling
Package manager Bun / npm Scripts & dependency management

System Architecture

┌─────────────┐      Server Functions / RPC       ┌─────────────────────┐
│   Browser   │ <────────────────────────────────> │ TanStack Start SSR  │
│  (React 19) │   type-safe createServerFn calls   │  Edge/Server Runtime│
└─────┬───────┘                                    └──────────┬──────────┘
      │ Web Audio synthesis, Recharts, 3D parallax           │
      │                                                      │
      │                        ┌─────────────────────────────┼───────────────────┐
      │                        │                             │                   │
      │                  ┌─────▼──────┐              ┌───────▼────────┐   ┌───────▼────────┐
      │                  │  Supabase  │              │  pgvector (HNSW)│   │ transformers.js │
      └──────────────────│ PostgreSQL │────────────> │  kb_embeddings  │<──│  local ONNX     │
                         │ + RLS Auth │              │  match_kb_...()  │   │  embeddings     │
                         └────────────┘              └──────────────────┘   └────────────────┘

Request flow

  1. The browser client calls type-safe server functions (createServerFn) generated by TanStack Start.
  2. Server functions query Supabase — public catalog data via RLS-protected tables, embeddings via the match_kb_embeddings(...) SQL function.
  3. For the concierge, the server generates a 384-dim query embedding locally with the ONNX model, retrieves the top relevant chunks from the pgvector index, and fuses results with keyword matching (RRF) to produce a grounded answer.
  4. All rendering is server-side for SEO and performance, then hydrated on the client.

Project Structure

The codebase follows a TanStack Start convention: file-based routes under src/routes, UI components under src/components, server/prisma-free data access under src/lib, and Supabase integrations isolated in src/integrations.

Bike_Store/
├── .github/
│   └── workflows/
│       └── deploy.yml                  # CI: build + deploy to Cloudflare Workers
├── public/
│   └── favicon.ico
├── scripts/
│   ├── run-migrations.mjs              # Migration runner (Management API or Postgres)
│   ├── seed_motorcycles.ts             # Seeds the catalog from API Ninjas into Supabase
│   ├── upload_and_assign_images.ts     # Uploads + assigns CDN images to bikes
│   └── eval-rag.ts                     # Offline evaluation harness for the RAG pipeline
├── src/
│   ├── assets/                         # Local fallback bike imagery
│   ├── components/
│   │   ├── site/                       # App-shell & feature components
│   │   │   ├── Navbar.tsx              # Top navigation + auth-aware links
│   │   │   ├── Footer.tsx
│   │   │   ├── BikeCard.tsx            # Showroom grid card with "Start ignition"
│   │   │   ├── BikeActions.tsx         # Wishlist / enquiry actions
│   │   │   ├── EngineDashboardHUD.tsx  # Floating tachometer + equalizer dock
│   │   │   ├── RAssistantChat.tsx      # R Assistant AI concierge widget
│   │   │   ├── ProfileScene3D.tsx      # 3D rider-license trackpass card
│   │   │   ├── BrandMarquee.tsx        # Brand ticker
│   │   │   ├── CatalogUnavailable.tsx  # Graceful empty-state
│   │   │   ├── EstimatedPriceNote.tsx  # Pricing disclosure component
│   │   │   ├── ScrollProgress.tsx      # Reading progress indicator
│   │   │   ├── PageTransition.tsx      # Route transition animations
│   │   │   └── Counter.tsx             # Animated stat counters
│   │   └── ui/                         # Radix-based shadcn/ui primitives (button, card, dialog, ...)
│   ├── data/
│   │   └── bikes.ts                    # Category taxonomy + client-safe constants
│   ├── hooks/
│   │   ├── use-auth.tsx                # Auth context provider (sign in / sign up / sign out)
│   │   └── use-mobile.tsx              # Responsive breakpoint hook
│   ├── integrations/
│   │   └── supabase/
│   │       ├── client.ts               # Browser Supabase client (anon key)
│   │       ├── client.server.ts        # Server Supabase admin client (service role)
│   │       ├── auth-middleware.ts      # Bearer-token auth verification for server calls
│   │       ├── auth-attacher.ts        # Attaches session bearer tokens to RPCs
│   │       └── types.ts                # Generated database types
│   ├── lib/
│   │   ├── engine-sound.ts             # Procedural Web Audio synthesizer
│   │   ├── chatbot.server.ts           # RAG pipeline: crawler, embeddings, retrieval
│   │   ├── chatbot.functions.ts        # TanStack server functions for the concierge
│   │   ├── motorcycles.server.ts       # DB queries for the catalog
│   │   ├── motorcycles.functions.ts    # TanStack server functions for the catalog
│   │   ├── error-capture.ts            # SSR error capture
│   │   ├── error-page.ts               # Branded error page renderer
│   │   └── utils.ts                    # Shared helpers (cn, ...)
│   ├── routes/                         # File-based routes
│   │   ├── __root.tsx                  # Root shell: meta, layout, providers, 404
│   │   ├── index.tsx                   # Home / landing page
│   │   ├── bikes.index.tsx             # Catalog with search & category filters
│   │   ├── bikes.$bikeId.tsx           # Individual bike detail page
│   │   ├── compare.tsx                 # Telemetry comparison cockpit
│   │   ├── about.tsx / contact.tsx     # Static pages
│   │   ├── login.tsx / signup.tsx      # Email authentication pages
│   │   ├── _authenticated.tsx          # Auth-guarded route group
│   │   ├── _authenticated/dashboard.tsx# Rider dashboard
│   │   └── _authenticated/admin.tsx    # Admin management console
│   ├── routeTree.gen.ts                # Generated route tree (do not edit)
│   ├── router.tsx                      # Router factory with QueryClient context
│   ├── server.ts                       # SSR entry with error normalization
│   ├── start.ts                        # App bootstrap entry
│   └── styles.css                      # Tailwind + design tokens
├── supabase/
│   ├── config.toml                     # Local Supabase CLI config
│   └── migrations/                     # SQL migrations (schema + RLS + vector index)
├── .env.example                        # Documented environment variable template
├── .dev.vars.example                   # Cloudflare secret variable template
├── wrangler.jsonc                      # Cloudflare Workers configuration
├── vite.config.ts                      # Vite + TanStack Start configuration
├── components.json                     # shadcn/ui configuration
├── package.json
└── tsconfig.json

Database Schema

Managed through SQL migrations in supabase/migrations/. Key tables and objects:

Object Purpose RLS
custom_bikes The motorcycle catalog (specs, prices, images, features) Public read; admin write
kb_embeddings RAG knowledge base: chunked content + 384-dim embeddings Public read
profiles User profile data, auto-created on signup Owner / admin
user_roles App role assignment (admin / user) with has_role() helper Owner / admin
wishlist Saved bikes per user Owner only
enquiries Buyer enquiries sent to staff Owner / admin
bookings Test-ride bookings Owner / admin

Notable database features:

  • public.match_kb_embeddings(query_embedding, match_threshold, match_count) — pgvector similarity search (HNSW index, cosine).
  • A handle_new_user() trigger auto-creates profiles and a default user role on signup.
  • A custom_bikes_updated_at trigger maintains the updated_at column.
  • Row Level Security is enabled on every application table.

Getting Started

Prerequisites

  • Node.js v20 or newer
  • Bun (recommended) or npm
  • A Supabase project (database + auth)
  • A Cloudflare account — only required for deployment

1. Clone and install

git clone https://github.com/Pyro-Warrior-1884/Bike_Store.git
cd Bike_Store
npm install

2. Configure environment variables

Copy .env.example to .env and fill in your Supabase credentials (see Environment Variables). Never commit the real .env — it is already ignored by .gitignore.

3. Apply database migrations

npm run db:migrate

This enables pgvector, creates all tables listed above, configures Row Level Security, and installs the vector-search function.

4. Seed the motorcycle catalog

bun scripts/seed_motorcycles.ts

Fetches real motorcycle data from the API Ninjas Motorcycles API, stores it in custom_bikes, and assigns category images from the local assets.

5. Start the development server

npm run dev

Open http://localhost:3000.

Note: if the catalog is not yet seeded (and the database is unreachable), the UI renders a graceful CatalogUnavailable state instead of failing.


Environment Variables

The application expects the following environment variables. Reference values only — obtain the real values from your Supabase project dashboard.

Variable Required Description Used by
VITE_SUPABASE_URL Yes Supabase project URL Browser client
VITE_SUPABASE_PUBLISHABLE_KEY Yes Anon / publishable API key Browser client
VITE_SUPABASE_PROJECT_ID No Project reference (used by some scripts) Scripts
SUPABASE_URL Yes Server-side Supabase URL Server / scripts
SUPABASE_SERVICE_ROLE_KEY Yes* Admin key (bypasses RLS — server-only, never ship) Server functions
SUPABASE_PUBLISHABLE_KEY No Fallback anon key for server contexts Server
DATABASE_URL Scripts Postgres connection string for migrations Migration runner
SUPABASE_DB_PASSWORD Scripts Database password for migrations Migration runner
API_NINJAS_KEY Seed API Ninjas Motorcycles API key Seeding script

* Required when the catalog/RAG server functions run against Supabase in production.

Security note: SUPABASE_SERVICE_ROLE_KEY bypasses Row Level Security and must only ever live in server-side contexts (Cloudflare secrets / GitHub Actions secrets). It must never be referenced from client code or committed to the repository.

See .env.example and .dev.vars.example for the full commented templates.


Available Scripts

Command Description
npm run dev Start the Vite dev server
npm run build Production build
npm run preview Preview the production build locally
npm run deploy Build, then deploy to Cloudflare Workers
npm run db:migrate Run Supabase migrations
npm run db:push Push schema changes via the Supabase CLI
npm run eval:rag Evaluate RAG retrieval quality offline
npm run lint Run ESLint
npm run format Format the codebase with Prettier

Deployment

Racerz deploys serverlessly to Cloudflare Workers.

  1. Authenticate with Wrangler

    bunx wrangler login
  2. Configure runtime secrets

    Copy .dev.vars.example to .dev.vars, fill in server secrets (including SUPABASE_SERVICE_ROLE_KEY), and upload them:

    bunx wrangler secret bulk .dev.vars
  3. Build and deploy

    npm run deploy

CI/CD

.github/workflows/deploy.yml builds and deploys on push to main. It requires the following GitHub repository secrets:

CLOUDFLARE_API_TOKEN, CLOUDFLARE_ACCOUNT_ID, VITE_SUPABASE_URL, VITE_SUPABASE_PUBLISHABLE_KEY, VITE_SUPABASE_PROJECT_ID, SUPABASE_URL, SUPABASE_PUBLISHABLE_KEY, SUPABASE_SERVICE_ROLE_KEY, API_NINJAS_KEY.


Contributing

Contributions are welcome. To contribute:

  1. Fork the repository.
  2. Create a feature branch (git checkout -b feature/amazing-feature).
  3. Commit your changes with a clear message.
  4. Push to the branch and open a pull request.

Please keep commits scoped, follow the existing lint/format tooling (npm run lint, npm run format), and never commit environment files or secrets.


License

Distributed under the MIT License. See LICENSE for more information.

Releases

Packages

Contributors

Languages