Skip to content

Hmziq.rs

open-source

hmziq.rs

Personal portfolio. Space-themed landing page with 3D star field and particle text, particle math in Rust via WebAssembly (SIMD128).

Stack

Bun, TanStack Start + Router (SSR, file-based routing), TanStack Query v5, VitePlus (Vite + oxlint + oxfmt), React 19, TypeScript, Tailwind CSS v4, React Compiler, Three.js + React Three Fiber (custom GLSL shaders), Firebase Analytics, Geist + Geist Mono.

Path alias: ~/./src/

Structure

├── vite.config.ts               # VitePlus config (lint, format, prerender)
├── vite-plugin-content.ts       # Custom Vite plugin (virtual:content + HMR)
├── content/
│   ├── projects/<slug>/project.mdx      # 32 projects
│   └── experiences/<slug>/experience.mdx # 6 experiences
├── src/
│   ├── routes/
│   │   ├── __root.tsx          # WASM provider, analytics, star field, SEO meta, JSON-LD
│   │   ├── index.tsx           # Homepage
│   │   ├── projects.tsx        # Projects listing (type filters)
│   │   └── projects.$slug.tsx  # Project detail
│   ├── components/
│   │   ├── three/              # StarField, ScatterText, CanvasContextEvents
│   │   ├── sections/           # Hero, Skills, Initiatives, Projects, Experience, Blog
│   │   ├── layout/             # Footer, PageContainer, Section
│   │   ├── ui/                 # GlassCard, TechIcon, SocialLinks, SocialIcon, ErrorBoundary, BackLink, MarkdownRenderer, ScrollIndicator
│   │   ├── projects/           # ProjectCard, ProjectDetail, ProjectsListing, ProjectLink
│   │   ├── initiatives/        # InitiativeCard, MysteryCard
│   │   ├── blog/               # BlogPostCard
│   │   └── wasm/               # WASMCanvas
│   ├── hooks/                  # useReducedMotion
│   ├── contexts/               # WASMContext, AnalyticsContext
│   ├── types/                  # blog.ts, virtual-content.d.ts
│   ├── lib/
│   │   ├── wasm/               # core.ts, starfield.ts, scatter-text.ts, types.ts
│   │   ├── blog-api.ts         # Blog client (blog.hmziq.rs)
│   │   ├── blog-queries.ts     # TanStack Query options
│   │   ├── blog.functions.ts   # TanStack Start server function
│   │   ├── techIcons.ts        # ~80 tech-to-icon mappings
│   │   └── dateUtils.ts        # Period string parser
│   ├── content/
│   │   ├── data/               # site.json, metadata.json, user.json
│   │   ├── projects.ts, experiences.ts, initiatives.ts, blog.ts
│   └── styles.css              # Tailwind v4 @theme, @font-face
├── wasm/src/
│   ├── lib.rs, math.rs, star_field.rs, scatter_text.rs
├── public/
│   ├── fonts/, fav/, wasm/pkg/
│   ├── rss.xml, atom.xml, sitemap.xml
│   ├── robots.txt, _headers, app-ads.txt
├── scripts/                    # copy-wasm, fetch-github-stats, generate-feeds
└── tests/                      # Playwright

Commands

bun install && bun run dev          # install + dev server on :3000
bun run build                      # WASM release + feeds + production build
bun run build:wasm / build:wasm:dev
bun run preview / prod             # preview production build
bun run generate:feeds             # RSS, Atom, sitemap
bun run fetch:github               # pull stars/forks into frontmatter
bun run type-check                 # tsc --noEmit
vp check / vp lint / vp fmt        # lint + format

Env vars (Firebase Analytics, set via GitHub repository variables in CI):

VITE_FIREBASE_API_KEY, VITE_FIREBASE_AUTH_DOMAIN, VITE_FIREBASE_PROJECT_ID,
VITE_FIREBASE_STORAGE_BUCKET, VITE_FIREBASE_MESSAGING_SENDER_ID,
VITE_FIREBASE_APP_ID, VITE_FIREBASE_MEASUREMENT_ID

WASM

Zero-copy shared memory. Rust allocates Vec<f32> buffers, JS creates Float32Array views on WASM linear memory. No per-frame copy. Structure of Arrays layout (separate arrays per component) maps directly to shader attributes and enables SIMD batch processing (f32x16, 16 floats per op).

Star field: SIMD-batched spherical positions, colors, sizes, twinkle. Frustum culling (Gribb-Hartmann). Bitpacked visibility (64 stars/u64). Mouse/click speed control.

Scatter text: Offscreen canvas text sampling (up to 10k particles). Form mode (lerp 0.08) and scatter mode (friction 0.98), both SIMD-batched.

Math: Sin/cos lookup tables (1024 entries), 16-wide SIMD lookups, deterministic seeded random.

Build: LTO, opt-level 3, single codegen unit, panic = "abort", no overflow checks. wasm-opt -O4, --fast-math, --converge, aggressive inlining. Target features: +simd128,+bulk-memory,+sign-ext,+mutable-globals.

Content

MDX under content/, loaded via virtual:content Vite plugin (gray-matter, HMR). Blog posts prefetched at build time from blog.hmziq.rs. GitHub stars/forks synced into frontmatter via fetch-github-stats.ts. Feeds generated from blog API.

Accessibility

prefers-reduced-motion kills all CSS animations and transitions globally. useReducedMotion hook (useSyncExternalStore) lets components skip JS animations: StarField stops rotating, ScatterText snaps to final positions. Skip-to-content link in root layout.

Deployment

Cloudflare Pages via GitHub Actions on push to master. CI: Bun + Node 22 + Rust nightly (wasm32-unknown-unknown) + wasm-pack, Cargo cache, build, deploy via wrangler. Security headers in public/_headers (HSTS, nosniff, DENY framing, immutable static asset cache, correct WASM MIME type).