Cosmic Crusader is a static Vite multi-page application. The interactive home route progressively enhances complete semantic portfolio HTML with a modular vanilla Three.js experience. /posts.html remains an independently usable normal page.
portfolio.ts
├── Vite HTML transform ──> crawlable index/posts HTML
├── ContentPanel ─────────> readable modal content
└── World ────────────────> celestial destinations
InputController ──> FlightController ──> Spacecraft + Camera
│ │
└──────────> LaserProjectileSystem
│
World interactables ─> ProximitySystem ─> HUD / ContentPanel
│
QualityManager ─────> World + SpaceRenderer
src/data/portfolio.ts is the verified structured source. The custom Vite HTML plugin in vite.config.ts renders:
- The complete 2D/crawlable portfolio in
index.html - The posts list in
posts.html - JSON-LD for the person, site, and real projects
Runtime code does not fetch or scrape portfolio content.
PortfolioApp owns application lifetime and creates the following independent modules:
SpaceRenderer: WebGLRenderer, composer, restrained bloom/vignette, resize, disposalWorld: solar system, destinations, instances, procedural environment, interaction registrySpacecraft: original ship geometry, anchors, engine effects, disposalInputController: keyboard, mouse/pointer lock, touch look, normalized actions, and held fire sourcesFlightController: acceleration, damping, persisted cruise-speed limits, boost, braking, orientation, camera, autopilot, collision recovery, resetLaserProjectileSystem: bounded instanced bolt/impact pools, cadence, inherited velocity, swept collision, quality, and disposalProximitySystem: nearest/inspectable object selection by surface distanceQualityManager: device-based presets and sampled-frame-rate downshiftsHUDController: telemetry, radar state, proximity prompt, projected destination markersContentPanel: content selection, native dialog/focus lifecycle, route synchronizationNavigationController: menu, map, autopilot selection, graphics/accessibility settingsTouchControls: joystick and large touch actionsAudioManager: muted-by-default procedural engine and UI audio
Every Three.js geometry, material, texture, animation loop, listener, and AudioContext has a disposal owner.
The animation loop uses a clamped delta and performs:
- Pause immediately when the document is hidden.
- Update procedural world animation and orbiters.
- Find the nearest interaction/collision candidate.
- Update flight, boost, damping, autopilot, collision prevention, and reset range.
- Recompute proximity and input context.
- Update the bounded projectile pool and swept collision checks.
- Consume bounded UI actions such as inspect, map, camera, and reset.
- Update the chase/cockpit camera.
- Update HUD, audio, and sampled quality.
- Render once through the selected graphics path.
High-frequency vectors remain in the simulation layer; the page is not rerendered by a UI framework.
GitHub Pages-friendly query state keeps important locations shareable:
/?destination=home/?destination=projects/?destination=projects&item=ib-question-bank/?destination=writing/posts.html
pushState, replaceState, and popstate synchronize content panels without requiring SPA rewrites. The former placeholder /posts/example-post.html is preserved as a noindex redirect to /posts.html.
- Build output contains all important text and links before JavaScript starts.
- WebGL failure or visitor choice reveals the complete 2D portfolio.
- Native dialogs provide modal semantics; explicit focus containment and restoration are implemented.
- Menus, radar markers, maps, links, settings, and panels are keyboard reachable.
- Reduced motion, reduced camera movement, high contrast, postprocessing disable, and guided exploration are available.
- Touch mode uses large labeled controls and prevents page scrolling while piloting.
| Feature | Low | Medium | High | Auto |
|---|---|---|---|---|
| Pixel ratio cap | 1.0 | 1.45 | 1.85 | Device selected |
| Stars | 1,200 | 2,800 | 5,200 | Device/frame selected |
| Asteroids | 60 | 120 | 180 | Device/frame selected |
| Postprocessing | Off | Available | Available | Adaptive |
| Shadows flag | Off | Off | Enabled for future selective use | Adaptive |
Stars use buffered point layers; asteroids use one InstancedMesh; laser cores, glow, and impacts use three bounded instanced pools; nebulae use small generated canvas textures. The main Three.js application is dynamically imported after the semantic shell. No large model, texture, video, or audio download exists.
npm run build produces a repository-path artifact using /spaceshipportfolio/. GitHub Actions runs npm ci, checks, tests, builds with --base=/, and deploys the root-based artifact required by portfolio.mycosmic.dev. The custom domain must be set in the repository's Pages settings; Actions deployments ignore CNAME files. No application server or VPS is involved.