Imported from MJPL013/elbaph (
AGENTS.md). Install upstream withnpx skills add MJPL013/elbaph. Copyright stays with the author.
AGENTS.md
This file is the operational guide for coding agents working on Elbaph. Treat the repository code as the final authority. If this document and the code disagree, inspect the relevant implementation and update this document in the same change.
Project Definition
Elbaph is a static, browser-based 3D portfolio for Manoj Pal. Visitors navigate a small spherical world, discover portfolio landmarks, and click them to open structured information panels.
Current product constraints:
- The experience is an explorable world, not a conventional resume page.
- The avatar stays at a fixed world position while the planet rotates beneath it.
- The world uses stylized low-poly geometry, shared toon materials, and ink outlines.
- Professional content is shown through landmarks and interaction panels. The resume PDF is not exposed in the public UI.
- Personal interests are intentionally placeholder content until the owner provides facts. Do not invent them.
- There is no backend, API server, database, router, or physics engine in this repository.
Current Implementation Status
- Four world quarters exist: Experience, AI Projects, Creative, and Contact.
- Thirteen portfolio landmarks and additional filler buildings are placed on the planet.
- All landmarks are true 3D procedural React Three Fiber components.
- Kazam Energy has a dedicated hero-building blockout with shared material slots, instanced chargers, instanced bollards, road markings, and atlas metadata.
- The texture manifest and prompt catalog exist, but runtime texture loading and generated texture files do not. Materials currently use solid toon colors.
- The Goku/Nimbus GLB is bundled locally. A lightweight placeholder renders while its lazy-loaded component and model load.
- The former personal placeholder is a visible Side Quest portal marked
WORK IN PROGRESS; it has no destination route yet. - Avatar readiness is confirmed only after a real GLB mesh renders, not merely after the file loader resolves.
- The sky dome uses a lightweight procedural shader for animated fine grain and horizon fuzz, reduced on low quality.
- Landmark interactions use district-colored Discovery Log panels with one Brief section expanded by default; Close and outside clicks dismiss the panel.
- Background music uses
Music/Morning_on_the_Map.mp3through one native audio element at 16% volume, starts after user interaction, loops, and persists mute state. - Keyboard movement, pointer/touch drag movement, collision blocking, interaction camera framing, quality tiers, and WebGL fallback are implemented.
- Render deployment is configured as a static site in
render.yaml.
Do not describe Kazam as a final textured production asset. It is the approved geometry/material-slot blockout awaiting a separate texture-generation and final-art phase.
Runtime Flow
src/main.tsxmountssrc/App.tsxand global CSS.App.tsxdetects WebGL, selects a quality tier, preloads the avatar, creates the R3FCanvas, and mounts DOM overlays.src/components/WorldScene.tsxowns lighting, shared materials, the planet, avatar, camera, diagnostics, and post-processing.src/components/TreadmillPlanet.tsxreads keyboard/pointer input, converts it to a camera-relative direction, checks raycast collisions, and rotates the complete planet group.src/components/Landmarks.tsxrenders portfolio landmarks and filler buildings fromsrc/world/landmarkData.ts.src/components/LandmarkBox.tsxconverts spherical coordinates to a position/quaternion, creates interaction and collision targets, and opens the selected content.src/components/scenery/HeroLandmark.tsxmaps eachbuildingArchetypeto its 3D building and adds a camera-facing label.src/components/InteractionOverlay.tsxresolves the selected ID throughsrc/content/portfolioContent.tsand renders the panel.src/components/WorldHud.tsxrenders quarter information and theBackgroundMusicControlDOM audio UI.
Source Of Truth
| Concern | Change here | Notes |
|---|---|---|
| Professional copy and links | src/content/portfolioCore.ts, portfolioExperience.ts, portfolioProjects.ts, portfolioAchievements.ts |
Use only confirmed facts. Preserve PortfolioContent shape. |
| Content schema and district labels | src/content/portfolioTypes.ts |
Content districts are not the same type as world quarters. |
| Content aggregation and lookup | src/content/portfolioContent.ts |
Every interactive landmark ID must resolve here. |
| Landmark position and visual metadata | src/world/landmarkData.ts |
Contains latitude, longitude, quarter, archetype, footprint, height, label offset, pad, and prop cluster. Do not put portfolio prose here. |
| Landmark-to-building selection | src/components/scenery/HeroLandmark.tsx |
Add new archetype rendering here after extending the type in landmarkData.ts. |
| Shared building primitives | src/components/scenery/buildings/BuildingKit.tsx |
Reuse these before adding another primitive abstraction. |
| District building geometry | src/components/scenery/buildings/*Buildings.tsx |
Files are grouped by Experience, Projects, Creative, and Contact. |
| Kazam hero geometry | src/components/scenery/buildings/KazamHeroBuilding.tsx |
Keep its explicit material/atlas metadata and performance budgets intact. |
| Shared toon palette | src/art/materials/materialPresets.ts |
Color and material family definitions. |
| Material IDs and types | src/art/materials/materialTypes.ts |
Extend deliberately; verification currently expects 17 IDs. |
| Material allocation/disposal | src/art/materials/ElbaphMaterialProvider.tsx |
One shared MeshToonMaterial per ID and one three-band gradient texture. |
| Planned texture contract | src/art/textures/textureManifest.ts |
Manifest only; it does not currently load textures. |
| Texture-generation prompts | docs/art/texture-prompt-library.md |
Prompt catalog only; no generated images are committed. |
| Avatar URL/preload | src/components/visuals/avatar/avatarAsset.ts |
The URL imports the tracked GLB through Vite. |
| Avatar sizing/orientation | src/components/Avatar.tsx, src/game/constants.ts |
Preserve attribution in README.md. |
| Movement math | src/game/treadmillMath.ts, src/game/facing.ts |
Keep math independent from React where possible. |
| Collision and traversal loop | src/components/TreadmillPlanet.tsx |
Uses predictive THREE.Raycaster; do not add a physics engine without explicit approval. |
| Camera behavior | src/components/CameraRig.tsx |
Handles follow, recentering, and interaction framing. |
| Interaction state | src/store/useGameStore.ts |
Zustand is the global source for active landmark and interaction state. |
| Pointer/touch state | src/store/usePointerInputStore.ts |
DOM pointer events are handled in PointerJoystick.tsx. |
| Debug state | src/components/DebugProbe.tsx, src/types/debug.ts |
Browser checks consume window.__SELF_WORLD_DEBUG__. Keep both synchronized. |
| Global visual/UI styles | src/styles.css |
Tailwind utilities are also used directly in overlay components. |
| Background music behavior | src/components/BackgroundMusicControl.tsx, src/hooks/useBackgroundMusic.ts |
Native HTML audio only; preserve first-interaction playback, 16% volume, looping, metadata preload, and mute persistence. |
| Static deployment | render.yaml |
Builds with npm ci && npm run build, publishes dist. |
Architectural Invariants
Do not break these without explicit owner approval and corresponding test changes:
- Keep the avatar fixed at
CHARACTER_FIXED_POSITION; movement rotates the planet quaternion. - Use viewport-relative movement from
src/game/facing.tsfor keyboard and pointer controls. - Freeze traversal while
useGameStore().isInteractingis true. - Keep collision lightweight: registered box colliders plus predictive raycasting.
- Keep portfolio facts separate from placement and geometry.
- Keep landmark IDs identical between
PORTFOLIO_CONTENTandLANDMARKS. - Keep building bodies attached to the spherical surface via
surfaceQuaternion. - Use
WorldBillboardLabelfor readable names; do not bake live text into a building facade. - Use
useElbaphMaterial()and shared material IDs in scenery. Do not add per-meshmeshStandardMaterialto the building kit. - High/medium quality use post-processing outlines. Low quality omits post-processing and may use local outline shells only on silhouette-critical geometry.
- Keep debug colliders hidden by default.
?debug=1and theHkey must continue to toggle them. - Keep the avatar placeholder visible until the GLB is ready.
- Do not expose or open the resume PDF from the app.
- Keep source files below 200 lines where practical; split by responsibility instead of compressing complex code into unreadable one-line structures.
Common Change Procedures
Edit existing portfolio facts
- Edit the matching file under
src/content/. - Do not change placement or geometry unless the request also asks for a world change.
- Run
npm run verify:contentandnpm run build.
Move or resize a landmark
- Edit only its entry in
src/world/landmarkData.tsfirst. - Keep
footprintaligned with the visible building and collider needs. - Adjust
labelOffsetif the billboard overlaps geometry. - Run layout, collision, render, and visual verification.
Add a portfolio landmark
- Add confirmed content under the correct
src/content/portfolio*.tsfile. - Add or reuse a
BuildingArchetypeand building component. - Add the archetype mapping in
HeroLandmark.tsx. - Add placement/configuration in
LANDMARKSusing the exact same ID. - Add or update verification expectations. Do not weaken counts merely to make tests pass.
Change a building or material
- Propose the visual concept, explain why it fits Elbaph, and state triangle/draw-call/texture implications before implementing a new visual direction.
- Reuse
BuildingKit.tsxand existing material IDs where they fit. - Add silhouette geometry only where it communicates function; reserve surface detail for future textures/decals.
- Check desktop, mobile, and
?quality=lowoutput.
Add runtime textures
This is not implemented yet. A complete change must include loading/fallback behavior, color-space handling, atlas use, low-quality variants, disposal, asset budgets, and verification. Do not merely add files matching manifest paths and claim textures are integrated.
Commands
Requirements: Node.js 20+, npm 10+, and Chrome or Edge for browser verification.
npm install
npm run dev
npm run build
npm run preview
Verification scripts:
npm run verify:content
npm run verify:architecture
npm run verify:avatar
npm run verify:audio
npm run verify:layout
npm run verify:render
npm run verify:visual
npm run verify:movement
npm run verify:relative-movement
npm run verify:focus-input
npm run verify:collision
npm run verify:camera
npm run verify:state
npm run report:size
report:size requires a current dist/, so run the build first. Browser checks start their own Vite server and locate local Chrome/Edge. Set PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH or CHROME_PATH if auto-detection fails. Screenshots and test artifacts go under ignored .agents/artifacts/.
Choose verification by blast radius, but run the full suite for movement, camera, collision, shared material, landmark-system, or renderer changes.
Quality And Performance Contracts
- Kazam budget: at most 7,000 triangles and 16 draw calls. Runtime checks inspect its
userDatametadata. - Shared scenery materials must not be duplicated; diagnostics compare material UUIDs.
- Future raster assets over 200 KB are flagged by
npm run report:size. - The active MP3 is 3.40 MiB and must remain a separate streamed asset;
report:sizewarns when an MP3 exceeds 5 MiB. - Current texture limits are declared in
TEXTURE_RUNTIME_LIMITS: 2048 category atlas, 1024 Kazam albedo atlas, 512 Kazam decal atlas, and 16-pixel gutters. - Quality can be forced with
?quality=high,?quality=medium, or?quality=low. - The material registry currently contains 17 shared IDs, including the portal-energy material.
Git And Generated Files
- Inspect
git statusbefore editing. Preserve unrelated user changes. - Do not commit
node_modules/,dist/,.agents/,.codex/, logs, screenshots, or local environment files. - The tracked avatar model at
3d_models/son_goku_and_kintoun_nimbus.glbis intentional. agent_instructions.txtis ignored legacy local context and contains stale claims. Do not use it as project truth; use this file and the implementation.- Keep commits scoped and describe the actual behavior changed.
Anti-Hallucination Rules
- Do not claim a feature, asset, metric, integration, or deployment exists without locating it in code or verifying it at runtime.
- Distinguish current implementation from roadmap work in every handoff.
- Do not invent personal facts, project links, employment details, or performance numbers.
- Do not infer that a manifest entry means its referenced file exists or is loaded.
- Music licensing and attribution are not recorded in this repository; do not claim redistribution rights without owner-provided evidence.
- When uncertain, name the unknown and inspect the relevant file or ask the owner. Do not fill gaps with plausible text.