three-low-poly 0.9.22 → 0.9.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +331 -9
- package/dist/index.cjs +396 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +1219 -281
- package/dist/index.iife.js +117 -13
- package/dist/index.iife.js.map +1 -1
- package/dist/index.mjs +6706 -0
- package/dist/index.mjs.map +1 -0
- package/dist/uv-grid.jpg +0 -0
- package/package.json +22 -20
- package/dist/index.cjs.js +0 -292
- package/dist/index.cjs.js.map +0 -1
- package/dist/index.es.js +0 -5240
- package/dist/index.es.js.map +0 -1
- package/dist/index.umd.js +0 -292
- package/dist/index.umd.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,20 +1,340 @@
|
|
|
1
1
|
# Three.js Low Poly
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Create or enhance stylized low-poly scenes entirely through code — procedurally generated geometries, prefabricated models, factory utilities, and atmospheric layers for [Three.js](https://threejs.org).
|
|
4
|
+
|
|
5
|
+
> **How to use this document** — Start here for intent, conventions, and direction. The [example gallery](https://jasonsturges.com/three-low-poly/) and TypeScript exports are the API reference; this file is the mental model. Written for humans first, structured so an AI collaborator can pick up full context from one read.
|
|
6
|
+
|
|
7
|
+
**Contents:** [What this is](#what-this-library-is) · [Mental model](#mental-model) · [Usage patterns](#usage-patterns) · [Conventions](#conventions-library-code) · [Current state](#current-state) · [Design patterns (target)](#design-patterns-target) · [Roadmap](#roadmap) · [Getting started](#getting-started)
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## What this library is
|
|
12
|
+
|
|
13
|
+
### Origin
|
|
14
|
+
|
|
15
|
+
An alternative to the Blender → export → load pipeline. Model in code via **procedural** and **parametric** geometry instead of external DCC tools. Splines, lathe, extrude, parabolic profiles — geometry as algorithms, not hand-authored meshes.
|
|
16
|
+
|
|
17
|
+
### Practical reality
|
|
18
|
+
|
|
19
|
+
Most adopters will import their own assets (glTF, etc.) and use this library as **scene enhancement** — blowing leaves, rain, lightning, effervescence in a jar, procedural fill on a shelf — not as a full replacement for modeling software. That is expected and supported.
|
|
20
|
+
|
|
21
|
+
There is still real **modeling capability** here: vertex-built geometry, prefab models, and factory assemblies are first-class. The library spans both worlds.
|
|
22
|
+
|
|
23
|
+
### Style
|
|
24
|
+
|
|
25
|
+
Generally low-poly and stylized, but “low poly” describes the aesthetic, not the whole thesis. The thesis is **code-first, parametric, performant scene building**.
|
|
26
|
+
|
|
27
|
+
### Performance
|
|
28
|
+
|
|
29
|
+
Exported assets often mean **one draw call per mesh**. This library favors **merged geometry, material groups, and instancing** so dense procedural scenes stay batch-friendly — a deliberate contrast to typical glTF import cost.
|
|
30
|
+
|
|
31
|
+
### Core principles
|
|
32
|
+
|
|
33
|
+
| Principle | Meaning |
|
|
34
|
+
|-----------|---------|
|
|
35
|
+
| **Procedural generation** | Geometry from algorithms, not imported meshes |
|
|
36
|
+
| **Parametric modeling** | Size, color, detail, and variation via options interfaces |
|
|
37
|
+
| **Prefabricated models** | Drop-in `Mesh` subclasses (trees, jars, books) ready for `scene.add()` |
|
|
38
|
+
| **Factory utilities** | Assemblies and fills (book rows, tile floors, walls) from one call |
|
|
39
|
+
| **Instanced layers** | Weather, scatter, and particles via `InstancedMesh` / `Points` |
|
|
40
|
+
| **Time-based animation** | `update(dt)` in seconds, not per-frame magic numbers |
|
|
41
|
+
| **Unique runtime, optional repeatability** | Stochastic variation by default; seeded reproducibility is roadmap (see below) |
|
|
4
42
|
|
|
5
43
|

|
|
6
44
|
_Example Library scene_
|
|
7
45
|
|
|
8
|
-
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Mental model
|
|
49
|
+
|
|
50
|
+
### Package layers (where code lives)
|
|
51
|
+
|
|
52
|
+
| Layer | Role | Examples |
|
|
53
|
+
|-------|------|----------|
|
|
54
|
+
| **Geometry** | Building blocks; prefer when mirroring Three.js patterns | `JarGeometry`, `TestTubeGeometry`, `BrickGeometry` |
|
|
55
|
+
| **Models (“prefabs”)** | Geometry + materials as ready-to-place objects | `Jar`, `Tree`, `TestTube`, `Mausoleum` |
|
|
56
|
+
| **Factories** | Composite assemblies and **fills** along extent | `rowOfBooksByCount`, `createHexagonalTilesByRadius` |
|
|
57
|
+
| **Environment** | Continuous scene- or region-scale atmosphere | `StarFieldEffect`, `RainEffect`, `LightningEffect`, `GroundFogEffect` |
|
|
58
|
+
| **Ambience** | Continuous layers, often volume- or prop-bound | `PetalDriftEffect`, `EffervescenceEffect`, `WispEffect`, `EmissivePulseEffect`, `FlameFlickerEffect`, `GlowHalo` |
|
|
59
|
+
| **FX** *(planned)* | Short-lived, event-triggered bursts | Dust on landing, spell flash, wind streak *(not in SDK yet)* |
|
|
60
|
+
| **Animators** | Camera choreography and paths | `cameraOrbitAnimation`, `cameraFlythroughAnimation` |
|
|
61
|
+
| **Utilities** | Math, easing, centering, RNG | `Easing`, `randomFloat`, `centerObject` |
|
|
62
|
+
|
|
63
|
+
**Model examples** showcase geometry. **Effect examples** showcase layers. **Scene examples** compose both (e.g. Mad Science: jar + effervescence).
|
|
64
|
+
|
|
65
|
+
### Visual layers — duration, scope, trigger
|
|
66
|
+
|
|
67
|
+
Use this frame when adding anything that moves, flickers, or spawns. **Preserve this taxonomy** when extending the library:
|
|
68
|
+
|
|
69
|
+
| Category | Duration | Scope | Trigger | Examples |
|
|
70
|
+
|----------|----------|-------|---------|----------|
|
|
71
|
+
| **VFX / FX** | Short, often one-shot | Local to an event | `play()`, `trigger()` | Dust on landing, spell flash, impact sparks |
|
|
72
|
+
| **Environment / weather** | Continuous | Scene or region | Always on (toggle optional) | Rain, fog, lightning, starfield |
|
|
73
|
+
| **Ambient detail** | Continuous | Volume or prop-adjacent | Scene setup | Petals in a yard, bubbles in a jar |
|
|
74
|
+
|
|
75
|
+
**Today:** Environment and ambience live under `src/effects/`. FX is roadmap-only; future FX will use `trigger()` + short lifetime, not only `update(dt)`.
|
|
76
|
+
|
|
77
|
+
| Export | Category | Notes |
|
|
78
|
+
|--------|----------|-------|
|
|
79
|
+
| `StarFieldEffect` | Environment | Sky dome; copy camera position each frame |
|
|
80
|
+
| `RainEffect` | Environment | Regional rainfall volume |
|
|
81
|
+
| `LightningEffect` | Environment | Drives `DirectionalLight`; expose `level` for fog/sky sync |
|
|
82
|
+
| `GroundFogEffect` | Environment | Drifting mist cards; interior + optional perimeter patches |
|
|
83
|
+
| `PetalDriftEffect` | Ambience | Scene volume or localized patch |
|
|
84
|
+
| `WispEffect` | Ambience | Drifting will-o'-the-wisps in a bounded volume |
|
|
85
|
+
| `EffervescenceEffect` | Ambience | Scale/position inside vessels; `spread` for round vessels |
|
|
86
|
+
| `EmissivePulseEffect` | Ambience | Drives `emissiveIntensity` on existing materials (fake LED); no geometry |
|
|
87
|
+
| `GlowHalo` | Ambience | Additive billboard glow; fake light without `PointLight` |
|
|
88
|
+
| `FlameFlickerEffect` | Ambience | Sine flicker driver for halo, flame material, optional real light |
|
|
89
|
+
|
|
90
|
+
### Modeling conventions
|
|
91
|
+
|
|
92
|
+
- Prefer **vertex modeling** in geometry classes; use **geometry groups** for multi-material meshes.
|
|
93
|
+
- Profile tools: splines, lathe, extrude, parabolic curves; NURBS is exploratory.
|
|
94
|
+
- Use **geometry classes** where Three.js would use `BufferGeometry` subclasses.
|
|
95
|
+
- Use **models** when the artifact is a stable prefab; use **factories** when the artifact is an assembly or a fill along extent.
|
|
96
|
+
|
|
97
|
+
### Glass and transparent contents
|
|
98
|
+
|
|
99
|
+
Transparent glass + liquid + instanced contents are a recurring pattern:
|
|
100
|
+
|
|
101
|
+
- Glass and liquid: `transparent: true`, `depthWrite: false`, `side: DoubleSide`
|
|
102
|
+
- Draw order: contents → liquid (`renderOrder` 1) → glass (`renderOrder` 2)
|
|
103
|
+
- See `TestTubeRack`, effervescence example, and mad-science scene patterns
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Usage patterns
|
|
108
|
+
|
|
109
|
+
### Drop-in model
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
import { MossyRocks } from "three-low-poly";
|
|
113
|
+
|
|
114
|
+
const rocks = new MossyRocks();
|
|
115
|
+
scene.add(rocks);
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Environment layer
|
|
119
|
+
|
|
120
|
+
```ts
|
|
121
|
+
import { RainEffect } from "three-low-poly";
|
|
122
|
+
|
|
123
|
+
const rain = new RainEffect({ area: 12, height: 16, intensity: 0.45 });
|
|
124
|
+
scene.add(rain);
|
|
125
|
+
|
|
126
|
+
function animate(dt: number) {
|
|
127
|
+
rain.update(dt);
|
|
128
|
+
renderer.render(scene, camera);
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Lightning + synced atmosphere
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
const bolt = new DirectionalLight(0xcdd8ff, 0);
|
|
136
|
+
bolt.position.set(5, 12, -8);
|
|
137
|
+
bolt.target.position.set(0, 2, 0);
|
|
138
|
+
scene.add(bolt, bolt.target);
|
|
139
|
+
|
|
140
|
+
const storm = new LightningEffect({ light: bolt, peak: 12, minGap: 3, maxGap: 9 });
|
|
141
|
+
|
|
142
|
+
function animate(dt: number) {
|
|
143
|
+
storm.update(dt);
|
|
144
|
+
const flash = storm.level; // lerp fog, sky, emissive windows, rain intensity…
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Ambience inside a prop
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
const fizz = new EffervescenceEffect({ width: 1.2, height: 1.45, spread: 0.88 });
|
|
152
|
+
fizz.position.set(0, 0.95, 0); // inside jar / flask volume
|
|
153
|
+
scene.add(fizz);
|
|
154
|
+
onFrame((dt) => fizz.update(dt));
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Star field sky dome
|
|
158
|
+
|
|
159
|
+
```ts
|
|
160
|
+
const stars = new StarFieldEffect({ style: "burst", radius: 480, twinkle: true });
|
|
161
|
+
scene.add(stars); // not parented to camera
|
|
162
|
+
|
|
163
|
+
onFrame(() => {
|
|
164
|
+
stars.position.copy(camera.position);
|
|
165
|
+
stars.update();
|
|
166
|
+
});
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## Conventions (library code)
|
|
172
|
+
|
|
173
|
+
| Topic | Convention |
|
|
174
|
+
|-------|------------|
|
|
175
|
+
| **Options** | `ThingOptions` interface; JSDoc on every option with defaults; export options types from `src/index.ts` |
|
|
176
|
+
| **Classes** | Class-level JSDoc + `@example` for public effects and major models |
|
|
177
|
+
| **Animation** | `update(dt: number)` — elapsed seconds |
|
|
178
|
+
| **Disposal** | `dispose()` when owning geometry, materials, or textures |
|
|
179
|
+
| **Instancing** | `DynamicDrawUsage`, reusable `Object3D` dummy, `Float32Array` state where hot |
|
|
180
|
+
| **Examples** | Every feature has a corresponding file under `app/examples/`; auto-discovered by the host gallery |
|
|
181
|
+
| **Documentation** | Parameter docs + minimal setup snippet in JSDoc — enough to wire without reading source |
|
|
182
|
+
| **Randomness** | Unique per runtime today via `Math.random()`; seeded reproducibility is planned |
|
|
9
183
|
|
|
10
|
-
|
|
184
|
+
**Particles in Three.js:** No built-in particle engine. Use `Points` + `PointsMaterial` for lightweight sprites, or `InstancedMesh` for streaks, bubbles, and petals. Choice is rendering strategy, not the environment/FX taxonomy.
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## Current state
|
|
189
|
+
|
|
190
|
+
What exists today and how mature each area is.
|
|
191
|
+
|
|
192
|
+
| Area | Status |
|
|
193
|
+
|------|--------|
|
|
194
|
+
| **Models & geometry** | Broad catalog; vertex-first, grouped materials |
|
|
195
|
+
| **Factories** | Book row, hex tiles, brick wall — ad hoc `...ByCount` / `...ByRadius` APIs |
|
|
196
|
+
| **Environment effects** | Star field, rain, lightning, ground fog |
|
|
197
|
+
| **Ambience effects** | Petal drift, effervescence, wisp, emissive pulse, glow halo, flame flicker |
|
|
198
|
+
| **FX (burst / triggered)** | **Not implemented** |
|
|
199
|
+
| **Animators** | Camera paths, light flicker, emissive pulse |
|
|
200
|
+
| **Host gallery** | `app/examples/` — models, effects, scenes, reference |
|
|
201
|
+
| **RNG** | `RandomNumberUtils` on bare `Math.random()` — **no seed in `src` today** |
|
|
202
|
+
| **WebGPU / TSL** | Not yet; target for shader portability |
|
|
203
|
+
|
|
204
|
+
### Modeling (today)
|
|
205
|
+
|
|
206
|
+
- Vertex-first geometry with **groups** for different materials
|
|
207
|
+
- Profile primitives: spline, parabolic, lathe, extrude; NURBS exploratory
|
|
208
|
+
- Geometry classes mirror Three.js `BufferGeometry` subclass patterns where possible
|
|
209
|
+
|
|
210
|
+
### Prefabs & instancing
|
|
211
|
+
|
|
212
|
+
- **Prefabs** — prebuilt `Mesh` objects (`Jar`, `Tree`, `Mausoleum`, …)
|
|
213
|
+
- **Instanced meshes** — tiles, books, particles, weather layers
|
|
214
|
+
|
|
215
|
+
### Performance (today)
|
|
216
|
+
|
|
217
|
+
- Merged geometry and instancing where factories and effects allow
|
|
218
|
+
- Batching audit and guidelines still informal — opportunity on roadmap
|
|
219
|
+
|
|
220
|
+
### Object options pattern
|
|
221
|
+
|
|
222
|
+
Public APIs expose `ThingOptions` interfaces (exported alongside classes). Defaults live in destructuring; JSDoc documents each field. This is the standard extension point — no positional-arg sprawl.
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## Design patterns (target)
|
|
227
|
+
|
|
228
|
+
Two recurring design problems appear across factories and effects. The roadmap is to name them once and apply them everywhere — the difference between a library that feels **designed** and one that feels **accreted**.
|
|
229
|
+
|
|
230
|
+
### 1. Factory `fit` — constraint solving, not bespoke APIs
|
|
231
|
+
|
|
232
|
+
Many factories are the **same operation under different pinned variables**. One invariant equation hides in each:
|
|
233
|
+
|
|
234
|
+
```
|
|
235
|
+
extent ≈ count × itemSize + gaps
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
Three coupled variables — `extent`, `count`, `itemSize` — and a factory is just **pin two, solve for the third**:
|
|
239
|
+
|
|
240
|
+
| Use case | Pinned | Solved |
|
|
241
|
+
|----------|--------|--------|
|
|
242
|
+
| “12 books on a 1-ft shelf” | count + extent | itemSize |
|
|
243
|
+
| “1-inch books filling 1 ft” | itemSize + extent | count |
|
|
244
|
+
| Hex tiles by-count vs by-radius | (either pair) | the third |
|
|
245
|
+
| Fence by-path vs by-segment | (either pair) | the third |
|
|
246
|
+
|
|
247
|
+
This is **constraint solving** — the same problem CSS flexbox, table layout, and bin-packing wrestle with. It only *feels* bespoke because each factory was written from scratch. It isn't; it's one template with a chosen pin. Existing `createHexagonalTilesByCount` / `createHexagonalTilesByRadius` and `rowOfBooksByCount` / `rowOfBooksByLength` are this pattern, discovered ad hoc.
|
|
248
|
+
|
|
249
|
+
**Direction:** one factory per subject, discriminated `fit` union — replaces `...ByCount` / `...ByRadius` proliferation:
|
|
250
|
+
|
|
251
|
+
```ts
|
|
252
|
+
type Fit =
|
|
253
|
+
| { by: "count"; count: number } // pin count
|
|
254
|
+
| { by: "size"; size: number } // pin item size
|
|
255
|
+
| { by: "pack"; gap?: number } // greedy: as many as fit
|
|
256
|
+
| { by: "pack-random"; sizeRange: [number, number]; seed?: number }; // stochastic fill
|
|
257
|
+
|
|
258
|
+
createTileFloor({ width, depth, fit: { by: "count", count: 24 } });
|
|
259
|
+
createBookRow({ length: 12, fit: { by: "pack-random", sizeRange: [0.8, 1.4], seed: 7 } });
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
Why this over named-per-pin functions:
|
|
263
|
+
|
|
264
|
+
- One import, one mental model, TypeScript exhaustiveness checking
|
|
265
|
+
- **Randomness has a natural home** — random packing is a *fill strategy*, not a pinned variable; `fit` makes deterministic and stochastic fills peers
|
|
266
|
+
|
|
267
|
+
**Goal:** share the same `fit` vocabulary across every fill-factory — books, fences, tiles, whatever's next.
|
|
268
|
+
|
|
269
|
+
**Limits:** staggered / 2D packings (hex tiles are offset-stacked) need their own placement solver. The shared `fit` vocabulary targets **most 1D fills and simple grids**, not a universal packer.
|
|
270
|
+
|
|
271
|
+
Emphasize **factories for assemblies** (racks, shelves, fences) over one-off geometry. Open design: `TestTube` vs liquid fill vs `TestTubeRack` as factory.
|
|
272
|
+
|
|
273
|
+
### 2. Seeded randomness — unique runtime, reproducible on demand
|
|
274
|
+
|
|
275
|
+
Randomness is a **major** part of this library: unique experiences each runtime (randomly-sized packed books, scatter variation, stochastic fills). But repeatability matters too — debug a scene, share a seed, get the same shelf every reload.
|
|
276
|
+
|
|
277
|
+
**Today:** `src/utils/RandomNumberUtils.ts` (`randomFloat`, `randomInteger`, `logarithmicRandomMax`, `logarithmicRandomMin`) all sit on bare `Math.random()`. This is a **from-scratch migration**, not finishing what's started.
|
|
278
|
+
|
|
279
|
+
**Direction:**
|
|
280
|
+
|
|
281
|
+
1. Small fast seedable PRNG (`mulberry32` / `splitmix32`) → `() => number` stream from a seed
|
|
282
|
+
2. Re-express `RandomNumberUtils` to draw from an injected RNG stream (default = unseeded, existing call sites keep working)
|
|
283
|
+
3. Thread optional `seed` through every stochastic factory and effect (`pack-random`, scatter, variation, …)
|
|
284
|
+
4. Reproducibility goal: same options + same seed ⇒ byte-identical scene graph
|
|
285
|
+
|
|
286
|
+
Default = fresh randomness each run. Pass `seed` to reproduce.
|
|
287
|
+
|
|
288
|
+
---
|
|
289
|
+
|
|
290
|
+
## Roadmap
|
|
291
|
+
|
|
292
|
+
Priorities and direction — not a commitment schedule.
|
|
293
|
+
|
|
294
|
+
### Atmosphere & content
|
|
295
|
+
|
|
296
|
+
- More **environment** layers (fog drivers, ground mist, wind fields)
|
|
297
|
+
- More **ambience** (leaves on terrain, localized scatter)
|
|
298
|
+
- **FX** module: short-lived bursts, `trigger()`, pools, fade-out
|
|
299
|
+
- Example `meta.category` tags (`environment` | `ambience` | `fx`) for gallery clarity
|
|
300
|
+
- Optional folder split: `environment/` / `ambience/` / `fx/` when FX lands
|
|
301
|
+
|
|
302
|
+
### Randomness & reproducibility
|
|
303
|
+
|
|
304
|
+
See [Seeded randomness](#2-seeded-randomness--unique-runtime-reproducible-on-demand) above. Highest-leverage migration in the random story.
|
|
305
|
+
|
|
306
|
+
### Factories
|
|
307
|
+
|
|
308
|
+
- Unified `fit` discriminant across book, tile, fence, and future fill factories
|
|
309
|
+
- More assembly factories (racks, shelves, composite props)
|
|
310
|
+
- Constraint-solving template instead of one-off `...ByX` functions
|
|
311
|
+
|
|
312
|
+
### Rendering & platform
|
|
313
|
+
|
|
314
|
+
- **WebGPU** with **TSL** shaders where possible — WebGL + WebGPU compatibility from one shader source
|
|
315
|
+
- Glassware material pass (`DoubleSide`, `depthWrite`, `renderOrder`) across bottles and science glass
|
|
316
|
+
- Batching audit: merge opportunities, instancing guidelines
|
|
317
|
+
|
|
318
|
+
### Geometry & scenes (exploratory)
|
|
319
|
+
|
|
320
|
+
- Diorama / room shells with windows (geometry exists; not yet library-ready)
|
|
321
|
+
- Leaded lattice windows, terrain, water
|
|
322
|
+
- NURBS / advanced profiles where they earn their complexity
|
|
323
|
+
|
|
324
|
+
### Documentation
|
|
325
|
+
|
|
326
|
+
- This README as single source of truth — no separate `docs/` folder
|
|
327
|
+
- Per-class JSDoc remains the API contract
|
|
328
|
+
- Examples remain living documentation
|
|
329
|
+
|
|
330
|
+
---
|
|
331
|
+
|
|
332
|
+
## Getting started
|
|
11
333
|
|
|
12
334
|
```shell
|
|
13
335
|
npm i three-low-poly
|
|
14
336
|
```
|
|
15
337
|
|
|
16
|
-
Then, import into a project and use as:
|
|
17
|
-
|
|
18
338
|
```js
|
|
19
339
|
import { MossyRocks } from "three-low-poly";
|
|
20
340
|
|
|
@@ -22,13 +342,15 @@ const rocks = new MossyRocks();
|
|
|
22
342
|
scene.add(rocks);
|
|
23
343
|
```
|
|
24
344
|
|
|
25
|
-
|
|
345
|
+
**Examples:** [jasonsturges.com/three-low-poly/](https://jasonsturges.com/three-low-poly/) — browse by category in the host gallery. Local dev: `npm run host`.
|
|
346
|
+
|
|
347
|
+
**Build:** Library publishes from `dist/`; examples live in `app/` and import `three-low-poly` like a consumer would.
|
|
26
348
|
|
|
27
349
|

|
|
28
350
|
_Example Graveyard scene_
|
|
29
351
|
|
|
30
|
-
|
|
352
|
+
---
|
|
31
353
|
|
|
32
|
-
|
|
354
|
+
## Author
|
|
33
355
|
|
|
34
|
-
|
|
356
|
+
Jason Sturges — procedural low-poly tooling for Three.js.
|