A minimalist, fast portfolio built with vanilla HTML, CSS, and JS. Themes, a Netflix‑style Interests carousel with MP4 previews, and a ruler‑style Projects carousel are included. Build is handled by esbuild; no framework required.
- Entry point: index.html
- Main runtime logic: js/main.js
- Projects carousel module: js/projects-carousel.js
- Global styles: css/styles.css
- Theme tokens: config/theme-tokens.json
- Theme provider: js/theme-provider.js
- Interests carousel (horizontal, auto‑scroll, posters + MP4 preview on hover/focus)
- Projects carousel (ruler‑style, category tabs, accessible, no dependencies)
- Theme system (five themes, tokenized colors, icons via per‑theme SVG sprite)
- Microblog pages, Donate page, and basic static pages
- Asset policy optimized for simplicity (original PNG posters only; no AVIF/WebP pipeline)
- Restored Interests carousel MP4 previews (art&design, astro, bjj, ea, meditation, mathematics&physics).
- Added new topic “Mathematics & Physics” to the carousel order.
- Removed optimized image variants (AVIF/WebP) and their HTML sources; use original PNG posters only.
- Standardized poster filenames to URL‑safe names that map 1:1 to keys via encodeURIComponent:
See implementation details in docs/site-overview.md.
Prerequisites:
- Node 18+ (for esbuild) and a local HTTP server (Python 3 or any static server).
Install deps and build:
npm install
npm run buildServe locally (two options):
- Preferred:
npm run serve(serves from repo root at http://localhost:5501/) - Or manually:
python3 -m http.server 5502then open http://localhost:5502/index.html
See package.json.
npm run clean– reset dist/npm run build– bundle all JS and CSS, then inject hashed filenames into HTML (via scripts/inject-hashes.js)npm run serve– local static server on port 5501- Contracts utilities for DonationVault (optional):
npm run contracts:*
- Interests carousel is created at runtime by main.buildSet() and autoscrolled via rAF loop in main.step(). Media paths are computed with main.moviePath() and main.posterPath(), both using
encodeURIComponentto support names with ampersands. - Projects carousel is bootstrapped from JSON in js/projects-carousel.js and exposes initRulerCarousel(). It renders a centered, infinite ruler with accessible roving tabindex and category tabs.
- Posters: original PNGs only in
assets/posters/. The code references PNG posters directly (no AVIF/WebP<source>elements). - Videos: 1:1 short MP4 previews in
assets/movies/. - Filenames: ensure keys in JS order/copy map match poster and movie filenames after URL encoding (e.g., “art&design” →
art%26design.pngandart%26design.mp4in HTTP requests).
- Focus-visible styles and keyboard navigation are implemented across widgets.
- Interests preview video plays on hover/focus and respects reduced motion.
- Performance observers collect basic field metrics in js/main.js.
- No third‑party runtime dependencies; small, cacheable bundles.
- Keep UI logic vanilla and accessible.
- Add new Interests by updating the
orderandcopymap in js/main.js, and by placing poster/video in the correspondingassetsdirectories. - Follow coding standards in
.kilocode/rules.
- Typeface Recursive by Arrow Type – see assets/Typography/ArrowType-Recursive-1.085/README.md and assets/Typography/ArrowType-Recursive-1.085/Recursive_Desktop/README.md.
- Icon sprites per theme under assets/icons/compiled/.