# Three.js — full corpus # LLM Wiki An open-source template for building LLM-powered knowledge bases, following [Andrej Karpathy's "LLM Wiki" pattern](https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f). You provide raw sources. The LLM reads them, writes structured wiki pages, cross-links everything, and maintains it over time. You never edit the wiki directly — you curate sources and ask questions. ## How It Works The system has three layers: ``` raw/ Sources you collect (articles, transcripts, notes, PDFs) wiki/ LLM-written & maintained pages (summaries, concepts, entities, syntheses) CLAUDE.md Schema that tells the LLM how to structure everything ``` Three operations drive the workflow: | Operation | Trigger | What happens | |-----------|---------|--------------| | **Ingest** | "ingest raw/my-source.txt" | LLM reads the source, creates a summary page, creates/updates concept and entity pages, adds cross-links, updates the index and log | | **Query** | Ask any question | LLM searches the wiki, synthesizes an answer with citations, optionally creates a synthesis page for novel insights | | **Lint** | "lint" or "health check" | LLM audits all pages for orphans, contradictions, missing links, incomplete sections, and low-confidence claims — fixes what it can, reports the rest | ## Quick Start 1. **Clone this repo** ```bash git clone https://github.com/YOUR_USERNAME/llm-wiki.git my-knowledge-base cd my-knowledge-base ``` 2. **Customize CLAUDE.md** for your domain - Update the Purpose section with your topic - Replace the placeholder tagging taxonomy with your own categories - Adjust confidence level descriptions if needed - Everything else (workflows, page formats, linking rules) works as-is 3. **Drop sources into `raw/`** - Text files, transcripts, articles, notes — any plain text - These are immutable once added; the LLM never modifies them 4. **Tell the LLM to ingest** ``` ingest raw/my-first-source.txt ``` The LLM will create summary pages, concept pages, entity pages, cross-links, and update the index. 5. **Ask questions** ``` What are the key differences between X and Y? ``` The LLM answers from the wiki, citing specific pages. 6. **Run health checks** ``` lint ``` The LLM audits the wiki and fixes issues. ## Directory Structure ``` . ├── CLAUDE.md # Schema — the LLM's instructions ├── raw/ # Your source documents (immutable) └── wiki/ ├── index.md # Master catalog of all pages ├── log.md # Append-only activity log ├── dashboard.md # Dataview dashboard (Obsidian) ├── analytics.md # Charts View analytics (Obsidian) ├── flashcards.md # Spaced repetition cards ├── summaries/ # One page per source document ├── concepts/ # Concept and framework pages ├── entities/ # People, tools, organizations, etc. ├── syntheses/ # Cross-cutting analyses and comparisons ├── journal/ # Research/session journal entries │ └── template.md # Journal entry template └── presentations/ # Marp slide decks ``` ## Enhancements This template includes several extras beyond the core wiki pattern: ### Dataview Dashboard (`wiki/dashboard.md`) Live queries that surface low-confidence pages, recent updates, concepts by tag, and pages with the most sources. Requires the [Dataview](https://github.com/blacksmithgu/obsidian-dataview) Obsidian plugin. ### Charts View Analytics (`wiki/analytics.md`) Visual analytics with pie charts, bar charts, and word clouds. Requires the [Charts View](https://github.com/caronchen/obsidian-chartsview-plugin) Obsidian plugin. ### Mermaid Diagrams Use Mermaid code blocks in any wiki page to create flowcharts, sequence diagrams, or concept maps. Native support in Obsidian and GitHub. ### Marp Slides (`wiki/presentations/`) Create slide decks from markdown using [Marp](https://marp.app/). Drop presentation files in this directory. ### Research Journal (`wiki/journal/`) Track your research sessions, experiments, or applied work with the included template. The LLM can reference journal entries when answering queries. ### Spaced Repetition (`wiki/flashcards.md`) Flashcards in the format used by the [Spaced Repetition](https://github.com/st3v3nmw/obsidian-spaced-repetition) Obsidian plugin. Ask the LLM to generate flashcards from any wiki page. ### MCP Server This repo works with Claude Code's MCP server capabilities. Point an MCP-compatible client at this repo and the LLM can read/write the wiki programmatically. ## Customizing for Your Domain The schema in `CLAUDE.md` is domain-agnostic. To adapt it: 1. **Purpose** — Describe your knowledge domain in one paragraph 2. **Tagging taxonomy** — Replace placeholder categories with your own (e.g., for a cooking KB: `cuisine`, `technique`, `ingredient`, `equipment`) 3. **Confidence levels** — Adjust the descriptions to match your domain's evidence standards 4. **Entity types** — Update the entity page description to match what entities mean in your domain (people, tools, companies, etc.) 5. **Journal template** — Customize `wiki/journal/template.md` for your workflow Everything else — page format, linking conventions, workflows, rules — is universal and works across domains. ## Example Domains This template works for any knowledge-intensive topic: - **Research notes** — papers, experiments, methodologies - **Book analysis** — themes, characters, author techniques - **Competitive analysis** — companies, products, market trends - **Course notes** — lectures, readings, key concepts - **Personal development** — frameworks, habits, book summaries - **Technical documentation** — APIs, architectures, design patterns - **Hobby deep-dives** — any subject you want to master ## License MIT # Three.js Knowledge Base An LLM-maintained production reference on **Three.js** — the JavaScript 3D library. Covers scenes and the scene graph, cameras and controls, geometry and primitives, materials and textures, lighting and shadows, fog and backgrounds, the WebGL renderer, responsive sizing, model loading (glTF), animation, raycasting/picking, post-processing, and performance. Verified against the official three.js docs, snapshot 2026-08-02. ## Concepts - [[concepts/threejs-overview|Three.js Overview]] - [[concepts/getting-started|Getting Started with Three.js]] - [[concepts/scene-graph|Scene Graph]] - [[concepts/primitives|Primitives]] - [[concepts/geometry-fundamentals|Geometry Fundamentals]] - [[concepts/cameras|Cameras]] - [[concepts/controls|Controls (OrbitControls)]] - [[concepts/materials|Materials]] - [[concepts/textures|Textures]] - [[concepts/lighting|Lighting]] - [[concepts/shadows|Shadows]] - [[concepts/fog-and-backgrounds|Fog and Backgrounds]] - [[concepts/renderer|Renderer]] - [[concepts/responsive-rendering|Responsive Rendering]] - [[concepts/loading-3d-models|Loading 3D Models]] - [[concepts/animation|Animation]] - [[concepts/raycasting-and-picking|Raycasting and Picking]] - [[concepts/post-processing|Post-Processing]] - [[concepts/performance|Performance and Optimization]] ## Syntheses - [[syntheses/performance-and-optimization|Performance and Optimization: Keeping a Three.js App Fast]] ## XL Edition (Pro) Per-item reference depth beyond this edition, in the gated XL layer (14 pages): deep **full API references** for every major subsystem — materials (full family), custom shaders, textures, lights, the renderer, geometry & buffers, objects, cameras, controls, math primitives, loaders, the animation system, the post-processing pipeline, and instancing/batching — with constructor signatures, property/method tables, and usage notes pulled from the official three.js class docs (~90 classes). Agents without Pro access should treat that per-class API depth as "covered in the XL edition" rather than out of scope. --- title: "Animation" type: concept tags: [threejs, animation, animationmixer, gltf, intermediate, foundational] created: 2026-08-02 updated: 2026-08-02 sources: ["raw/web_community-animationmixer-three-js-docs.md", "raw/web_community-gltfloader-three-js-docs.md", "raw/web_community-fundamentals.md", "raw/web_community-cleanup.md"] confidence: high threejs_docs_snapshot: "2026-08-02" --- ## Definition Three.js supports two complementary ways of animating a scene: procedural motion driven by application code inside the render loop, and authored clip playback through `AnimationMixer`, which plays `AnimationClip`s for a given root object. ## How It Works **Authored clips.** `AnimationMixer.clipAction(clip, optionalRoot, blendMode)` returns (creating it if necessary) an `AnimationAction` for a clip and root — calling it repeatedly with the same clip/root always returns the same action, enabling playback control and blending workflows. `GLTFLoader` returns an `animations` array with its loaded asset (see [[concepts/loading-3d-models]]), so model imports commonly feed straight into a mixer: ```js const mixer = new THREE.AnimationMixer(gltf.scene); const action = mixer.clipAction(gltf.animations[0]); action.play(); renderer.setAnimationLoop(() => { mixer.update(clock.getDelta()); renderer.render(scene, camera); }); ``` `AnimationMixer.update(deltaTime)` advances the mixer's global `time` by the given delta and updates the animation; this is normally called every frame with the delta time from a `Clock` or `Timer`. `AnimationMixer.timeScale` (default `1`) scales that global time — setting it to `0` and back to `1` is a documented way to pause and resume every action the mixer controls at once. **Procedural motion.** For application-driven motion, update object state — typically `position`, `rotation`, or `scale` on [[concepts/scene-graph|scene-graph]] objects — inside the render loop, then render the frame, using elapsed delta time rather than assuming a fixed frame rate: ```js function render(time) { time *= 0.001; // convert milliseconds to seconds cube.rotation.x = time; cube.rotation.y = time; renderer.render(scene, camera); requestAnimationFrame(render); } requestAnimationFrame(render); ``` Transform animation itself belongs to the [[concepts/scene-graph]]; render cadence and canvas ownership belong to the [[concepts/renderer]]. ## Key Parameters - `AnimationMixer.time` — the mixer's global time in seconds, starting at `0` on creation. - `AnimationMixer.timeScale` — scales global time; `0` pauses, `1` is normal speed. - `AnimationMixer.clipAction(clip, optionalRoot, blendMode)` — returns an `AnimationAction`; `blendMode` can be `NormalAnimationBlendMode` or `AdditiveAnimationBlendMode`. - `AnimationMixer.existingAction(clip, optionalRoot)` — looks up an already-created action without creating a new one, returning `null` if not found. - `AnimationMixer.setTime(time)` — jumps the mixer to an exact time (scaled by `timeScale`). ## When To Use Use `AnimationMixer` and clip playback whenever animating authored content — character rigs, keyframed props, or anything exported from a DCC tool via glTF (see [[concepts/loading-3d-models]]). Use procedural motion in the render loop for application-driven behavior that isn't captured as an authored clip, such as reacting to input, physics, or generative logic. Use delta time (from a `Clock`/`Timer`, or the render loop's `time` argument) in both cases rather than assuming a fixed frame rate, since real frame rates vary by device and load. ## Risks & Pitfalls - Assuming a fixed frame rate instead of using elapsed delta time produces animation speed that varies with actual frame rate. - Calling `mixer.uncacheAction()`, `uncacheClip()`, or `uncacheRoot()` without first stopping the associated action(s) via `AnimationAction#stop` is documented as unsafe — always stop actions before deallocating their mixer resources. - As with materials, geometry, and textures (see [[concepts/materials]] and [[concepts/geometry-fundamentals]]), animation resources are not automatically freed by garbage collection; follow the same explicit lifecycle discipline used elsewhere in three.js. ## Related Concepts Set up a scene through [[concepts/getting-started]], load clips via [[concepts/loading-3d-models]], and inspect visual results using [[concepts/cameras]]. See also [[concepts/scene-graph]] for the object transforms that both procedural and clip-driven animation ultimately update, and [[concepts/renderer]] for how the render loop and `mixer.update()` are coordinated. ## Sources - `raw/web_community-animationmixer-three-js-docs.md` — `AnimationMixer` API reference: constructor, `time`, `timeScale`, `clipAction`, `existingAction`, `setTime`, `update`, `uncacheAction`/`uncacheClip`/`uncacheRoot` and their stop-before-uncache requirement. - `raw/web_community-gltfloader-three-js-docs.md` — confirms `GLTFLoader`'s loaded-asset result includes an `animations: AnimationClip[]` array feeding directly into a mixer. - `raw/web_community-fundamentals.md` — procedural render-loop animation example (`requestAnimationFrame`, per-frame rotation updates, delta-time-from-milliseconds conversion). - `raw/web_community-cleanup.md` — general resource-disposal discipline extended here to animation/mixer cleanup. --- title: "Cameras" type: concept tags: [threejs, camera, perspective, projection, beginner, foundational] created: 2026-08-02 updated: 2026-08-02 sources: ["raw/web_community-creating-a-scene.md", "raw/web_community-fundamentals.md"] confidence: high threejs_docs_snapshot: "2026-08-02" --- ## Definition A camera defines the view used when a renderer draws a scene — it determines what portion of the 3D world, inside its viewing frustum, is visible in the final 2D image. The common entry point is `PerspectiveCamera`, whose field of view, aspect ratio, near plane, and far plane together determine what can be seen. ## How It Works ```js const camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 1000); camera.position.set(0, 1, 5); ``` The four `PerspectiveCamera` constructor arguments are, in order: - **field of view (fov)** — the vertical extent of the scene visible on the display, given in degrees (most other three.js angles are in radians, but the perspective camera takes degrees). - **aspect ratio** — normally the width of the render target divided by its height; using the wrong ratio squishes the image, similar to playing an old movie on the wrong-shaped screen. - **near** and **far** clipping planes — the range of space in front of the camera that gets rendered. Objects closer than `near` or farther than `far` are clipped and not drawn. Together these four values define a **frustum**: a pyramid-like 3D volume with its tip sliced off. Anything inside the frustum is drawn; anything outside is not. The height of the near/far planes is set by the field of view, and their width is set by the field of view combined with the aspect ratio. By default, objects added to a scene sit at the origin `(0, 0, 0)`. Since a camera also defaults to looking down the -Z axis from the origin, camera and subject would otherwise start inside each other — moving the camera back (e.g. `camera.position.z = 5`) is what makes the scene visible. ## Key Parameters - `fov` — vertical field of view in degrees; wider values expand the visible area but increase perspective distortion at the edges. - `aspect` — width/height ratio of the render target; should track the canvas's actual displayed aspect ratio. - `near` / `far` — clipping plane distances; treat these as part of scene design, not arbitrary defaults, since a very large `far`/`near` ratio can hurt depth precision while overly tight values may clip visible content. `PerspectiveCamera` argument order is `(fov, aspect, near, far)`. - `camera.position` — where the camera sits in the scene graph; must be moved off the origin to avoid nesting inside objects placed at the default position. ## Resize with the Renderer When the canvas size changes, update both the camera's aspect ratio/projection matrix and the [[concepts/renderer|renderer]]'s size together — they are two halves of the same responsive behavior: ```js camera.aspect = width / height; camera.updateProjectionMatrix(); renderer.setSize(width, height); ``` ## When To Use Use `PerspectiveCamera` for the vast majority of three.js scenes that should look naturally 3D with foreshortening. Tune `near`/`far` deliberately for scenes with large scale differences (e.g. a solar-system-scale scene may need different clipping planes than a tabletop-scale scene) to balance visible range against depth-buffer precision. ## Risks & Pitfalls - Forgetting to move the camera off the origin (or forgetting to move the subject) results in a blank render because the camera starts inside the geometry. - Failing to update `camera.aspect` and call `updateProjectionMatrix()` after a resize leaves the rendered image stretched or squished even though the canvas itself resized correctly. - Because a camera does not have to be part of the [[concepts/scene-graph]] to function, it's easy to forget that a camera parented to another object will inherit that parent's transform — useful intentionally, surprising otherwise. - Transparency sorting can vary depending on the camera's viewpoint; test transparent [[concepts/materials|materials]] against the intended camera angles rather than a single default view. ## Related Concepts Place cameras in the [[concepts/scene-graph]], produce frames with the [[concepts/renderer]], and test camera choices with transparent [[concepts/materials]] since transparency sorting can vary by view. See also [[concepts/getting-started]] and [[concepts/threejs-overview]]. ## Sources - `raw/web_community-creating-a-scene.md` — `PerspectiveCamera` constructor arguments (fov, aspect ratio, near/far clipping planes) and the origin-overlap rationale for moving the camera. - `raw/web_community-fundamentals.md` — frustum concept, the field-of-view/aspect relationship, and the note that a camera need not be part of the scenegraph to function. --- title: "Controls (OrbitControls)" type: concept tags: [threejs, controls, orbitcontrols, camera, interaction, beginner, foundational] created: 2026-08-02 updated: 2026-08-02 sources: ["raw/web_community-orbitcontrols-three-js-docs.md"] confidence: high threejs_docs_snapshot: "2026-08-02" --- ## Definition `OrbitControls` is an addon class that lets a user orbit, dolly (zoom), and pan a [[concepts/cameras|camera]] around a focus point using mouse, touch, or keyboard input, without the application writing its own input-handling code. ## How It Works `OrbitControls` is constructed with the camera it manages and the DOM element to attach listeners to: ```js import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; const controls = new OrbitControls(camera, canvas); controls.target.set(0, 0, 0); controls.update(); ``` `.target` is the focus point the camera orbits around; changing it and calling `.update()` re-centers the interaction. The controls modify the camera's `position` (and orientation toward `target`) directly in response to input — they do not replace the camera or the [[concepts/renderer]] call. **The update-loop contract.** Several features only work if `controls.update()` is called every frame inside the render loop: `autoRotate`, `enableDamping`, and any deltaTime-dependent behavior. Failing to call `update()` when these are enabled leaves the feature inert even though the property is set. **Events.** `OrbitControls` dispatches `start` (interaction begins), `change` (camera transformed), and `end` (interaction finished) events. This makes them a natural trigger for a [[concepts/performance|render-on-demand]] setup: render once per `change` event instead of running a continuous animation loop. ## Key Parameters - `.enableRotate` / `.enablePan` / `.enableZoom` — toggle each interaction independently; all default `true`. A single axis of rotation can be locked by setting `minPolarAngle`/`maxPolarAngle` (or `minAzimuthAngle`/`maxAzimuthAngle`) to the same value. - `.minDistance` / `.maxDistance` — dolly (zoom) limits for a perspective camera; default `0` / `Infinity`. - `.minZoom` / `.maxZoom` — zoom limits for an orthographic camera; default `0` / `Infinity`. - `.minPolarAngle` / `.maxPolarAngle` — vertical orbit limits in radians, range `[0, Math.PI]`; default `0` / `Math.PI`. - `.minAzimuthAngle` / `.maxAzimuthAngle` — horizontal orbit limits in radians; must be a sub-interval of `[-2*PI, 2*PI]` with `max - min < 2*PI`; default `-Infinity` / `Infinity` (unrestricted). - `.enableDamping` (default `false`) + `.dampingFactor` (default `0.05`) — adds inertia so movement eases out instead of stopping instantly; **requires** `update()` in the render loop. - `.autoRotate` (default `false`) + `.autoRotateSpeed` (default `2`, ≈30s per orbit at 60fps) — automatically spins around `target`; **requires** `update()` in the render loop, and passing `deltaTime` to `update()` if the rotation speed should be frame-rate independent. - `.target` (`Vector3`) — the focus point the camera orbits; update manually and call `.update()` to change focus. - `.zoomToCursor` (default `false`) — zoom toward the cursor position instead of the target. - `.mouseButtons` / `.touches` / `.keys` — remap which mouse buttons, touch gestures, and keyboard keys drive rotate/pan/dolly. - `.rotateSpeed` / `.panSpeed` / `.zoomSpeed` (all default `1`) / `.keyPanSpeed` (default `7` px/keypress) / `.keyRotateSpeed` (default `1`) — tune interaction sensitivity. - `listenToKeyEvents(domElement)` — required to enable keyboard panning/rotation; `window` is the recommended argument. ## When To Use Add `OrbitControls` any time a scene should let the user freely inspect a subject from multiple angles — product viewers, model previews, editors — rather than a scripted or fixed camera. Combine with `enableDamping` for a less stiff, higher-production feel, and with the `change` event for [[concepts/performance|render-on-demand]] apps that should stay idle until the user actually interacts. ## Risks & Pitfalls - Enabling `enableDamping` or `autoRotate` without calling `controls.update()` every frame silently does nothing — both features are explicitly documented as requiring the per-frame update call. - In a render-on-demand setup, calling `render()` directly from the `change` event while `enableDamping` is on creates an infinite loop (the render calls `update()`, which fires another `change` event); guard with a "render already requested" flag scheduled via `requestAnimationFrame` instead (see [[concepts/performance]]). - Restricting `minAzimuthAngle`/`maxAzimuthAngle` to an interval wider than `2*PI` (or violating the sub-interval requirement) is invalid per the documented constraint. - `minZoom`/`maxZoom` only affect orthographic cameras; `minDistance`/`maxDistance` only affect perspective cameras — setting the wrong pair has no effect for the current camera type. ## Related Concepts `OrbitControls` operates on a [[concepts/cameras|camera]] and pairs naturally with [[concepts/performance]] for render-on-demand and [[concepts/raycasting-and-picking]] (spinning a scene before picking an object). See also [[concepts/threejs-overview]]. ## Sources - `raw/web_community-orbitcontrols-three-js-docs.md` — `OrbitControls` API reference: constructor, `target`, `enableDamping`/`dampingFactor`, `autoRotate`/`autoRotateSpeed`, rotate/pan/zoom limits and toggles, `mouseButtons`/`touches`/`keys`, `listenToKeyEvents`, and the `start`/`change`/`end` events. --- title: "Fog and Backgrounds" type: concept tags: [threejs, fog, background, skybox, cubemap, scene, intermediate, foundational] created: 2026-08-02 updated: 2026-08-02 sources: ["raw/web_community-fog.md", "raw/web_community-backgrounds-and-skyboxes.md"] confidence: high threejs_docs_snapshot: "2026-08-02" --- ## Definition `scene.fog` fades rendered objects toward a chosen color based on distance from the camera. `scene.background` sets what's visible where nothing was drawn — a flat color, a texture, a cubemap, or an equirectangular environment — and is the basis for skyboxes. ## How It Works **Fog.** Three.js provides two fog types, both assigned to the scene: ```js const scene = new THREE.Scene(); scene.fog = new THREE.Fog(0xFFFFFF, /* near */ 10, /* far */ 100); // or, exponential falloff: scene.fog = new THREE.FogExp2(0xFFFFFF, /* density */ 0.1); ``` `Fog` fades linearly: anything closer than `near` is unaffected, anything farther than `far` is fully the fog color, and the zone between fades from material color to fog color. `FogExp2` grows exponentially with distance instead and is closer to how fog behaves in reality, but `Fog` is used more often because its explicit `near`/`far` lets an app show a clear scene up to a chosen distance before fading. Fog is computed per pixel as part of rendering — it only affects things actually drawn, so **the fog color and `scene.background` color should typically be set to the same value**, or the horizon will show a visible seam between fogged geometry and an unfogged background: ```js scene.fog = new THREE.Fog('lightblue', 1, 2); scene.background = new THREE.Color('lightblue'); ``` Materials have their own `.fog` boolean (default `true` on most materials) for opting individual surfaces out of scene fog — useful for a vehicle-simulator cockpit or house interior where the fog outside shouldn't visibly apply to the far wall of a room that's physically closer than the fog's `far` distance. **Backgrounds.** The simplest static background is pure CSS on the canvas element, with the renderer given `alpha: true` so undrawn areas are transparent: ```js const renderer = new THREE.WebGLRenderer({ antialias: true, canvas, alpha: true }); ``` If the background needs to be affected by [[concepts/post-processing]], it must be drawn by three.js itself instead of CSS — set `scene.background` directly to a loaded texture: ```js const loader = new THREE.TextureLoader(); const bgTexture = loader.load('resources/images/daikanyama.jpg'); bgTexture.colorSpace = THREE.SRGBColorSpace; scene.background = bgTexture; ``` A flat image background will stretch to fill the canvas; correcting the aspect ratio requires adjusting the texture's `.repeat`/`.offset` at render time based on the ratio between the canvas's and the image's aspect (this is the same `Texture` API covered in [[concepts/textures]]). **Skyboxes.** A skybox surrounds the camera with imagery so the horizon reads as sky. Common implementations: (1) a cube or sphere with an inward-facing texture (`material.side = THREE.BackSide`) placed directly in the scene or in a second scene rendered separately; (2) a **cubemap** — six square images, one per cube face, loaded with `CubeTextureLoader` and assigned straight to `scene.background`: ```js const loader = new THREE.CubeTextureLoader(); const texture = loader.load([ 'pos-x.jpg', 'neg-x.jpg', 'pos-y.jpg', 'neg-y.jpg', 'pos-z.jpg', 'neg-z.jpg', ]); scene.background = texture; ``` (3) an **equirectangular map** — a single wide image like a 360° photo — loaded as a normal `Texture` but tagged with `EquirectangularReflectionMapping` before being assigned as the background: ```js const loader = new THREE.TextureLoader(); const texture = loader.load('tears_of_steel_bridge_2k.jpg', () => { texture.mapping = THREE.EquirectangularReflectionMapping; texture.colorSpace = THREE.SRGBColorSpace; scene.background = texture; }); ``` Unlike a flat image background, cubemap and equirectangular backgrounds need no per-frame aspect correction — they already cover every viewing direction. [[concepts/controls|OrbitControls]] pairs naturally with any skybox so the user can look around it. ## Key Parameters - `THREE.Fog(color, near, far)` — linear fog; `near`/`far` are camera-relative distances. - `THREE.FogExp2(color, density)` — exponential fog; `density` controls falloff rate. - `material.fog` (boolean, default `true` on most materials) — whether scene fog applies to that material. - `scene.background` — accepts a `Color`, a `Texture` (flat image), a cubemap `Texture` from `CubeTextureLoader`, or an equirectangular `Texture` tagged `EquirectangularReflectionMapping`. - `WebGLRenderer({ alpha: true })` — required for a CSS-drawn (not three.js-drawn) transparent background to show through. - `material.side = THREE.BackSide` — needed on a skybox cube/sphere so its inward-facing surface renders. ## When To Use Use `Fog`/`FogExp2` to hide distant clipping/pop-in, create atmosphere, or bound visible draw distance for performance reasons. Use a plain CSS background when nothing in the 3D scene needs to composite with it. Switch to a three.js-drawn `scene.background` texture as soon as [[concepts/post-processing]] effects need to touch the background. Use a cubemap or equirectangular background (with [[concepts/controls|OrbitControls]]) for any scene that should feel surrounded by an environment rather than framed against a flat backdrop. ## Risks & Pitfalls - Setting `scene.fog` without also setting `scene.background` to the same color (or vice versa) creates a visible mismatch at the horizon where fogged geometry meets an unfogged background. - Forgetting that fog only affects *rendered* pixels — objects the fog should visually hide but that aren't drawn (e.g. because they're culled) aren't "extra hidden" by fog; fog is a per-pixel color blend, not an object-level visibility system. - Leaving `material.fog = true` (the default) on interior surfaces of an enclosed space (vehicle cockpit, house interior) that's larger than the fog's `near`/`far` range causes far walls to look incorrectly fogged from inside. - Using a flat-image `scene.background` without correcting `.repeat`/`.offset` for aspect ratio leaves the image visibly stretched. - Forgetting `alpha: true` on the renderer when relying on a CSS background — the canvas will opaquely paint over it. - Forgetting `side: THREE.BackSide` on a skybox cube/sphere — the inside faces will be invisible (the default renders only the outside). ## Related Concepts Backgrounds are built from the same [[concepts/textures|texture]] APIs used elsewhere, are affected by [[concepts/post-processing]] only when drawn by three.js rather than CSS, and skyboxes pair with [[concepts/controls]] for camera interaction. See also [[concepts/lighting]] for how HemisphereLight sky/ground colors relate conceptually to backgrounds, and [[concepts/threejs-overview]]. ## Sources - `raw/web_community-fog.md` — manual article: `Fog` vs `FogExp2`, the fog/background color-matching requirement, and the per-material `fog` boolean with the vehicle-cockpit/house-interior rationale. - `raw/web_community-backgrounds-and-skyboxes.md` — manual article: CSS vs three.js-drawn backgrounds and the `alpha: true` renderer flag, aspect-correcting a flat background texture, skybox cube/sphere with `BackSide`, `CubeTextureLoader` cubemaps, and equirectangular backgrounds via `EquirectangularReflectionMapping`. --- title: "Geometry Fundamentals" type: concept tags: [threejs, geometry, buffergeometry, attributes, mesh, intermediate, foundational] created: 2026-08-02 updated: 2026-08-02 sources: ["raw/web_community-buffergeometry-three-js-docs.md", "raw/web_community-fundamentals.md", "raw/web_community-cleanup.md"] confidence: high threejs_docs_snapshot: "2026-08-02" --- ## Definition `BufferGeometry` is the foundational representation of mesh, line, or point geometry in three.js. It stores vertex positions, face indices, normals, colors, UVs, and custom attributes in buffers designed to be handed to the GPU efficiently, rather than as loose per-vertex JavaScript objects. ## How It Works Three.js ships many built-in geometry primitives (`BoxGeometry`, `SphereGeometry`, `PlaneGeometry`, and others) for common shapes. For procedural or imported vertex data, build a custom `BufferGeometry` and attach data with `setAttribute()`. The official example below constructs a square from a `Float32Array`: `position` uses three components per vertex, and because the square is not indexed, the two shared corner vertices are duplicated once per triangle. ```js const geometry = new THREE.BufferGeometry(); // duplicate the top left and bottom right vertices because each // vertex needs to appear once per triangle const vertices = new Float32Array([ -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, ]); geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3)); const mesh = new THREE.Mesh(geometry, material); ``` **Attributes.** Attributes hold per-vertex data in GPU-bound buffers, accessed through `setAttribute()` and `getAttribute()` rather than by touching the internal `attributes` dictionary directly. `position` defines where each vertex sits; normals, colors, UVs, and custom data are additional named attributes. **Indexed triangles.** The optional `index` attribute lets vertices be reused across multiple triangles — each triangle references the indices of three vertices ("indexed triangles"). If no index is set, the renderer assumes every three contiguous positions form one triangle, forcing shared vertices to be duplicated as in the example above. Set the index with `setIndex()`: ```js geometry.setIndex([0, 1, 2, 2, 3, 0]); ``` **Normals and UVs.** Normals describe vertex orientation for lighting. `computeVertexNormals()` derives them from vertex data; for indexed geometry, each vertex normal becomes the average of the face normals of the faces sharing that vertex, while non-indexed geometry gets each vertex normal set equal to its own face normal. UV attributes carry texture coordinates that textured [[concepts/materials|materials]] map onto the surface. **Shared geometry, per-mesh transforms.** Because geometry holds shape data rather than placement, multiple meshes can reference the same immutable geometry (and material) while each mesh keeps its own transform: ```js const sharedGeometry = new THREE.BoxGeometry(); scene.add(new THREE.Mesh(sharedGeometry, materialA)); scene.add(new THREE.Mesh(sharedGeometry, materialB)); ``` Geometry-level methods such as `translate()`, `rotateX()`/`rotateY()`/`rotateZ()`, and `scale()` are documented as one-time operations for baking a transform into the vertex data — not calls to make every render loop. Prefer object `position`, `rotation`, and `scale` (i.e. `Object3D` transforms) for real-time motion. ## Key Parameters - `.attributes` — dictionary of named `BufferAttribute`/`InterleavedBufferAttribute` values; use `setAttribute()`/`getAttribute()` rather than direct access. - `.index` — optional `BufferAttribute` enabling indexed triangles; default `null` (non-indexed). - `.boundingBox` / `.boundingSphere` — computed via `computeBoundingBox()` / `computeBoundingSphere()`; not automatically kept in sync with vertex edits. - `.groups` — splits a geometry into per-material draw-call groups via `addGroup()`/`clearGroups()`; every vertex/index must belong to exactly one group. - `.morphAttributes` — holds morph targets; once rendered, morph attribute data cannot be changed in place and requires a new geometry instance. ## When To Use Use a built-in primitive whenever a standard shape suffices. Build a custom `BufferGeometry` when importing external vertex data or generating shapes procedurally. Use indexed triangles (`setIndex()`) whenever a mesh has shared vertices across faces, to reduce memory and upload size. Use one-time geometry methods (`translate()`, `rotateX()`, `scale()`) only for baking an initial transform, not for per-frame animation. ## Risks & Pitfalls - Calling geometry-level `translate()`/`rotate*()`/`scale()` inside a render loop is a documented anti-pattern — use `Object3D` transforms (`position`/`rotation`/`scale`) instead for real-time motion. - Forgetting to call `computeVertexNormals()` (or supplying no normals at all) leaves lighting-aware materials shaded incorrectly. - `boundingBox`/`boundingSphere` are `null` until explicitly computed, and are not automatically recomputed after vertex edits. - Like materials and textures, geometries own GPU-side resources and are **not** cleaned up by JavaScript garbage collection; call `dispose()` once a geometry is no longer needed, especially in long-running apps that load and unload assets. ## Related Concepts Place geometry on the [[concepts/scene-graph]] with a [[concepts/materials|material]], load prebuilt geometry with [[concepts/loading-3d-models]], and render it through the [[concepts/renderer]]. See also [[concepts/threejs-overview]]. ## Sources - `raw/web_community-buffergeometry-three-js-docs.md` — `BufferGeometry` API reference: attributes, index, groups, morph attributes, `computeVertexNormals()`, `dispose()`, and the one-time-operation methods (`translate`, `rotateX/Y/Z`, `scale`). - `raw/web_community-fundamentals.md` — introduces `Geometry` as vertex data shared across meshes and lists built-in primitives. - `raw/web_community-cleanup.md` — resource-lifetime rules: geometries, textures, and materials require explicit `dispose()` since the browser only frees them automatically on page close. --- title: "Getting Started with Three.js" type: concept tags: [threejs, installation, esm, webgl, beginner, foundational] created: 2026-08-02 updated: 2026-08-02 sources: ["raw/web_community-installation.md", "raw/web_community-creating-a-scene.md", "raw/web_community-fundamentals.md"] confidence: high threejs_docs_snapshot: "2026-08-02" --- ## Definition Getting started with three.js means setting up a project structure, installing the library through npm or a CDN import map, and assembling the minimal trio of objects — a `Scene`, a `Camera`, and a renderer — needed to draw a first frame. ## How It Works Every three.js project needs at least one HTML file and a JavaScript file. The official installation guide offers two paths: - **Option 1 — npm plus a build tool** (recommended for most projects): install Node.js, then `npm install --save three` and a build tool such as Vite (`npm install --save-dev vite`). Running `npx vite` serves the app locally with local-file and npm-package imports working out of the box, no import map required. Deploying runs a production build (e.g. `npx vite build`) into a `dist/` folder ready to host. - **Option 2 — import from a CDN**: no build tool is used, so `index.html` needs an [import map](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap) pointing the bare `three` specifier at a CDN URL for a specific version, plus a `three/addons/` entry if addons are used. This still requires a local server (`npx serve .` or similar) — opening the HTML file directly from the filesystem does not work because important browser features are blocked for security reasons on `file://` origins. Once installed, a minimal app connects a `Scene`, a `Camera`, and a renderer: the renderer draws the scene from the camera's view onto its canvas. [[concepts/scene-graph]], [[concepts/cameras]], and [[concepts/renderer]] expand each role in depth. ```js import * as THREE from 'three'; const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera(75, innerWidth / innerHeight, 0.1, 1000); const renderer = new THREE.WebGLRenderer(); renderer.setSize(innerWidth, innerHeight); document.body.appendChild(renderer.domElement); scene.add(new THREE.Mesh(new THREE.BoxGeometry(), new THREE.MeshBasicMaterial({ color: 0x44aa88 }))); camera.position.z = 5; renderer.setAnimationLoop(() => renderer.render(scene, camera)); ``` ## Key Parameters - **Module system**: as of r147, the preferred way to load three.js is via ES modules and import maps (`