@origingame/engine 0.3.0 → 0.4.0
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/dist/web/origin-engine.d.ts +38 -2
- package/dist/web/origin-engine.js +250 -10
- package/dist/web/origin-engine_bg.wasm +0 -0
- package/dist/web/origin-engine_bg.wasm.d.ts +14 -2
- package/dist/web-publish/origin-engine-lanes.js +255 -34
- package/dist/web-publish/origin-engine-lanes_bg.wasm +0 -0
- package/dist/web-publish/origin-engine.d.ts +39 -3
- package/dist/web-publish/origin-engine.js +253 -32
- package/dist/web-publish/origin-engine_bg.wasm +0 -0
- package/dist/web-publish/origin-engine_bg.wasm.d.ts +15 -3
- package/dist/web-publish-2d/origin-engine-lanes.js +253 -32
- package/dist/web-publish-2d/origin-engine-lanes_bg.wasm +0 -0
- package/dist/web-publish-2d/origin-engine.d.ts +38 -2
- package/dist/web-publish-2d/origin-engine.js +250 -29
- package/dist/web-publish-2d/origin-engine_bg.wasm +0 -0
- package/dist/web-publish-2d/origin-engine_bg.wasm.d.ts +14 -2
- package/knowledge/README.md +2 -1
- package/knowledge/guides/three-to-og.md +393 -0
- package/knowledge/knowledge.json +2 -1
- package/knowledge/package.json +3 -2
- package/knowledge/scaffold/origin-engine.json +2 -2
- package/knowledge/scaffold/template/package.json +1 -1
- package/knowledge/scaffold/template/project.ogt +1 -1
- package/knowledge/scripts/validate.ts +140 -21
- package/knowledge/skills/og-audio/SKILL.md +2 -2
- package/knowledge/skills/og-build/SKILL.md +22 -3
- package/knowledge/skills/og-core/SKILL.md +20 -5
- package/knowledge/skills/og-feel/SKILL.md +2 -2
- package/knowledge/skills/og-game/SKILL.md +481 -35
- package/knowledge/skills/og-i18n/SKILL.md +7 -7
- package/knowledge/skills/og-model/SKILL.md +374 -0
- package/knowledge/skills/og-platform-sdk/SKILL.md +1 -1
- package/knowledge/skills/og-ui/SKILL.md +15 -8
- package/knowledge/wiki/ai.md +20 -20
- package/knowledge/wiki/anim.md +63 -55
- package/knowledge/wiki/atmosphere.md +13 -13
- package/knowledge/wiki/audio.md +18 -18
- package/knowledge/wiki/camera.md +13 -13
- package/knowledge/wiki/commands.md +11 -11
- package/knowledge/wiki/debug.md +13 -13
- package/knowledge/wiki/game.md +8 -8
- package/knowledge/wiki/i18n.md +7 -7
- package/knowledge/wiki/index.md +57 -3
- package/knowledge/wiki/input.md +47 -47
- package/knowledge/wiki/load.md +57 -57
- package/knowledge/wiki/nav.md +34 -34
- package/knowledge/wiki/net.md +10 -10
- package/knowledge/wiki/path.md +14 -14
- package/knowledge/wiki/physics.md +95 -95
- package/knowledge/wiki/platform.md +44 -44
- package/knowledge/wiki/probe.md +86 -86
- package/knowledge/wiki/reflect.md +16 -4
- package/knowledge/wiki/render.md +1168 -170
- package/knowledge/wiki/rng.md +14 -14
- package/knowledge/wiki/shapes.md +727 -0
- package/knowledge/wiki/stream.md +15 -15
- package/knowledge/wiki/system.md +8 -8
- package/knowledge/wiki/systems.md +2 -2
- package/knowledge/wiki/terrain.md +24 -20
- package/knowledge/wiki/tilemap.md +13 -13
- package/knowledge/wiki/time.md +4 -4
- package/knowledge/wiki/timeline.md +14 -14
- package/knowledge/wiki/transform.md +8 -8
- package/knowledge/wiki/tween.md +17 -17
- package/knowledge/wiki/ui.md +245 -269
- package/knowledge/wiki/video.md +5 -5
- package/knowledge/wiki/world.md +36 -36
- package/package.json +4 -4
- package/schema/api.schema.json +1834 -305
- package/shell/platform.ts +5 -0
- package/shell/player.ts +8 -2
- package/shell/transport.ts +6 -0
- package/src/generated/abi.ts +37 -1
- package/src/geom.ts +260 -0
- package/src/index.ts +8 -1
- package/src/node/playtest-run.ts +1 -0
- package/src/platform-local.ts +2 -0
- package/src/playtest.ts +8 -0
- package/src/runtime.ts +87 -6
- package/src/ui-kit/settings.ts +9 -0
- package/src/web/shell.ts +1 -1
- package/src/web/worker.ts +2 -2
- package/types/bindings.json +697 -402
- package/types/index.d.ts +1045 -127
|
@@ -116,6 +116,7 @@ Mistakes the games made, or would have, before reading the right page:
|
|
|
116
116
|
| **og-feel** | how much: hit stop, shake, squash, easing, floating text, the camera, frame rates, sorting, parallax, controller tunables | time, tween, camera, systems |
|
|
117
117
|
| **og-ui** | screens and HUDs: templates, widgets, focus, phones, UI styles and motion | ui |
|
|
118
118
|
| **og-taste** | the look: a style from the premise, composition, colour, type, motion, feedback, atmosphere by intent, the done checklist | — (it uses ui and atmosphere) |
|
|
119
|
+
| **og-model** | a 3D model built as code from a reference image: the detail inventory, eight gated passes, the generators' recipes (§18 has their fields), budgets, the review frames and `og compare` | — (it uses render and shapes) |
|
|
119
120
|
| **og-ai** | enemies and NPCs: navigation and minds as data | nav, ai |
|
|
120
121
|
| **og-audio** | sound: events, presets, UI sounds, the mix, music, space | audio |
|
|
121
122
|
| **og-i18n** | languages: string tables, messages, fonts, line breaking, right to left | i18n |
|
|
@@ -155,7 +156,14 @@ beside the rebuild: the reload still happens, the `reload` event carries a
|
|
|
155
156
|
and a `check` event with the diagnostics follows; `og test --json` ends
|
|
156
157
|
with a `test` event whose `check` object has the same three. Read the
|
|
157
158
|
diagnostics and fix them before anything else; `--no-check` skips the
|
|
158
|
-
check (never for `og build --publish`). A
|
|
159
|
+
check (never for `og build --publish`). A `2d` project's publish build
|
|
160
|
+
leaves the 3D world out (terrain, planar water, scattered copies, the 3D
|
|
161
|
+
fluids, volumetric fog: `og.render.capabilities(world).world3d` is false
|
|
162
|
+
there), so `og build --publish` refuses one whose scenes hold `Terrain`,
|
|
163
|
+
`TerrainScatter`, `Water`, `WaterSurface` or `Fluid3D`, naming each
|
|
164
|
+
`scene.ogt:line`, and there `og.terrain.*` and a `SHAPE_HEIGHTFIELD`
|
|
165
|
+
collider answer a refusal naming `world3d`: remove them, or make the
|
|
166
|
+
project `profile "3d"`. A created project's
|
|
159
167
|
`tsconfig.json` resolves `@origingame/engine` (the generated
|
|
160
168
|
`types/index.d.ts`) and `@origingame/engine/playtest` from `node_modules`.
|
|
161
169
|
An example inside the engine repository has no `node_modules`: its
|
|
@@ -280,9 +288,13 @@ registered schema and refuses a model path that does not exist.
|
|
|
280
288
|
A `.vox` with frames (MagicaVoxel's animation) cooks to clips that swap
|
|
281
289
|
the frames' models: play them as skinned clips (§9). `voxFps 8` sets the
|
|
282
290
|
rate (default 10), `voxClip walk 0 3` names frames 0 to 3 (repeatable;
|
|
283
|
-
without it one clip `frames` holds
|
|
291
|
+
without it one clip `frames` holds the playback range set in the editor,
|
|
292
|
+
else every frame; a node marked to loop repeats its keys over the file's
|
|
293
|
+
frames). Each frame is centred on
|
|
284
294
|
its own pivot, as in the editor: give the frames one height (or pad them)
|
|
285
295
|
for a character whose feet stay on the ground.
|
|
296
|
+
- An `.ogt` of `type model` is a model written as text: og-geom parts by
|
|
297
|
+
their `og.render` names, placed, with materials and pivots (§18).
|
|
286
298
|
- Reusable production assets come through the platform's asset catalog into
|
|
287
299
|
`assets/`; record each file's licence next to it.
|
|
288
300
|
|
|
@@ -380,7 +392,13 @@ else ignores it. The stamp is world state, so a replay reproduces it.
|
|
|
380
392
|
`flipX`, `flash`, `shadow`, nine-slice `sliceX`/`sliceY`) is drawn every
|
|
381
393
|
frame at its transform, its scale multiplying the size (so squash and
|
|
382
394
|
stretch is a tween of `og.Transform.scale`). `og.render.sprite` stays for
|
|
383
|
-
one-tick, immediate drawing (HUDs, debug).
|
|
395
|
+
one-tick, immediate drawing (HUDs, debug). Sprites and og.ui's frames
|
|
396
|
+
are filtered anisotropically where the device can
|
|
397
|
+
(`og.render.capabilities(world).spriteAnisotropy`: 16, or 1 on a WebGL2
|
|
398
|
+
without `EXT_texture_filter_anisotropic` and on a software rasterizer), so a sprite or a nine-slice
|
|
399
|
+
squeezed along one axis keeps the other axis's detail (a button's
|
|
400
|
+
outline stays sharp); at 1 it blurs, and og.ui bounds a frame's middle
|
|
401
|
+
at twice its art for that reason.
|
|
384
402
|
- **Pixel sprites in a 3D set** stand on the ground with `og.Sprite.dropShadow`
|
|
385
403
|
(or `SpriteDesc.dropShadow`): 0.5 casts the sprite's shape, darkened and
|
|
386
404
|
flattened onto the ground plane (y 0) along the sun, the first
|
|
@@ -980,7 +998,9 @@ pixels then, per bone, `bone x y weight` in that bone's space (weights
|
|
|
980
998
|
summing to 1), or plain `x y` in the slot's bone. A bone's or region's
|
|
981
999
|
`skew` turns its y axis that many degrees past its x axis. A slot draws
|
|
982
1000
|
`texel × color + offset`. Bone keys add to the setup pose (`rotate` and
|
|
983
|
-
`skew` degrees, `translate` pixels, `scale` multiplies);
|
|
1001
|
+
`skew` degrees, `translate` pixels, `scale` multiplies); a `rotate` key
|
|
1002
|
+
turns the shorter way to the next, or `rotate 0 0 clockwise 1` (or
|
|
1003
|
+
`counterclockwise n`) that way through n more whole turns; every key eases
|
|
984
1004
|
linearly to the next, holds with `step`, or follows `curve x1 y1 x2 y2`
|
|
985
1005
|
(a cubic Bézier from 0,0 to 1,1, x time and y value; more segments as
|
|
986
1006
|
`x y x1 y1 x2 y2`). A `deform` key offsets every influence in order, one
|
|
@@ -988,15 +1008,26 @@ linearly to the next, holds with `step`, or follows `curve x1 y1 x2 y2`
|
|
|
988
1008
|
then (alone, the file's order); an `ik` key sets the constraint's weight
|
|
989
1009
|
and bend. An `ik`'s `bones` are a chain of any length, root first: one
|
|
990
1010
|
bone points, two bend at the joint, three or more (a tail, a tentacle, a
|
|
991
|
-
three-joint leg) are solved by FABRIK and curl to the `bend` side.
|
|
1011
|
+
three-joint leg) are solved by FABRIK and curl to the `bend` side. After the IK, a
|
|
1012
|
+
`transform t { bones a; target b; mix 1 1 1 1 }` pulls bones towards
|
|
1013
|
+
another bone's world rotation, origin, scale and shear by its mix, and an
|
|
1014
|
+
`along s { path rail; bones s1 s2; position 0 percent; spacing 0 length;
|
|
1015
|
+
rotate tangent 0; mix 1 1 }` lays bones along a `path` attachment (a
|
|
1016
|
+
cubic spline, `vertex x y` three per knot, drawn as nothing) while its
|
|
1017
|
+
slot shows it. A `skin armor { swap torso torso-armor; swap hat none }`
|
|
1018
|
+
block shows other attachments of the same slots wherever the default ones
|
|
1019
|
+
would show; `og.Skeleton2D.skin` picks it (`rig.skins.indexOf("armor")`,
|
|
1020
|
+
`default` is 0). A `box` draws nothing: `og.anim.skeleton2dBoxes(world, hero)`
|
|
992
1021
|
answers its polygon (in the Transform's frame) while its slot shows it,
|
|
993
1022
|
for hit and hurt boxes a clip switches. A `child` shows an `armature`
|
|
994
1023
|
block (a rig of its own on the same texture) in its slot; it plays the
|
|
995
1024
|
parent's clip by name when it has one, else its `clip`, at the parent's
|
|
996
|
-
time
|
|
1025
|
+
time; its events arrive as og.Skeleton2DEvent with `armature` its name
|
|
1026
|
+
(empty for the skeleton's own clip). A DragonBones 5.5 export is imported instead of written: a rig2d
|
|
997
1027
|
`.ogt` with `dragonbones "hero_ske.json"` and `atlas "hero_tex.json"`
|
|
998
1028
|
(skew, colour offsets, zOrder and IK timelines, armature displays,
|
|
999
|
-
bounding boxes
|
|
1029
|
+
bounding boxes, path displays and constraints, every skin, curves and `clockwise`
|
|
1030
|
+
turns included; Spine's files are not read, convert
|
|
1000
1031
|
them to this text).
|
|
1001
1032
|
|
|
1002
1033
|
```ts
|
|
@@ -1369,8 +1400,10 @@ render sprite 12
|
|
|
1369
1400
|
`underwaterDensity` and the surface from below shows the sky only
|
|
1370
1401
|
straight up (on by default; set the density to 0 to see through).
|
|
1371
1402
|
|
|
1372
|
-
**Terrain** (`reference/terrain.md
|
|
1373
|
-
|
|
1403
|
+
**Terrain** (`reference/terrain.md`, 3D projects only: a `2d` project's
|
|
1404
|
+
publish build has none, §2) is a height field cooked from a
|
|
1405
|
+
`type terrain` .ogt beside a 16-bit grey PNG (or an EXR in metres), or
|
|
1406
|
+
generated by the cook (below):
|
|
1374
1407
|
|
|
1375
1408
|
```text
|
|
1376
1409
|
type terrain
|
|
@@ -1381,9 +1414,23 @@ height -20 120 # metres
|
|
|
1381
1414
|
size 2048 2048 # metres along x and z, centred on the entity
|
|
1382
1415
|
control "island-control.png" # optional RGBA: layer 0 in R, 1 in G, 2 in B, 3 in A
|
|
1383
1416
|
heightBlend 0.15 # sharpen the blends by each albedo's alpha (its height)
|
|
1384
|
-
layer {
|
|
1385
|
-
|
|
1386
|
-
|
|
1417
|
+
layer { # a block's '}' stands alone on its line
|
|
1418
|
+
albedo "textures/grass.png"
|
|
1419
|
+
normal "textures/grass-n.png"
|
|
1420
|
+
tile 6
|
|
1421
|
+
slope 0 30
|
|
1422
|
+
}
|
|
1423
|
+
layer {
|
|
1424
|
+
albedo "textures/rock.png"
|
|
1425
|
+
tile 12
|
|
1426
|
+
triplanar true
|
|
1427
|
+
slope 28 90
|
|
1428
|
+
}
|
|
1429
|
+
layer {
|
|
1430
|
+
albedo "textures/snow.png"
|
|
1431
|
+
altitude 90 1000
|
|
1432
|
+
altitudeFade 10
|
|
1433
|
+
}
|
|
1387
1434
|
```
|
|
1388
1435
|
|
|
1389
1436
|
A layer shows where its control channel (1 without a map) times its slope
|
|
@@ -1398,6 +1445,151 @@ world.insert(ground, og.Terrain, { data: info.data });
|
|
|
1398
1445
|
world.insert(ground, og.Collider, { shape: SHAPE_HEIGHTFIELD, mesh: info.geometry });
|
|
1399
1446
|
```
|
|
1400
1447
|
|
|
1448
|
+
**A generated terrain.** Instead of `heightmap`, a `generate` block makes
|
|
1449
|
+
the field in the cook (never both: the cook refuses the pair and names
|
|
1450
|
+
the lines). `height` and `size` mean what they mean for a heightmap: the
|
|
1451
|
+
field is stretched so its lowest sample is `height`'s low and its highest
|
|
1452
|
+
its high, and no sample leaves that range. Every line, with its default
|
|
1453
|
+
(leave out what you do not need; erosion, thermal, terraces, rivers and
|
|
1454
|
+
the sea are off until given):
|
|
1455
|
+
|
|
1456
|
+
```text
|
|
1457
|
+
type terrain
|
|
1458
|
+
version 1
|
|
1459
|
+
---
|
|
1460
|
+
height -40 160 # metres
|
|
1461
|
+
size 1024 1024 # metres along x and z
|
|
1462
|
+
generate {
|
|
1463
|
+
samples 257 257 # columns and rows (2 to 4097)
|
|
1464
|
+
seed 1 # another seed, another terrain of the same kind
|
|
1465
|
+
noise {
|
|
1466
|
+
octaves 6 # 1 to 12: more is finer detail
|
|
1467
|
+
frequency 3 # features across the longer side
|
|
1468
|
+
lacunarity 2 # each octave's frequency over the last's (1 to 8)
|
|
1469
|
+
gain 0.5 # each octave's amplitude over the last's (0 to 1): higher is rougher
|
|
1470
|
+
warp 0 # domain warp in features: 0.3 to 1 bends ridges and coasts
|
|
1471
|
+
}
|
|
1472
|
+
mask island 0.4 # land fades to `height`'s low over this share of the half size
|
|
1473
|
+
# or `mask ridge 1`: sharp ridged mountains (0 to 1); default no mask
|
|
1474
|
+
erosion { # hydraulic erosion: seeded drops carve gullies and fill valleys
|
|
1475
|
+
drops 40000 # ~0.5 to 1 per sample; more is deeper erosion and a slower cook
|
|
1476
|
+
lifetime 30
|
|
1477
|
+
radius 3 # samples each drop erodes around it
|
|
1478
|
+
inertia 0.05
|
|
1479
|
+
capacity 4
|
|
1480
|
+
deposition 0.3
|
|
1481
|
+
erosion 0.3
|
|
1482
|
+
evaporation 0.01
|
|
1483
|
+
gravity 4
|
|
1484
|
+
}
|
|
1485
|
+
thermal { # slopes steeper than talus slump into scree
|
|
1486
|
+
talus 35 # degrees
|
|
1487
|
+
iterations 20
|
|
1488
|
+
rate 0.5
|
|
1489
|
+
}
|
|
1490
|
+
terraces {
|
|
1491
|
+
step 10 # metres between steps
|
|
1492
|
+
blend 0.4 # 0 hard steps, 1 smooth ramps
|
|
1493
|
+
}
|
|
1494
|
+
sea 0 # metres above the entity: og.terrain.load's seaLevel
|
|
1495
|
+
shore 2 # metres either side of the sea flattened into beaches (needs sea)
|
|
1496
|
+
rivers { # carved where the flow gathers, down to the sea or the edge
|
|
1497
|
+
threshold 400 # samples draining through before it is a river: lower, more rivers
|
|
1498
|
+
depth 2 # metres
|
|
1499
|
+
width 6 # metres
|
|
1500
|
+
}
|
|
1501
|
+
moisture { # what biomes read, 0 to 1
|
|
1502
|
+
flow 1 # weight of the gathered flow (wet in valleys and by rivers)
|
|
1503
|
+
scale 64 # samples draining through for half of it
|
|
1504
|
+
noise 0.5 # weight of a noise
|
|
1505
|
+
frequency 6
|
|
1506
|
+
}
|
|
1507
|
+
biome { # any number; each writes its layer's control channel
|
|
1508
|
+
layer 0 # required: the layer (0 to 3, one the terrain has)
|
|
1509
|
+
weight 1
|
|
1510
|
+
altitude -1000000 1000000 # metres above the entity
|
|
1511
|
+
altitudeFade 2
|
|
1512
|
+
slope 0 90 # degrees
|
|
1513
|
+
slopeFade 4
|
|
1514
|
+
moisture 0 1
|
|
1515
|
+
moistureFade 0.1
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1518
|
+
layer {
|
|
1519
|
+
albedo "textures/sand.png"
|
|
1520
|
+
tile 4
|
|
1521
|
+
}
|
|
1522
|
+
layer {
|
|
1523
|
+
albedo "textures/grass.png"
|
|
1524
|
+
tile 6
|
|
1525
|
+
}
|
|
1526
|
+
layer {
|
|
1527
|
+
albedo "textures/rock.png"
|
|
1528
|
+
tile 12
|
|
1529
|
+
triplanar true
|
|
1530
|
+
}
|
|
1531
|
+
```
|
|
1532
|
+
|
|
1533
|
+
An island with beaches, rivers and rock on its cliffs, for that file's
|
|
1534
|
+
three layers (a block's `{` ends its line):
|
|
1535
|
+
|
|
1536
|
+
```text
|
|
1537
|
+
generate {
|
|
1538
|
+
seed 7
|
|
1539
|
+
noise {
|
|
1540
|
+
warp 0.5
|
|
1541
|
+
}
|
|
1542
|
+
mask island 0.45
|
|
1543
|
+
erosion {
|
|
1544
|
+
drops 40000
|
|
1545
|
+
}
|
|
1546
|
+
sea 6
|
|
1547
|
+
shore 3
|
|
1548
|
+
rivers {
|
|
1549
|
+
threshold 300
|
|
1550
|
+
depth 2.5
|
|
1551
|
+
width 8
|
|
1552
|
+
}
|
|
1553
|
+
biome {
|
|
1554
|
+
layer 0
|
|
1555
|
+
altitude -1000 9
|
|
1556
|
+
}
|
|
1557
|
+
biome {
|
|
1558
|
+
layer 1
|
|
1559
|
+
altitude 9 1000
|
|
1560
|
+
slope 0 32
|
|
1561
|
+
}
|
|
1562
|
+
biome {
|
|
1563
|
+
layer 2
|
|
1564
|
+
slope 32 90
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1567
|
+
```
|
|
1568
|
+
|
|
1569
|
+
With `biome` rules the generator writes the control map (a terrain with
|
|
1570
|
+
biomes names no `control`); a channel is the most any of its layer's
|
|
1571
|
+
biomes gives a sample, its `weight` times its three bands. Without biomes
|
|
1572
|
+
there is no control map and the layers' own `slope` and `altitude`
|
|
1573
|
+
place them, as for a heightmap. The same file makes the same terrain on
|
|
1574
|
+
every machine (the generator uses only exact arithmetic and its own
|
|
1575
|
+
random numbers). It is a credible terrain of a kind, never a terrain from
|
|
1576
|
+
a picture: move the seed, the mask and the erosion until it reads right.
|
|
1577
|
+
`og cook --report` gives its height histogram, the share of land above
|
|
1578
|
+
the sea and the rivers' length, and writes its height and control maps
|
|
1579
|
+
as PNGs to `og-out/terrain-maps/` to look at.
|
|
1580
|
+
|
|
1581
|
+
Its sea is the water's level; the water is the terrain's size:
|
|
1582
|
+
|
|
1583
|
+
```ts
|
|
1584
|
+
if (info.seaLevel !== null) {
|
|
1585
|
+
const sea = must(world.spawn({ name: "sea", position: { x: 0, y: info.seaLevel, z: 0 } }));
|
|
1586
|
+
world.insert(sea, og.Water, { size: info.size, segments: 128 });
|
|
1587
|
+
}
|
|
1588
|
+
```
|
|
1589
|
+
|
|
1590
|
+
(on the terrain's entity's x and z, under its parent if it has one; an
|
|
1591
|
+
`og.WaterSurface` on the same entity makes the waves move and bodies float).
|
|
1592
|
+
|
|
1401
1593
|
It is drawn around the camera at finer detail nearby (casting and
|
|
1402
1594
|
receiving shadows, under the fog), placed by its entity's world transform
|
|
1403
1595
|
(turn or scale the entity and the terrain turns and scales with it), and
|
|
@@ -1747,6 +1939,35 @@ og.render.look(world)?.name; // the
|
|
|
1747
1939
|
stays sharper under camera motion and `taaSharpen` (0–1) restores
|
|
1748
1940
|
detail TAA softens. `RenderCapabilities.antialias` says what the device
|
|
1749
1941
|
resolved it to.
|
|
1942
|
+
- **Graphics quality** is RenderSettings' quality fields, read every
|
|
1943
|
+
frame: `rectShadows`, `shadowedLights`, `shadowMapScale`,
|
|
1944
|
+
`volumetricFog`, `softParticles`, `screenSpaceReflections`,
|
|
1945
|
+
`ambientOcclusion`, `msaaSamples` (4, or 1 for FXAA where the
|
|
1946
|
+
antialiasing multisamples). `og.render.applyQuality(world, preset)`
|
|
1947
|
+
writes a preset's row of them and records it in
|
|
1948
|
+
`RenderSettings.quality` (`none` before any):
|
|
1949
|
+
|
|
1950
|
+
| Field | low | medium | high |
|
|
1951
|
+
|---|---|---|---|
|
|
1952
|
+
| rectShadows | false | true | true |
|
|
1953
|
+
| shadowedLights | 2 | 8 | 8 |
|
|
1954
|
+
| shadowMapScale | 0.5 | 1 | 2 |
|
|
1955
|
+
| volumetricFog, softParticles, screenSpaceReflections, ambientOcclusion | false | true | true |
|
|
1956
|
+
| msaaSamples | 1 | 4 | 4 |
|
|
1957
|
+
|
|
1958
|
+
Medium is the defaults, the frame drawn before any preset. The renderer
|
|
1959
|
+
reads the fields and nothing else, so `og run --commands
|
|
1960
|
+
"0.5:get:og.RenderSettings"` shows what is drawn, and a field set after
|
|
1961
|
+
the preset wins. The switches only take away: the scene's PostEffects
|
|
1962
|
+
and lights keep their settings. The settings screen applies the
|
|
1963
|
+
player's pick when given the world (`og.ui.settingsScreen(id, { world,
|
|
1964
|
+
settings, ... })`); apply a saved preset yourself at start:
|
|
1965
|
+
|
|
1966
|
+
```ts
|
|
1967
|
+
start(world) { og.render.applyQuality(world, save.settings.quality ?? "medium"); }
|
|
1968
|
+
```
|
|
1969
|
+
|
|
1970
|
+
Inside a system, declare `og.RenderSettings` among its writes.
|
|
1750
1971
|
|
|
1751
1972
|
## 17. Saving progress
|
|
1752
1973
|
|
|
@@ -1891,6 +2112,201 @@ spaced along the length, as three.js spaces them. Rings and circles are one-side
|
|
|
1891
2112
|
standard material draws the triangle edges instead of the faces, one pixel
|
|
1892
2113
|
wide on every tier.
|
|
1893
2114
|
|
|
2115
|
+
**Shapes, extrusions, lathes and solids.** Three.js's modelling classes
|
|
2116
|
+
keep their names, parameters and defaults, so a three.js extrusion is a
|
|
2117
|
+
paste. `og.Shape` and `og.Path2` are three.js's Shape and Path:
|
|
2118
|
+
`moveTo`, `lineTo`, `quadraticCurveTo`, `bezierCurveTo`, `splineThru`,
|
|
2119
|
+
`arc`, `absarc`, `ellipse`, `absellipse`, `closePath`, `holes` and
|
|
2120
|
+
`getPoints(divisions)`. They flatten to points before they cross to the
|
|
2121
|
+
engine, so a points array works wherever a shape does
|
|
2122
|
+
(`reference/shapes.md`).
|
|
2123
|
+
- `shapeGeometry` is a flat shape with holes, one-sided like a circle.
|
|
2124
|
+
- `extrudeGeometry` pushes shapes along +Z (`depth`, `steps`) or along an
|
|
2125
|
+
og.path (`extrudePath`). `bevelEnabled`, `bevelThickness`, `bevelSize`,
|
|
2126
|
+
`bevelOffset` and `bevelSegments` round its edges, as in three.js.
|
|
2127
|
+
- `latheGeometry` turns a profile of `points` round +Y (`segments`,
|
|
2128
|
+
`phiStart`, `phiLength`), for vases, bottles and columns.
|
|
2129
|
+
- `polyhedronGeometry` takes `vertices`, `indices`, `radius` and `detail`.
|
|
2130
|
+
`icosahedronGeometry`, `dodecahedronGeometry`, `octahedronGeometry` and
|
|
2131
|
+
`tetrahedronGeometry` take `radius` and `detail`.
|
|
2132
|
+
- `sweepGeometry` sweeps a 2D `section` along an og.path. Its `scale` and
|
|
2133
|
+
`twist` are keyed over the path's length from 0 to 1, for horns, tusks,
|
|
2134
|
+
handles and twisted columns.
|
|
2135
|
+
- `mergeGeometries` places `parts` (each a geometry with `position`,
|
|
2136
|
+
`quaternion`, `scale` and a `mirror` axis) into one draw. Write an
|
|
2137
|
+
array as the same part at several placements.
|
|
2138
|
+
- `csgGeometry` is `union`, `subtract` or `intersect` of two placed
|
|
2139
|
+
closed geometries. Chain calls for more operands.
|
|
2140
|
+
|
|
2141
|
+
Every result is a geometry like `bufferGeometry`'s, with a BVH, `physics`
|
|
2142
|
+
and `dynamic`, and answered by `geometryInfo`:
|
|
2143
|
+
|
|
2144
|
+
```ts
|
|
2145
|
+
const gear = new og.Shape().absarc(0, 0, 1, 0, Math.PI * 2, false);
|
|
2146
|
+
gear.holes.push(new og.Path2().absarc(0, 0, 0.3, 0, Math.PI * 2, true));
|
|
2147
|
+
const disc = must(og.render.extrudeGeometry(world, {
|
|
2148
|
+
shapes: gear, depth: 0.2, bevelEnabled: true, bevelThickness: 0.05, bevelSize: 0.05,
|
|
2149
|
+
}));
|
|
2150
|
+
const vase = must(og.render.latheGeometry(world, {
|
|
2151
|
+
points: [{ x: 0, y: 0 }, { x: 0.5, y: 0.1 }, { x: 0.3, y: 1 }, { x: 0.4, y: 1.4 }],
|
|
2152
|
+
segments: 32,
|
|
2153
|
+
}));
|
|
2154
|
+
const cube = must(og.render.boxGeometry(world, { width: 1, height: 1, depth: 1 }));
|
|
2155
|
+
const ball = must(og.render.sphereGeometry(world, { radius: 0.15 }));
|
|
2156
|
+
const dice = must(og.render.csgGeometry(world, {
|
|
2157
|
+
op: "subtract", a: { geometry: cube }, b: { geometry: ball, position: { x: 0, y: 0, z: 0.5 } },
|
|
2158
|
+
}));
|
|
2159
|
+
```
|
|
2160
|
+
|
|
2161
|
+
The generators and the CSG decide every cut with exact predicates and use
|
|
2162
|
+
no platform trigonometry, so every host makes the same triangles. A CSG
|
|
2163
|
+
operand must be closed (every edge shared by two triangles). Its cost
|
|
2164
|
+
grows with the product of the two triangle counts where their boxes
|
|
2165
|
+
overlap, so cut low-poly operands at load, not every tick.
|
|
2166
|
+
|
|
2167
|
+
Every generator above takes `uvRepeat` as `boxGeometry` does (its uvs
|
|
2168
|
+
scaled, so a texture tiles). `bevelSize` left out (or null) is
|
|
2169
|
+
`bevelThickness - 0.1`, as in three.js: 0.1 at the default thickness.
|
|
2170
|
+
|
|
2171
|
+
**Models written as text: `type model`.** A prop made of these parts
|
|
2172
|
+
belongs in an asset, not in `start`: an `.ogt` of `type model` under
|
|
2173
|
+
`assets/` names each part's geometry by its `og.render` call, with the
|
|
2174
|
+
desc's field names and defaults, places it as `mergeGeometries` places a
|
|
2175
|
+
part, gives it a material and hangs it from a named pivot. `og cook`
|
|
2176
|
+
builds it into the same model blob a glTF cooks to: meshopt, levels of
|
|
2177
|
+
detail with their measured errors, the raycast BVH, the nodes. Load it
|
|
2178
|
+
with `og.load.gltf(world, "models/clockwork.ogt")` and `world.instantiate`,
|
|
2179
|
+
or name it in a scene (`model "models/clockwork.ogt"`), as any model.
|
|
2180
|
+
|
|
2181
|
+
```
|
|
2182
|
+
type model
|
|
2183
|
+
version 1
|
|
2184
|
+
---
|
|
2185
|
+
material "brass" {
|
|
2186
|
+
color 0.78 0.52 0.16 # linear, as glTF's baseColorFactor
|
|
2187
|
+
metalness 1
|
|
2188
|
+
roughness 0.32
|
|
2189
|
+
}
|
|
2190
|
+
material "glaze" {
|
|
2191
|
+
color 0.12 0.34 0.72
|
|
2192
|
+
roughness 0.3
|
|
2193
|
+
}
|
|
2194
|
+
pivot "axle" { # a node: code and animation find it by name
|
|
2195
|
+
position 0 1.25 0
|
|
2196
|
+
}
|
|
2197
|
+
part "gear" {
|
|
2198
|
+
pivot "axle" # hangs from the pivot (default: the root)
|
|
2199
|
+
material "brass"
|
|
2200
|
+
position 0 0 -0.1
|
|
2201
|
+
extrudeGeometry {
|
|
2202
|
+
shape { # og.Shape's calls, one a line
|
|
2203
|
+
moveTo 1 0
|
|
2204
|
+
absarc 0 0 1 0 6.283185307179586 false
|
|
2205
|
+
hole {
|
|
2206
|
+
absarc 0 0 0.28 0 6.283185307179586 true
|
|
2207
|
+
}
|
|
2208
|
+
}
|
|
2209
|
+
depth 0.16
|
|
2210
|
+
bevelThickness 0.04
|
|
2211
|
+
bevelSize 0.03
|
|
2212
|
+
}
|
|
2213
|
+
}
|
|
2214
|
+
part "bolt" { # one mesh under three nodes: drawn instanced
|
|
2215
|
+
pivot "axle"
|
|
2216
|
+
material "brass"
|
|
2217
|
+
cylinderGeometry {
|
|
2218
|
+
radiusTop 0.06
|
|
2219
|
+
radiusBottom 0.06
|
|
2220
|
+
height 0.36
|
|
2221
|
+
}
|
|
2222
|
+
at {
|
|
2223
|
+
position 0.55 0 0
|
|
2224
|
+
quaternion 0.7071068 0 0 0.7071068
|
|
2225
|
+
}
|
|
2226
|
+
at {
|
|
2227
|
+
position -0.275 0.476 0
|
|
2228
|
+
quaternion 0.7071068 0 0 0.7071068
|
|
2229
|
+
}
|
|
2230
|
+
at {
|
|
2231
|
+
position -0.275 -0.476 0
|
|
2232
|
+
quaternion 0.7071068 0 0 0.7071068
|
|
2233
|
+
}
|
|
2234
|
+
}
|
|
2235
|
+
part "vase" {
|
|
2236
|
+
material "glaze"
|
|
2237
|
+
position -2.2 0 0
|
|
2238
|
+
latheGeometry {
|
|
2239
|
+
points 0 0 0.32 0.04 0.42 0.4 0.24 0.95 0.3 1.25
|
|
2240
|
+
segments 40
|
|
2241
|
+
}
|
|
2242
|
+
}
|
|
2243
|
+
part "horn" {
|
|
2244
|
+
position 2.2 0 0
|
|
2245
|
+
sweepGeometry {
|
|
2246
|
+
section {
|
|
2247
|
+
absarc 0 0 0.22 0 6.283185307179586 false
|
|
2248
|
+
}
|
|
2249
|
+
path { # og.path's lines: kind, closed, tension, point
|
|
2250
|
+
kind catmullRom
|
|
2251
|
+
point 0 0 0
|
|
2252
|
+
point 0.15 0.6 0
|
|
2253
|
+
point -0.45 1.35 0.15
|
|
2254
|
+
}
|
|
2255
|
+
scale 0 1 # t value, repeatable (twist the same)
|
|
2256
|
+
scale 1 0.05
|
|
2257
|
+
}
|
|
2258
|
+
}
|
|
2259
|
+
part "dice" {
|
|
2260
|
+
position 1.1 0.3 0.55
|
|
2261
|
+
csgGeometry {
|
|
2262
|
+
op subtract
|
|
2263
|
+
a { # an operand: a geometry block, placed
|
|
2264
|
+
boxGeometry {
|
|
2265
|
+
width 0.6
|
|
2266
|
+
height 0.6
|
|
2267
|
+
depth 0.6
|
|
2268
|
+
}
|
|
2269
|
+
}
|
|
2270
|
+
b {
|
|
2271
|
+
position 0 0 0.3
|
|
2272
|
+
icosahedronGeometry {
|
|
2273
|
+
radius 0.08
|
|
2274
|
+
detail 1
|
|
2275
|
+
}
|
|
2276
|
+
}
|
|
2277
|
+
}
|
|
2278
|
+
}
|
|
2279
|
+
```
|
|
2280
|
+
|
|
2281
|
+
- Geometries: `boxGeometry`, `planeGeometry`, `sphereGeometry`,
|
|
2282
|
+
`cylinderGeometry`, `coneGeometry`, `capsuleGeometry`, `torusGeometry`,
|
|
2283
|
+
`shapeGeometry`, `extrudeGeometry` (`extrudePath { }` a path block),
|
|
2284
|
+
`latheGeometry` (`points x y x y ...`), `polyhedronGeometry`, the four
|
|
2285
|
+
solids, `sweepGeometry`, `csgGeometry` (`a { }`, `b { }`) and
|
|
2286
|
+
`mergeGeometries` (`part { }` blocks), each with `uvRepeat u v`. A
|
|
2287
|
+
part holds exactly one; combine more with `csgGeometry` or
|
|
2288
|
+
`mergeGeometries`.
|
|
2289
|
+
- Shapes: `moveTo`, `lineTo`, `quadraticCurveTo`, `bezierCurveTo`,
|
|
2290
|
+
`splineThru x y ...`, `arc`, `absarc`, `ellipse`, `absellipse` (angles in
|
|
2291
|
+
radians, then `true` for clockwise), `closePath`, `points x y ...`
|
|
2292
|
+
(setFromPoints) and `hole { }`. They flatten to the points og.Shape
|
|
2293
|
+
gives in TypeScript, bit for bit.
|
|
2294
|
+
- Placement: `position`, `quaternion x y z w`, `scale`, `mirror x|y|z`,
|
|
2295
|
+
on the part or in `at { }` blocks, one node each. The same part at
|
|
2296
|
+
several placements is one mesh drawn instanced; a mirrored placement is
|
|
2297
|
+
baked into a mesh of its own.
|
|
2298
|
+
- Materials: `color`, `opacity`, `metalness` (default 0), `roughness`
|
|
2299
|
+
(default 1), `emissive`, `emissiveIntensity`, `doubleSided`,
|
|
2300
|
+
`alphaTest`. A part without one draws glTF's grey default.
|
|
2301
|
+
- `og cook --report` lists the model's `triangles`, `parts`, `draws` (the
|
|
2302
|
+
distinct meshes; instanced placements are one) and `bvhBytes`/`bvhShare`.
|
|
2303
|
+
Past `budgets.triangles` or `budgets.vertices` in project.ogt the cook
|
|
2304
|
+
refuses it, so lower `segments`, `curveSegments`, `steps` or `detail`.
|
|
2305
|
+
Import settings (`models/clockwork.ogt.ogt`, `model { lods ... raycast
|
|
2306
|
+
false }`) apply as to a glTF.
|
|
2307
|
+
- `og dev` re-cooks it on an edit and the running game draws the edit
|
|
2308
|
+
under the same asset handle.
|
|
2309
|
+
|
|
1894
2310
|
**Lines and points.** `og.render.lines(world, desc)` and
|
|
1895
2311
|
`og.render.points(world, desc)` are immediate mode, like
|
|
1896
2312
|
`og.render.sprite`: submit them every tick they should show.
|
|
@@ -2154,6 +2570,10 @@ These are the checks to use before opening frames. All of them run from
|
|
|
2154
2570
|
`totalBytes` 64 MiB, `soundSeconds` 600, `videoSeconds` 300,
|
|
2155
2571
|
`fontGlyphs` 8192, `navPolygons` 65536, `sceneEntities` 10000 and
|
|
2156
2572
|
`emitterParticles` 16384, each a default a project may move.
|
|
2573
|
+
`bvhShare` 30 is a warning, not a limit: a model whose cooked raycast
|
|
2574
|
+
BVH is over 30 % of its blob (and at least 16 KiB) is named by `og cook
|
|
2575
|
+
--report` and `og doctor`; write `model { raycast false }` in its .ogt
|
|
2576
|
+
when nothing raycasts against it.
|
|
2157
2577
|
|
|
2158
2578
|
## 22. Levels of detail, reflection probes and screen-space reflections
|
|
2159
2579
|
|
|
@@ -2172,15 +2592,21 @@ model {
|
|
|
2172
2592
|
}
|
|
2173
2593
|
```
|
|
2174
2594
|
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2595
|
+
The cook measures each level's error, the largest distance between the
|
|
2596
|
+
level and the full mesh in the model's units, and `og cook --report`
|
|
2597
|
+
lists each model's triangles (`lods`) and error (`lodErrors`) per level.
|
|
2598
|
+
The renderer draws each `og.Model` entity at the coarsest level whose
|
|
2599
|
+
error covers less than a pixel at the entity's distance, with
|
|
2600
|
+
hysteresis, so nothing flickers at a boundary: a small prop keeps its
|
|
2601
|
+
full mesh until it is far away, a large tree drops levels sooner. A
|
|
2602
|
+
level whose error is too large for its purpose (a hard-surface model
|
|
2603
|
+
melting at a distance) is cooked tighter with `lodError`, or the model
|
|
2604
|
+
keeps more detail with `lodBias`. `og.Model.lodBias` (per entity) and
|
|
2605
|
+
`RenderSettings.lodBias` (the frame) scale that choice: 2 keeps the full
|
|
2606
|
+
mesh twice as far, and 0 always draws it. Check the choice with
|
|
2607
|
+
`debug:lod`, which tints models green, yellow, orange and red by level,
|
|
2608
|
+
with `dump_entity:<name>` (`render.lod`), and with the triangles in
|
|
2609
|
+
`ProbeTimings.triangles` or `dump_render`.
|
|
2184
2610
|
|
|
2185
2611
|
**Reflection probes.** Smooth surfaces reflect the environment map, which
|
|
2186
2612
|
is the sky. Indoors that is wrong: a chrome sphere in a room would show
|
|
@@ -2212,8 +2638,11 @@ world.insert(probe, og.ReflectionProbe, {
|
|
|
2212
2638
|
the interval high.
|
|
2213
2639
|
- Size the box to the room. Each object takes the smallest box holding
|
|
2214
2640
|
its centre, so two rooms that share a model each reflect their own.
|
|
2215
|
-
The capture shows everything in the room: characters in their pose
|
|
2216
|
-
|
|
2641
|
+
The capture shows everything in the room: characters in their pose
|
|
2642
|
+
(and each one takes the probe of the room its pose stands in), terrain,
|
|
2643
|
+
grass, water (refracting what lies below it), 3D fluids, glass,
|
|
2644
|
+
particles (soft ones fading as in the frame), lines and world sprites
|
|
2645
|
+
and text. Terrain, grass and water inside the box are lit
|
|
2217
2646
|
by it too. At most 8 probes (`MAX_REFLECTION_PROBES`) are used,
|
|
2218
2647
|
nearest the camera first.
|
|
2219
2648
|
- `dump_render` lists the frame's probes and whether each was loaded from
|
|
@@ -2261,7 +2690,8 @@ default) or `hdr`:
|
|
|
2261
2690
|
`depth: true` also keeps the view's linear depth, from near (0) to far
|
|
2262
2691
|
(1), of its opaque meshes, on every tier, WebGL2 included. It costs a
|
|
2263
2692
|
second draw of the view's opaque meshes, so ask for it only when a
|
|
2264
|
-
material reads it.
|
|
2693
|
+
material reads it. (A scene with soft particles, `softDistance` above 0,
|
|
2694
|
+
pays that draw in every view anyway: its particles fade against it.)
|
|
2265
2695
|
`RenderCapabilities.maxRenderTargetSize` is the largest side.
|
|
2266
2696
|
|
|
2267
2697
|
**A second camera.** `og.CameraView` on an entity is a camera with
|
|
@@ -2285,16 +2715,18 @@ world.insert(p2, og.CameraView, { viewportX: 0.5, viewportWidth: 0.5 });
|
|
|
2285
2715
|
A view draws what the main camera draws, from its own eye and on its own
|
|
2286
2716
|
`layers`: meshes and models (skinned meshes and custom shaders included),
|
|
2287
2717
|
opaque then transparent back to front, the terrain and the sky, particle
|
|
2288
|
-
systems, og.Lines and og.Points, and world sprites and text, lit and
|
|
2718
|
+
systems, trails, og.Lines and og.Points, and world sprites and text, lit and
|
|
2289
2719
|
shadowed by the frame's lights. Each view is a second draw of everything
|
|
2290
2720
|
its layers admit, so keep it cheap with `layers` and `every`.
|
|
2291
2721
|
- An `ldr` target and a viewport are exposed with the view's `exposure`
|
|
2292
2722
|
and tone mapped with the frame's curve. An `hdr` target holds linear
|
|
2293
2723
|
radiance and is exposed by the frame that shows it.
|
|
2294
2724
|
- Bloom, AO, SSR, depth of field, colour grading and custom post passes
|
|
2295
|
-
run on the main frame only.
|
|
2296
|
-
|
|
2297
|
-
|
|
2725
|
+
run on the main frame only (the 2D glow, `PostEffects.glow`, is the
|
|
2726
|
+
exception: a view adds its own).
|
|
2727
|
+
- In a view, sprites are 2D-lit and glow and 2D fluids and soft
|
|
2728
|
+
particles draw as in the main frame. Screen sprites, the UI and debug
|
|
2729
|
+
draw stay on the main frame.
|
|
2298
2730
|
|
|
2299
2731
|
A viewport view draws over the finished image and under the UI.
|
|
2300
2732
|
|
|
@@ -2340,8 +2772,9 @@ fn fragment(f: FragmentInput, p: Params) -> SurfaceOutput // f:
|
|
|
2340
2772
|
// standard_surface(f), noise3(p).
|
|
2341
2773
|
```
|
|
2342
2774
|
An entry you leave out is the standard one.
|
|
2343
|
-
- `lit` surfaces are lit by the sun's cascades, the point and
|
|
2344
|
-
with their shadows
|
|
2775
|
+
- `lit` surfaces are lit by the sun's cascades, the point, spot and rect
|
|
2776
|
+
lights with their shadows and cookies (a rect light as an area, as on a
|
|
2777
|
+
standard material), the environment and the fog. `unlit` surfaces draw
|
|
2345
2778
|
as returned.
|
|
2346
2779
|
- The depth prepass, every shadow pass and every view run the same
|
|
2347
2780
|
entries, and alpha under the material's `alphaTest` is cut in each of
|
|
@@ -2361,11 +2794,15 @@ with up to eight `param` lines. The function reads:
|
|
|
2361
2794
|
|
|
2362
2795
|
It returns linear HDR. To use one:
|
|
2363
2796
|
1. Load it with `og.load.post(world, "post/crt.ogt")`.
|
|
2364
|
-
2. Put the
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2797
|
+
2. Put the handles in the list `PostEffects.custom`, at most
|
|
2798
|
+
`RenderCapabilities.maxCustomPosts` (8) of them. They run in its order,
|
|
2799
|
+
each over the one before it, after depth of field and motion blur and
|
|
2800
|
+
before exposure, bloom and tone mapping. Write the list whole:
|
|
2801
|
+
`post.custom = [grade, crt]`, `post.custom = [...post.custom, h]`,
|
|
2802
|
+
`post.custom = []`. Reading it answers a frozen copy, so
|
|
2803
|
+
`post.custom.push(h)` throws instead of changing nothing; nine passes
|
|
2804
|
+
are refused, never cut to eight. A look gives it on one line:
|
|
2805
|
+
`custom "post/tint.ogt" "post/crt.ogt"`.
|
|
2369
2806
|
3. Set its parameters with `og.render.setPostParam(world, post, "curve",
|
|
2370
2807
|
[0.1])`.
|
|
2371
2808
|
|
|
@@ -2450,3 +2887,12 @@ textures between lanterns to stay under it.
|
|
|
2450
2887
|
`reference/index.md` (the generated wiki shipped with this skill) maps every
|
|
2451
2888
|
module (grouped by skill, as in §1), type and function to its page, with the IDL text, defaults, ranges
|
|
2452
2889
|
and units of every field.
|
|
2890
|
+
|
|
2891
|
+
`guides/three-to-og.md` (beside this skill) maps three.js's classes and
|
|
2892
|
+
idioms to the engine's: the scene graph to entities and og.Parent,
|
|
2893
|
+
Object3D to og.Transform, the geometry classes to §18's generators, the
|
|
2894
|
+
materials to StandardMaterialDesc, the loaders to og.load, the render
|
|
2895
|
+
loop to systems on the tick, Raycaster to `og.render.raycast`, and the
|
|
2896
|
+
gaps by name. `og migrate three <file.ts>` rewrites a three.js file's
|
|
2897
|
+
mechanical part with those mappings and marks every line it cannot,
|
|
2898
|
+
citing the guide's section.
|