Open-source Astro + Svelte learning project for Wheelora, an AI decision wheel concept built around fast choices, local-first creation, starter packs, weighted spins, and a playful interactive demo.
This repository is intentionally the public web experience only. The mobile app, backend API, database schema, and private product docs live elsewhere.
I made this repository public as an educational, hobby-oriented build log for how I approach a modern Astro + Svelte web project. The goal is to make the implementation inspectable: fast pages, accessible UI, SEO metadata, AI crawler context, responsive layout, and a real interactive Svelte demo.
It is a reference for how I like to build product-shaped web experiences:
This repository is shared for learning, portfolio, and hobby purposes. It is not legal advice, immigration advice, or a statement about anyone's employment status. If you are in a visa-sensitive situation, talk to a qualified attorney or your school advisor before relying on any project structure.
Latest mobile PageSpeed Insights run shared from production:
| Category | Score |
|---|---|
| Performance | 100 |
| Accessibility | 100 |
| Best Practices | 100 |
| SEO | 100 |
| Metric | Result |
|---|---|
| First Contentful Paint | 0.9 s |
| Largest Contentful Paint | 1.5 s |
| Total Blocking Time | 0 ms |
| Cumulative Layout Shift | 0 |
| Speed Index | 1.0 s |
Captured Apr 27, 2026 at 11:01 PM CDT with Lighthouse 13.0.1, mobile emulation, Moto G Power, and Slow 4G throttling. Lighthouse values vary by run, network, region, and deploy environment, so treat these as a production snapshot rather than a permanent guarantee.
If you are here to learn from the project, these are the most interesting parts:
robots.txt, and llms.txtAstro owns routing, static page generation, document structure, SEO metadata, and the production build. The project uses Astro because content-heavy pages should ship as HTML first, with JavaScript added only where needed.
Key pieces:
src/pagessrc/layouts/BaseLayout.astrodist@astrojs/sitemapastro.config.mjsSvelte powers the interactive product demo: wheel lists, theme switching, animated spins, result states, and SVG text fitting. The static pages stay Astro-rendered, while Svelte handles the parts that need state and motion.
Important demo files:
src/components/svelte/WebDemoApp.sveltesrc/components/svelte/WheelUI.sveltesrc/components/svelte/ThemeShowcase.sveltesrc/store/theme.tsThe spin physics, weighted result calculation, and text fitting helpers are written in TypeScript:
src/lib/spinLogic.tssrc/lib/textPathFitting.tsThe wheel demo uses weighted outcomes, secure random sampling when available, SVG arc labels, and bounded animation timing so the UI feels close to the app without needing the app runtime.
The global CSS is hand-authored in src/styles/global.css. The visual system is intentionally lightweight: no Tailwind build step, no component library theme runtime, and no CSS-in-JS.
The CSS focuses on:
The deployment image uses Bun, and the repo includes bun.lock. package-lock.json is also present so the project remains easy to install with npm in environments where Bun is not the default.
The Dockerfile has separate dependency, build, dev, and production targets. The production image serves the static dist output with a small Bun server in serve-static.ts, mostly so legal pages can be rendered through the backend legal API when deployed behind the production proxy.
.
├── public/
│ ├── assets/brand/
│ ├── llms.txt
│ ├── robots.txt
│ └── site.webmanifest
├── scripts/
│ └── clean-sitemap.js
├── src/
│ ├── components/
│ │ ├── LegalDocument.astro
│ │ └── svelte/
│ ├── data/
│ │ └── site.ts
│ ├── layouts/
│ │ └── BaseLayout.astro
│ ├── lib/
│ │ ├── spinLogic.ts
│ │ └── textPathFitting.ts
│ ├── pages/
│ ├── store/
│ └── styles/
├── astro.config.mjs
├── Dockerfile
├── package.json
└── serve-static.ts
Use Node.js 22.12+.
npm install
npm run dev
The dev server binds to 0.0.0.0:4321 so it works cleanly from containers and local network testing.
npm run build
npm run preview
npm run build runs Astro and then normalizes sitemap timestamps through scripts/clean-sitemap.js.
docker compose up --build web-preview
The preview service maps the production server to port 4323.
The /terms and /privacy routes are part of the public website, but production legal content is rendered from the Wheelora backend API.
At runtime, serve-static.ts expects:
INTERNAL_API_BASE=https://your-internal-api.example.com
Static fallback/client rendering can also use:
PUBLIC_LEGAL_API_BASE=https://your-public-api.example.com
If you fork this site for another project, replace the legal integration with your own content or API.
The site includes:
robots.txtllms.txtMost of this lives in src/layouts/BaseLayout.astro, src/data/site.ts, src/pages, and public.
The current production shape is intentionally simple:
serve-static.tsThe interactive demo is the largest client-side feature, so most performance work is about keeping that component purposeful, bounded, and visually stable.
You are welcome to study the implementation and adapt the code under the license terms. Please do not reuse Wheelora names, logos, icons, screenshots, product copy, or brand assets for another product.
Code is released under the MIT License. Wheelora brand names, logos, icons, screenshots, and product assets are not licensed for reuse. See LICENSE.md and TRADEMARKS.md.