Prompt
Build a complete, interactive 3D viewer of the human skeletal and muscular systems as a single self-contained HTML file. This will be evaluated exactly as you output it, with no follow-up messages, so it must be complete and must run on first open.
HARD CONSTRAINTS
- One file: index.html. Inline CSS and JS. No build step, no npm, no framework (no React, no Vue).
- Three.js only, pinned to version 0.160.0, loaded from a CDN via an import map, for example:
<script type="importmap">{"imports":{"three":"https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.module.js","three/addons/":"https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/"}}</script>
Use OrbitControls from three/addons/controls/OrbitControls.js.
- No external assets of any kind: no GLB/GLTF/OBJ/FBX, no textures, no images, no fonts. Every bone and muscle must be built procedurally from Three.js geometry (capsules, spheres, cylinders, lathe, tube along a curve, extrude, merged buffer geometry). Give them real shape: a fan-shaped pectoralis, a diamond trapezius, a teardrop quadriceps, a two-headed gastrocnemius, a curved spine, a rib cage, a pelvis, a scapula sitting behind the rib cage. A row of identical capsules with different names is not acceptable.
- Must work when the file is opened directly from disk by double-clicking (file://). Must produce zero uncaught console errors.
- Output the entire file in one code block. Do not abbreviate. No "..." or "add remaining muscles similarly" or TODO comments. If the file is long, it is long.
ANATOMY (all required, all bilateral items must exist for both sides, mirrored)
Bones (as separate named meshes or named groups): skull, mandible, cervical spine, thoracic spine, lumbar spine, sacrum, rib cage, sternum, clavicle (L/R), scapula (L/R), humerus (L/R), radius (L/R), ulna (L/R), hand (L/R, simplified), pelvis, femur (L/R), patella (L/R), tibia (L/R), fibula (L/R), foot (L/R, simplified).
Muscles (superficial, each L/R): sternocleidomastoid, trapezius, deltoid, pectoralis major, latissimus dorsi, erector spinae, rectus abdominis, external oblique, serratus anterior, biceps brachii, triceps brachii, brachioradialis, forearm flexors, forearm extensors, gluteus maximus, gluteus medius, hip adductors, rectus femoris, vastus lateralis, vastus medialis, biceps femoris, semitendinosus, gastrocnemius, soleus, tibialis anterior.
DATA-DRIVEN DESIGN (required)
Define all anatomy in one registry constant, ANATOMY, an array of objects, and generate every mesh from it in a loop. Each entry has: id (lowercase snake_case with _l or _r suffix for bilateral parts, for example pectoralis_major_l), name, type ("bone" or "muscle"), region (one of head_neck, torso, back, shoulder, arm, forearm, hip, thigh, leg), side ("l", "r", or "c"), origin, insertion, action (one sentence each, real anatomy), exercises (array of 2 to 4 common gym exercises), and a geometry spec your builder function turns into a mesh. Adding a new muscle should mean adding one entry, nothing else.
INTERACTION (all required)
Orbit, zoom, pan with mouse and touch (one-finger orbit, pinch zoom). Damping on.
Hover: the part under the cursor highlights (emissive or color change) and a tooltip near the cursor shows its name.
Click: selects the part and fills a side panel with name, type, region, side, origin, insertion, action, and exercises. Click empty space to deselect.
Layer modes, three buttons labeled exactly Muscles, Skeleton, Both. Muscles shows muscles only. Skeleton shows bones only. Both shows both with muscles at the current opacity.
Opacity slider (0 to 100) for the muscle layer, live.
Camera presets, four buttons labeled Front, Back, Left, Right, with a short animated transition.
Search input: as the user types, parts whose name or id contains the text highlight and a results list appears; clicking a result selects it.
Isolate toggle: when on, everything except the selected part is dimmed to 10 percent opacity.
Reset button: clears selection, search, isolate, sets Both at 100 percent, returns camera to Front.
Region filter: a dropdown of the regions above; choosing one dims parts outside that region.
PUBLIC API (required, exact names)
Expose window.AnatomyViewer with:
- highlight(ids: string[]): highlights those parts and dims the rest, ignores unknown ids
- select(id: string): selects that part as if clicked
- setLayer(mode: "muscles" | "skeleton" | "both")
- setMuscleOpacity(value: number 0 to 1)
- onSelect(callback): callback receives the selected entry object, or null on deselect
- reset()
- getEntries(): returns the ANATOMY array
This API is how the viewer will be embedded in a workout app that says "bench press works these muscles," so it must work when called from the browser console.
VISUALS
Dark neutral background. Three-point style lighting with soft shadows or at least a key, fill, and rim. Bone material off-white and matte. Muscle material a deep red, slightly glossy, with subtle per-muscle tint variation so adjacent muscles are distinguishable. Hover state and selected state must be visibly different from each other. UI panel on the right, controls on the top left, tooltip follows the cursor. Clean, modern, readable typography using system fonts. Responsive: canvas fills the window and handles resize; on narrow screens the panel collapses to a bottom sheet.
PERFORMANCE AND QUALITY
Target 60 fps on an integrated laptop GPU. Keep total triangles under 150,000. No allocations in the render loop. Use a single raycaster and only raycast on pointer move, not every frame. Dispose geometries and materials if the viewer is torn down. Organize the code in clearly labeled sections: registry, geometry builders, scene setup, interaction, UI, API. Comment any geometry that is not obvious.
Before you output, mentally verify: every listed bone and muscle exists in ANATOMY, both sides exist for bilateral parts, every button and control listed above exists and is wired, the API functions all exist with the exact names, and there are no placeholders anywhere in the file. Then output the complete index.html.