A personal portfolio built with SvelteKit and Svelte 5, statically generated and deployed on Cloudflare Pages.
Lighthouse: 100 / 100 / 100 / 100
Interactive 3D Globe — Built with Three.js and three-globe. Dynamically loads WebGL textures at 1k, 2k, or 4k resolution based on device capability (screen size, memory, connection speed). Includes a rotating cloud layer, elevation mapping, and tilt-on-hover interaction.
Adaptive Performance — Device detection categorizes hardware as low, medium, or high-end to adjust texture resolution, frame rates, and animation complexity at runtime. Three.js and the globe are dynamically imported so they never block initial page load.
Starfield Background — Canvas-rendered animated star layer behind the globe.
Draggable Toolbar — A floating, GSAP-powered draggable toolbar for navigation and social links with glassmorphism styling.
Resume Viewer — Renders markdown to HTML with DOMPurify sanitization. Supports print-to-PDF and raw markdown download.
Photography Inquiry Form — Custom-built form with a styled dropdown (no native <select>), email validation, and Formspree backend integration.
RSS & Sitemap — Auto-generated Atom feed and XML sitemap for SEO.
| Layer | Tools |
|---|---|
| Framework | SvelteKit 2, Svelte 5 (runes) |
| 3D | Three.js, three-globe |
| Animation | GSAP + Draggable plugin |
| Content | mdsvex, marked, DOMPurify |
| Styling | Custom CSS variables, no framework |
| Testing | Playwright (Chromium + iPhone 13), Vitest |
| Deploy | Cloudflare Pages, static prerendering |
| Build | Vite 7, route-based code splitting |
- / — Landing, globe, work history, skills, about
- /resume — Markdown resume viewer
- /contact — Photography inquiry form
- All routes are prerendered at build time — no server runtime needed
- Three.js ecosystem is excluded from Vite pre-optimization and loaded via dynamic
import()to keep the initial bundle small - Chunks are split by route (resume, blog) and by library (GSAP, markdown processing, vendor)
- Security headers configured via Cloudflare
_headersfile (CSP, X-Frame-Options, cache policies) - Respects
prefers-reduced-motionfor all animations