Last updated: 2025-11-08
This document captures the agentic specification for a small TypeScript web project that lets a user drag-and-drop a 3D model into the browser and inspect it with PBR rendering using Babylon.js. It is intended to be a developer-facing specification: it defines goals, UX flows, data shapes, acceptance criteria, file layout, API contracts, edge cases, dev setup and verification plan.
- Write minimal, focused code that solves the problem directly
- Follow language-specific conventions and style guides
- Keep functions small and single-purpose
- Use meaningful names for variables, functions, and classes
- Avoid code duplication through reusable abstractions
- Handle errors explicitly and gracefully
- Document complex logic with inline comments
- Remove dead code and unused dependencies
- Maintain consistent UI patterns across features
- Provide clear feedback for user actions
- Use consistent terminology and messaging
- Ensure accessibility standards are met
- Design for mobile and desktop experiences
- Handle loading and error states gracefully
- Validate user input with helpful error messages
- Provide a minimal, robust in-browser 3D viewer powered by Babylon.js and TypeScript.
- Support drag-and-drop of local 3D files (glTF/GLB primary; OBJ/MTL fallback). Optionally support other formats via loaders.
- Render using PBR (metallic-roughness) with texture support (base color, normal, metallicRoughness, occlusion, emissive, alpha).
- Provide user interactions: orbit/zoom/pan camera, rotate model, toggle lighting, adjust environment intensity, change exposure/tonemapping.
- Show progress and error feedback for loading.
- Be easy to run locally (Vite-based dev server) and easy to extend.
- This is not a full 3D editor. No persistent saving or complex scene editing.
- No server-side model processing — all loading is client-side.
- Language: TypeScript
- Bundler/dev server: Vite
- Renderer: babylonjs (core) + @babylonjs/loaders (GLTF/OBJ) — use the published packages under the modern names (e.g., "@babylonjs/core" and "@babylonjs/loaders")
- UI: Plain HTML/CSS with small UI controls (no heavy UI framework required). Optionally add a tiny UI library later (e.g., vanilla-floating controls or a lightweight component lib).
- Dev tools: ESLint, Prettier optional, basic unit tests with Vitest (optional, minimal smoke tests).
Suggested minimal dependencies (for package.json):
- vite
- typescript
- @babylonjs/core
- @babylonjs/loaders
- @types/node (dev)
- vitest (dev) (optional)
Pin versions at implementation time.
- User opens the app; sees a centered canvas and a drag-and-drop hint area.
- The scene initializes with a neutral environment (HDR skybox or procedural environment) and a default camera and light.
- User drags a supported 3D file onto the drop area or clicks a fallback file picker.
- App parses the file locally using Babylon loaders. Show progress spinner and percent where available.
- On success: the model is shown, camera frames the model, and controls are enabled (orbit/zoom/pan). The UI shows basic model info (file name, mesh count, texture count).
- User can change lighting intensity/color, switch environment maps, toggle ground/grid, and adjust exposure/tonemapping.
- User can re-drop a new model to replace the scene.
- On error (unsupported file, corrupt file, missing textures), show clear error with possible remediation (e.g., "Try exporting as glTF/GLB").
Accessibility and input modalities
- Support mouse and touch for camera controls.
- Keyboard shortcuts: reset camera (R), toggle UI visibility (H), zoom to fit (F).
- Primary supported format: glTF (.gltf) and binary glTF (.glb) via Babylon's GLTF loader.
- Secondary: OBJ + MTL using Babylon OBJ loader. Textures must be provided alongside.
- For other formats (FBX, STL) we will not implement first — mention as future work (FBX is proprietary/complex).
When loading, handle these cases:
- glb: single-file, embedded textures — load directly from File blob using URL.createObjectURL.
- gltf + external resources: when user drops a .gltf with separate files (textures), support drop of multiple files simultaneously; resolve relative URIs by mapping file names to blobs.
- OBJ + MTL: accept both files in one drop, or if only OBJ is dropped use default material.
- All model parsing and rendering is client-side only. Do not upload dropped files off the user's machine.
- Be careful with using URL.createObjectURL and revokeObjectURL after use.
- Limit file size for UX safety (e.g., warn > 200 MB) but allow loading if browser supports it.
Contract for the viewer module (minimal public surface)
- initialize(options): Promise
- Inputs: { canvas: HTMLCanvasElement, engineOptions?: object, sceneOptions?: object }
- Output: Promise resolves when scene & defaults are ready
- loadFiles(files: FileList | File[]): Promise
- Inputs: an array-like of File objects (from drag/drop or file input). Implementation maps names/URIs for glTF resources.
- Output: { success: boolean, message?: string, metadata?: { meshes: number, materials: number, textures: number } }
- dispose(): void
- Clean up Babylon engine, revoke object URLs, free GPU resources.
Error modes
- Unsupported extension: return success:false with message.
- Parse error: return message and console.error stack.
Data shapes
- LoadResult:
- success: boolean
- message?: string
- metadata?: { meshes: number, nodes: number, materials: number, textures: number, fileName?: string }
The feature is acceptable when the following manual tests pass:
- Load a glb (single-file) model — textures render correctly and camera frames model.
- Load a gltf with external textures passed in the same drop — textures render and relative URIs resolved.
- Zoom/rotate/pan work on mouse and touch.
- Toggle environment intensity and see visible material response.
- Drop an unsupported file extension and see an error message.
Automated tests (suggested, low effort):
- Unit: viewer.initialize returns without throwing when given a canvas mock.
- Unit: loadFiles rejects with unsupported file type for a .txt file.
Manual verification checklist
- Verify PBR materials respond to environment HDR/intensity.
- Verify embedded and external textures load and are applied.
- Verify that object URLs are revoked when model replaced or viewer disposed.
- Very large files (100s MB) may crash or hang the browser. Mitigation: display a warning and allow cancel.
- glTF with absolute external URIs — these must be fetched; prefer local mapping (warn user) or block cross-origin requests.
- Missing resources in a multi-file drop — show partial load and list missing files.
- Multiple files dropped where none is a recognized model — show error and suggest file picker.
- Models with many materials/meshes — combine or flatten where possible for performance (future optimization).
- Use hardware-accelerated WebGL via Babylon engine.
- Limit default texture sizes by downscaling very large images (optional enhancement).
- Dispose unused scenes and textures when loading new model to avoid memory leaks.
index.html— minimal shell with canvas and controls.src/main.ts— bootstraps app, wires DOM events (drag/drop, file input) and attaches the viewer.src/viewer.ts— Babylon wrapper: init engine, scene, camera, lights, environment, loader logic, public API described above.src/ui/controls.ts— lightweight UI for toggles/sliders (exposure, env intensity, ground, reset).src/styles.css— minimal styling.public/— sample environment maps, sample models for development.
- Clone repo locally.
- npm install
- npm run dev (start Vite). Open http://localhost:5173
This will be turned into an explicit README.md during scaffold.
- Create a small set of sample models (FBX / GLB / glTF with external textures) to manually test loaders.
- Test in latest Chrome, Firefox, and Edge. Ensure touch interaction works on a mobile device.
- Smoke-test memory with Chrome DevTools when repeatedly loading/unloading models.
- Project scaffold and canonical viewer that shows a built-in sample glb.
- Drag-and-drop + local file glTF/glb loading (single-file) implemented.
- Multi-file drop and URI mapping for external textures.
- OBJ/MTL support.
- UI controls for lighting/environment/exposure.
- Small performance & memory leak fixes, tests, README.
- Add model library and presets, implement GLB streaming for large models, add analytics (opt-in), add share/upload features (explicit consent), multi-file drag-and-drop with zip support.
- Keep third-party packages up to date and watch for major changes in the Babylon package split (imports under
@babylonjs/corevs legacy bundles). Use ESM-compatible package imports (Vite-friendly).
Next step: scaffold the TypeScript + Vite project with minimal viewer skeleton and an example glb; wire drag-and-drop. See TODO in workspace task list.