@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
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
# three.js to Origin Engine
|
|
2
|
+
|
|
3
|
+
For an author who knows three.js, or who has a three.js file to bring
|
|
4
|
+
over. Origin Engine keeps three.js's vocabulary wherever it does not
|
|
5
|
+
contradict the engine: `Vector3`, position, quaternion and scale, the
|
|
6
|
+
material parameters, the geometry classes' parameters and defaults, glTF
|
|
7
|
+
loading, layers. What it does not keep is the object model. A three.js
|
|
8
|
+
program is a tree of mutable objects that a loop you write renders; an
|
|
9
|
+
Origin Engine game is a world of entities with plain components, changed
|
|
10
|
+
by systems on a fixed tick, and the engine draws every frame itself. Read
|
|
11
|
+
og-game §3 (components, systems, the game) and og-core first: this page
|
|
12
|
+
only maps names.
|
|
13
|
+
|
|
14
|
+
`og migrate three <file.ts>` (§11) rewrites the mechanical part of a
|
|
15
|
+
file with these mappings and marks every line it cannot, citing the
|
|
16
|
+
section here that says what to do.
|
|
17
|
+
|
|
18
|
+
## 1. The model, side by side
|
|
19
|
+
|
|
20
|
+
| three.js | Origin Engine |
|
|
21
|
+
|---|---|
|
|
22
|
+
| `new THREE.Scene()` | the world: every entity spawned is in it, nothing is added |
|
|
23
|
+
| an `Object3D`, `Group` or `Mesh` | an entity (`world.spawn`), its data as components |
|
|
24
|
+
| `object.position`, `quaternion`, `scale` | the og.Transform component, read with `world.get` and written with `world.set` |
|
|
25
|
+
| `parent.add(child)` | og.Parent on the child (`SpawnDesc.parent` at spawn) |
|
|
26
|
+
| a `BufferGeometry`, a `Material`, a `Texture` | a handle the world owns (Geometry, Material, Texture), made by `og.render` or `og.load` |
|
|
27
|
+
| `new THREE.Mesh(geometry, material)` | og.Mesh `{ geometry, material }` on an entity |
|
|
28
|
+
| `renderer.render(scene, camera)` in `requestAnimationFrame` | nothing: the engine draws every frame; game logic runs in systems on the fixed tick (§8) |
|
|
29
|
+
| `camera` | the og.Camera resource (one per world), og.CameraView for more |
|
|
30
|
+
| `Raycaster` | `og.render.raycast` (§9) |
|
|
31
|
+
| `GLTFLoader`, `TextureLoader` | `og.load.gltf`, `og.load.texture` of cooked assets (§7) |
|
|
32
|
+
| a thrown error | a Result: `{ ok: true, value }` or `{ ok: false, reason }` |
|
|
33
|
+
| `Math.random()`, `clock.getDelta()` | og.Rng and og.Time: deterministic, so replays and tests repeat |
|
|
34
|
+
|
|
35
|
+
Three rules follow from the model and catch every port:
|
|
36
|
+
|
|
37
|
+
- **Values are plain.** og.Transform's position is `{ x, y, z }`, not a
|
|
38
|
+
Vector3 object with methods. `vec3`, `quat`, `mat4` and `color` are
|
|
39
|
+
three.js's methods as pure functions (`vec3.add(a, b)` returns a new
|
|
40
|
+
value; `a.add(b)` does not exist), so a result can go straight into a
|
|
41
|
+
component (`reference/math.md`).
|
|
42
|
+
- **Every call that can fail answers a Result.** The examples here use
|
|
43
|
+
a `must` helper, as the templates do:
|
|
44
|
+
`function must<T>(r: { ok: true; value: T } | { ok: false; reason: string }): T { if (!r.ok) throw new Error(r.reason); return r.value; }`.
|
|
45
|
+
- **Calls take the world.** Setup goes in `GameDesc.start(world)` (or a
|
|
46
|
+
command), per-tick logic in a system; neither keeps state in module
|
|
47
|
+
variables (og-core).
|
|
48
|
+
|
|
49
|
+
## 2. The scene graph: entities and og.Parent
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
// three.js
|
|
53
|
+
const ship = new THREE.Group();
|
|
54
|
+
const hull = new THREE.Mesh(new THREE.BoxGeometry(2, 0.5, 4), steel);
|
|
55
|
+
ship.add(hull);
|
|
56
|
+
scene.add(ship);
|
|
57
|
+
|
|
58
|
+
// Origin Engine, in start(world)
|
|
59
|
+
const ship = must(world.spawn({ name: "ship" }));
|
|
60
|
+
const hull = must(world.spawn({ name: "hull", parent: ship }));
|
|
61
|
+
world.insert(hull, og.Mesh, { geometry: must(og.render.boxGeometry(world, { width: 2, height: 0.5, depth: 4 })), material: steel });
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
- `parent.add(child)` after the spawn is `world.insert(child, og.Parent,
|
|
65
|
+
{ entity: parent })`; `parent.remove(child)` is `world.remove(child,
|
|
66
|
+
og.Parent)`; `scene.remove(object)` is `world.despawn(object)`.
|
|
67
|
+
- A child's og.Transform is relative to its parent, as three.js's
|
|
68
|
+
`position` is; the engine composes og.MatrixWorld down the chain after
|
|
69
|
+
the systems run, so there is no `updateMatrixWorld` to call.
|
|
70
|
+
- `getObjectByName("hull")` is `world.find("hull")`. Names are unique and
|
|
71
|
+
the probe, the command channel and the tests address entities by them:
|
|
72
|
+
name every entity anyone will ask about.
|
|
73
|
+
- `scene.traverse(fn)` over everything of a kind is a system's query over
|
|
74
|
+
the components that kind has (og-core): `reads: [og.Mesh]` visits every
|
|
75
|
+
drawn mesh, archetype by archetype.
|
|
76
|
+
- A scene written by hand in three.js code is often better as a scene
|
|
77
|
+
file: `.ogt` text with nested `entity` blocks, cooked and diffable
|
|
78
|
+
(og-game §4).
|
|
79
|
+
|
|
80
|
+
## 3. Object3D: og.Transform and the components
|
|
81
|
+
|
|
82
|
+
| three.js `Object3D` | Origin Engine |
|
|
83
|
+
|---|---|
|
|
84
|
+
| `position.set(x, y, z)` | `world.set(e, og.Transform, { position: { x, y, z } })` |
|
|
85
|
+
| `quaternion.set(x, y, z, w)` | `world.set(e, og.Transform, { quaternion: { x, y, z, w } })` |
|
|
86
|
+
| `rotation.set(x, y, z)` (an Euler) | `{ quaternion: quat.fromEuler({ x, y, z }) }`: radians, order `"XYZ"` as three.js's default |
|
|
87
|
+
| `scale.set(x, y, z)`, `scale.setScalar(s)` | `{ scale: { x, y, z } }` |
|
|
88
|
+
| `position.x += v` | read, change, write: `const t = must(world.get(e, og.Transform)); world.set(e, og.Transform, { position: { ...t.position, x: t.position.x + v } })`, or a system over the column (og-core) |
|
|
89
|
+
| `lookAt(target)` (a camera or a light) | `{ quaternion: og.transform.lookAt(eye, target) }`: it points -Z at the target, as three.js turns cameras and lights |
|
|
90
|
+
| `lookAt(target)` (any other object) | three.js points such an object's +Z at the target: `og.transform.lookAt(target, eye)`, the reverse, does the same |
|
|
91
|
+
| `matrixWorld` | og.MatrixWorld (read only; the engine writes it) |
|
|
92
|
+
| `visible`, `castShadow`, `receiveShadow`, `layers` | og.Mesh's (and og.Model's) `visible`, `castShadow`, `receiveShadow`, `layers` |
|
|
93
|
+
| `name` | `SpawnDesc.name` |
|
|
94
|
+
| `userData` | your own component (`defineComponent`): reflected, saved, inspectable |
|
|
95
|
+
|
|
96
|
+
Two defaults differ from three.js: `Mesh.receiveShadow` is on (three.js's
|
|
97
|
+
is off) and `DirectionalLight.castShadow` is on. Set them where the port
|
|
98
|
+
depends on the old value.
|
|
99
|
+
|
|
100
|
+
## 4. Geometry: og.render and og-geom
|
|
101
|
+
|
|
102
|
+
The geometry classes keep their parameters, names and defaults; the
|
|
103
|
+
positional arguments become a desc object of the same names, and the
|
|
104
|
+
result is a Geometry handle (a Result) that draws through og.Mesh, carries
|
|
105
|
+
a BVH for `og.render.raycast` and is a `Collider.mesh` at once
|
|
106
|
+
(og-game §18 has the details).
|
|
107
|
+
|
|
108
|
+
| three.js | Origin Engine | Not carried over |
|
|
109
|
+
|---|---|---|
|
|
110
|
+
| `BoxGeometry(width, height, depth)` | `og.render.boxGeometry(world, { width, height, depth })` | the segment counts |
|
|
111
|
+
| `PlaneGeometry(width, height)` | `og.render.planeGeometry` | the segment counts |
|
|
112
|
+
| `SphereGeometry(radius, widthSegments, heightSegments)` | `og.render.sphereGeometry` | `phiStart`, `phiLength`, `thetaStart`, `thetaLength` |
|
|
113
|
+
| `CylinderGeometry(radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength)` | `og.render.cylinderGeometry` | — |
|
|
114
|
+
| `ConeGeometry(radius, height, radialSegments, heightSegments, openEnded)` | `og.render.coneGeometry` | `thetaStart`, `thetaLength` |
|
|
115
|
+
| `CapsuleGeometry(radius, height, capSegments, radialSegments, heightSegments)` | `og.render.capsuleGeometry` (`height` the straight middle, as r174's) | — |
|
|
116
|
+
| `TorusGeometry(radius, tube, radialSegments, tubularSegments, arc)` | `og.render.torusGeometry` | — |
|
|
117
|
+
| `RingGeometry(innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength)` | `og.render.ringGeometry` | — |
|
|
118
|
+
| `CircleGeometry(radius, segments, thetaStart, thetaLength)` | `og.render.circleGeometry` | — |
|
|
119
|
+
| `TubeGeometry(new CatmullRomCurve3(points), tubularSegments, radius, radialSegments, closed)` | `og.render.tubeGeometry(world, { points, ... })`, or `path` an og.path | other Curve classes: write the curve as an og.path |
|
|
120
|
+
| `LatheGeometry(points, segments, phiStart, phiLength)` | `og.render.latheGeometry` (points `{ x, y }`) | — |
|
|
121
|
+
| `Shape`, `Path` | `og.Shape`, `og.Path2` (the root `shapes` module, `reference/shapes.md`): the same calls | — |
|
|
122
|
+
| `ShapeGeometry(shapes, curveSegments)` | `og.render.shapeGeometry(world, { shapes, curveSegments })` | — |
|
|
123
|
+
| `ExtrudeGeometry(shapes, { depth, bevelEnabled, ... })` | `og.render.extrudeGeometry(world, { shapes, depth, bevelEnabled, ... })`; `extrudePath` an og.path | `UVGenerator` |
|
|
124
|
+
| `PolyhedronGeometry(vertices, indices, radius, detail)` | `og.render.polyhedronGeometry` | — |
|
|
125
|
+
| `IcosahedronGeometry`, `DodecahedronGeometry`, `OctahedronGeometry`, `TetrahedronGeometry` `(radius, detail)` | `og.render.icosahedronGeometry` and the other three | — |
|
|
126
|
+
| `BufferGeometry` with `setAttribute` and `setIndex` | `og.render.bufferGeometry(world, { positions, normals, uvs, colors, indices })` (typed arrays, normals computed when left out) | groups (one material per geometry: split it) |
|
|
127
|
+
| `attribute.needsUpdate = true` | `og.render.updateGeometry` of a geometry made with `dynamic: true` | — |
|
|
128
|
+
| `BufferGeometryUtils.mergeGeometries([...])` | `og.render.mergeGeometries(world, { parts: [{ geometry, position, quaternion, scale, mirror }] })` | — |
|
|
129
|
+
| three-bvh-csg's `Evaluator` | `og.render.csgGeometry(world, { op, a, b })` with exact predicates | — |
|
|
130
|
+
| `TorusKnotGeometry`, `TextGeometry`, `EdgesGeometry`, `WireframeGeometry` | none: a knot as `tubeGeometry` through its points, text as `og.render.text` or og.ui, edges as `wireframe: true` on the material or `og.render.lines` | — |
|
|
131
|
+
|
|
132
|
+
Two more go beyond three.js: `og.render.sweepGeometry` sweeps a section
|
|
133
|
+
along an og.path with a scale and twist over its length (horns, tusks,
|
|
134
|
+
handles), and a prop built of these parts belongs in an asset rather
|
|
135
|
+
than in code: an `.ogt` of `type model` names each part by its
|
|
136
|
+
`og.render` call with the desc's fields, places it as `mergeGeometries`
|
|
137
|
+
does and gives it a material and a pivot; the cook builds it into the
|
|
138
|
+
model blob a glTF cooks to, with levels of detail and the BVH, and
|
|
139
|
+
`og.load.gltf` loads it (og-game §18 has the grammar). The og-model
|
|
140
|
+
skill builds such props from a reference image.
|
|
141
|
+
|
|
142
|
+
`og.render.geometryInfo` answers what `geometry.attributes.position.count`
|
|
143
|
+
and `computeBoundingBox` did. Geometries are made where the world is
|
|
144
|
+
(start, a command, a system), never at module load.
|
|
145
|
+
|
|
146
|
+
## 5. Materials and textures
|
|
147
|
+
|
|
148
|
+
Every lit three.js mesh material becomes `og.render.standardMaterial(world,
|
|
149
|
+
desc)`, with the StandardMaterialDesc fields under three.js's names:
|
|
150
|
+
`color`, `metalness`, `roughness`, `emissive`, `emissiveIntensity`, `map`,
|
|
151
|
+
`normalMap`, `normalScale`, `roughnessMap`, `metalnessMap`, `aoMap`,
|
|
152
|
+
`emissiveMap`, `opacity`, `transparent`, `alphaTest`, `side`,
|
|
153
|
+
`flatShading`, `wireframe`, `envMapIntensity`, and MeshPhysicalMaterial's
|
|
154
|
+
`clearcoat`, `sheen`, `transmission`, `thickness`, `ior`, `iridescence`
|
|
155
|
+
and `anisotropy`.
|
|
156
|
+
|
|
157
|
+
| three.js | Origin Engine |
|
|
158
|
+
|---|---|
|
|
159
|
+
| `MeshStandardMaterial(params)`, `MeshPhysicalMaterial(params)` | `standardMaterial(world, params)` |
|
|
160
|
+
| `MeshBasicMaterial(params)` | `standardMaterial(world, { ...params, unlit: true })` |
|
|
161
|
+
| `MeshToonMaterial(params)` | `standardMaterial(world, { ...params, toon: true })` (`gradientMap` quantizes the light) |
|
|
162
|
+
| `MeshLambertMaterial`, `MeshPhongMaterial` | `standardMaterial`: roughness near 1 for Lambert; Phong's `shininess` and `specular` have no field (lower roughness for a tighter highlight) |
|
|
163
|
+
| `color: 0xff8800`, `new THREE.Color("#ff8800")` | `color: color.fromHex(0xff8800)`: sRGB hex to linear, as three.js's colour management does |
|
|
164
|
+
| `new THREE.Color(r, g, b)` | `{ r, g, b }`, linear, as three.js's components are |
|
|
165
|
+
| `side: THREE.DoubleSide` (`FrontSide`, `BackSide`) | `side: "double"` (`"front"`, `"back"`) |
|
|
166
|
+
| `material.roughness = 0.3` | `og.render.updateMaterial(world, material, { roughness: 0.3 })` |
|
|
167
|
+
| `vertexColors` on | the geometry's `colors` multiply the colour whenever it has them |
|
|
168
|
+
| `texture.repeat.set(4, 4)` with `RepeatWrapping` | the geometry's `uvRepeat: { x: 4, y: 4 }`; textures always wrap |
|
|
169
|
+
| `texture.colorSpace = THREE.SRGBColorSpace` | the cook's import settings (og-game §5): colour textures are sRGB, a `kind normal` texture is linear |
|
|
170
|
+
| `scene.environment = pmrem.fromEquirectangular(hdr)` | og.Environment's `map` from `og.load.environment` of a `type environment` asset (§7) |
|
|
171
|
+
| `LineBasicMaterial`, `PointsMaterial` | `og.render.lines` and `og.render.points` each tick, or the og.Lines and og.Points components over a geometry |
|
|
172
|
+
| `SpriteMaterial` with `THREE.Sprite` | og.Sprite, or `og.render.sprite` each tick |
|
|
173
|
+
| `ShaderMaterial`, `RawShaderMaterial`, `onBeforeCompile` | §10 |
|
|
174
|
+
|
|
175
|
+
Toon, rim, outline, dissolve and hit flash are fields of the same desc
|
|
176
|
+
(og-game §10). One geometry has one material: three.js's material arrays
|
|
177
|
+
and geometry groups become one entity per group.
|
|
178
|
+
|
|
179
|
+
## 6. Lights, the camera and the frame
|
|
180
|
+
|
|
181
|
+
| three.js | Origin Engine |
|
|
182
|
+
|---|---|
|
|
183
|
+
| `DirectionalLight(color, intensity)`, `position` and `target` | og.DirectionalLight `{ color, intensity }` on an entity: it shines along the entity's -Z, so aim it with `og.transform.lookAt(position, target)` (three.js's default target is the origin) |
|
|
184
|
+
| `PointLight(color, intensity, distance)` | og.PointLight `{ color, intensity, distance }`: `distance` is never infinite (10 by default); `decay` is not carried over |
|
|
185
|
+
| `SpotLight(color, intensity, distance, angle, penumbra)` | og.SpotLight, along the entity's -Z like the directional light |
|
|
186
|
+
| `RectAreaLight(color, intensity, width, height)` | og.RectLight |
|
|
187
|
+
| `AmbientLight`, `HemisphereLight` | no light entity: the sky lights every surface (RenderSettings.environmentIntensity), or an environment map does (og.Environment); og.Sky colours the sky itself |
|
|
188
|
+
| `light.castShadow = true`, `light.shadow.mapSize` | the light's `castShadow`; `RenderOptions.shadowMapSize` and RenderSettings.shadowMapScale |
|
|
189
|
+
| `renderer.shadowMap.enabled = true` | nothing: shadows are on per light |
|
|
190
|
+
| `PerspectiveCamera(fov, aspect, near, far)` | the og.Camera resource: `const camera = must(world.resource(og.Camera)); camera.fov = 50;` (degrees, vertical, as three.js); the aspect is the play surface's |
|
|
191
|
+
| `camera.aspect = w / h; camera.updateProjectionMatrix()` on resize | nothing: the engine sizes the canvas and the projection |
|
|
192
|
+
| `OrthographicCamera(left, right, top, bottom, near, far)` | og.Camera with `orthographic: true` and `height` the visible world height (`top - bottom`); the width follows the aspect |
|
|
193
|
+
| `camera.position.set(x, y, z)`, `camera.lookAt(x, y, z)` | `camera.position = { x, y, z }`, `camera.lookAt({ x, y, z })` on the resource handle |
|
|
194
|
+
| `scene.background = new THREE.Color(0x87ceeb)` | `camera.background = color.fromHex(0x87ceeb)` (og.Camera's `background`) |
|
|
195
|
+
| `scene.fog = new THREE.Fog(color, near, far)` | og.Fog's `color`, `start`, `end` (`density` for FogExp2), with `enabled` true (og-game §11) |
|
|
196
|
+
| `new THREE.WebGLRenderer({ antialias: true })` | `GameDesc.render` (`render: { antialias: "msaa4" }`); the engine owns the canvas, on an OffscreenCanvas in a Worker on the web |
|
|
197
|
+
| `renderer.toneMapping`, `toneMappingExposure` | RenderSettings.toneMapping (`"aces"` by default, `"agx"`, `"none"`) and `exposure` (og-game §16) |
|
|
198
|
+
| a second camera into a `WebGLRenderTarget` | og.CameraView with `target` from `og.render.renderTarget` (og-game §23) |
|
|
199
|
+
| `EffectComposer` and its passes | og.PostEffects (bloom, AO, depth of field, outline, LUTs and more, og-game §10) and custom post passes (§10 here) |
|
|
200
|
+
|
|
201
|
+
Light intensities are three.js's physical units in spirit (a point
|
|
202
|
+
light's `intensity` is its radiance at one metre) but not calibrated
|
|
203
|
+
against them: judge a ported scene's light in a frame, not by its
|
|
204
|
+
numbers.
|
|
205
|
+
|
|
206
|
+
## 7. Loaders: og.load and the cook
|
|
207
|
+
|
|
208
|
+
There is no loader object and nothing is fetched by URL. Sources go in
|
|
209
|
+
`assets/`, `og cook` turns them into `cooked/` (meshopt meshes with LODs
|
|
210
|
+
and BVHs, KTX2 textures, QOA audio, MSDF fonts), and every `og.load`
|
|
211
|
+
call names an asset id, the path under `assets/` (og-game §5, §6).
|
|
212
|
+
|
|
213
|
+
| three.js | Origin Engine |
|
|
214
|
+
|---|---|
|
|
215
|
+
| `new GLTFLoader().load(url, (gltf) => scene.add(gltf.scene))` | `const ship = must(og.load.gltf(world, "models/ship.glb"))`, then `world.instantiate(ship, { name: "ship", position })` once `og.load.status(world, ship)` is `"ready"`, or the `AssetReady` event; a scene's `model` line instantiates it for you |
|
|
216
|
+
| `gltf.animations` with an `AnimationMixer` | og.AnimationPlayer or og.AnimationGraph on the instance (og-game §9) |
|
|
217
|
+
| `DRACOLoader`, `KTX2Loader`, `MeshoptDecoder` | the cook compresses; give it the uncompressed glTF (it reads no Draco) |
|
|
218
|
+
| `new THREE.TextureLoader().load("textures/crate.png")` | `og.load.texture(world, "textures/crate.png")` |
|
|
219
|
+
| `RGBELoader`, `EXRLoader`, `CubeTextureLoader` for the environment | an `.ogt` of `type environment` naming the `.hdr`, `.exr` or cube, loaded with `og.load.environment` (prefiltered at cook time) |
|
|
220
|
+
| `AudioLoader` with `THREE.Audio` | `og.load.sound` and og.AudioSource (og-audio) |
|
|
221
|
+
| `FontLoader` | `og.load.font` of a TTF or OTF, for `og.render.text` and og.ui |
|
|
222
|
+
| `loader.loadAsync(url)` and `await` | no promises: a load completes at a tick boundary, and under `og run` before the next tick, so it lands on the same tick every run |
|
|
223
|
+
|
|
224
|
+
A MagicaVoxel `.vox` loads with `og.load.gltf` too, and so does a
|
|
225
|
+
`type model` asset (§4).
|
|
226
|
+
|
|
227
|
+
## 8. The render loop: the tick
|
|
228
|
+
|
|
229
|
+
```ts
|
|
230
|
+
// three.js
|
|
231
|
+
const clock = new THREE.Clock();
|
|
232
|
+
renderer.setAnimationLoop(() => {
|
|
233
|
+
const dt = clock.getDelta();
|
|
234
|
+
cube.rotation.y += dt;
|
|
235
|
+
renderer.render(scene, camera);
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
// Origin Engine: a component marks what turns, a system turns it
|
|
239
|
+
const Spin = defineComponent("Spin", { speed: f32(1) });
|
|
240
|
+
const Turn = defineSystem("Turn", { reads: [Spin], writes: [og.Transform] }, (q, time) => {
|
|
241
|
+
for (const a of q.archetypes()) {
|
|
242
|
+
const rot = a.column(og.Transform).quaternion;
|
|
243
|
+
const speed = a.column(Spin).speed;
|
|
244
|
+
for (let i = 0; i < a.count; i++) {
|
|
245
|
+
const next = quat.multiply(
|
|
246
|
+
{ x: rot[i * 4], y: rot[i * 4 + 1], z: rot[i * 4 + 2], w: rot[i * 4 + 3] },
|
|
247
|
+
og.transform.fromAxisAngle({ x: 0, y: 1, z: 0 }, speed[i] * time.dt),
|
|
248
|
+
);
|
|
249
|
+
rot.set([next.x, next.y, next.z, next.w], i * 4);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
export default og.game({ systems: [Turn], start(world) { /* spawn the cube with Spin */ } });
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
- The loop body becomes one or more systems, each one job, listed in
|
|
257
|
+
`GameDesc.systems`. A system runs once per tick (60 Hz by default,
|
|
258
|
+
fixed) over the archetypes that hold its components; the engine
|
|
259
|
+
renders between ticks and interpolates.
|
|
260
|
+
- `clock.getDelta()` is `time.dt` (the og.Time resource, fixed per
|
|
261
|
+
tick); `clock.getElapsedTime()` is `time.elapsed`. Nothing in a tick
|
|
262
|
+
reads the wall clock.
|
|
263
|
+
- `Math.random()` is og.Rng (`world.resource(og.Rng)`, `range`, `chance`,
|
|
264
|
+
`integer`): seeded from the project, so a replay repeats the run.
|
|
265
|
+
- `renderer.render(scene, camera)`, `requestAnimationFrame` and the
|
|
266
|
+
resize handler are deleted: the engine draws every frame.
|
|
267
|
+
- Input listeners (`addEventListener("keydown")`) become reads of
|
|
268
|
+
og.Input in a system (`input.pressed("Space")`, og-game §7): the main
|
|
269
|
+
thread owns the events and the tick sees them at its start.
|
|
270
|
+
|
|
271
|
+
## 9. Picking: og.render.raycast
|
|
272
|
+
|
|
273
|
+
```ts
|
|
274
|
+
// three.js
|
|
275
|
+
raycaster.setFromCamera(pointer, camera);
|
|
276
|
+
const hits = raycaster.intersectObjects(scene.children, true);
|
|
277
|
+
|
|
278
|
+
// Origin Engine, in a system that reads og.Input and og.Camera
|
|
279
|
+
const camera = must(world.resource(og.Camera));
|
|
280
|
+
const input = must(world.resource(og.Input));
|
|
281
|
+
const ray = camera.screenToRay(input.pointer.x, input.pointer.y); // CSS pixels, not -1..1
|
|
282
|
+
const hits = must(og.render.raycast(world, ray, { first: true }));
|
|
283
|
+
if (hits.length > 0) og.debug.sphere(world, hits[0].point, 0.05);
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
- It tests what is drawn (every og.Mesh and og.Model at its world
|
|
287
|
+
transform, through each geometry's BVH, both faces), nearest first,
|
|
288
|
+
always over the whole world: there is no list of objects to pass. Each
|
|
289
|
+
hit has `entity`, `geometry`, `distance`, `point`, `normal`, `uv` and
|
|
290
|
+
`faceIndex`, as three.js's intersection.
|
|
291
|
+
- `near` and `far` are `maxDistance`; three.js's `layers` are the desc's
|
|
292
|
+
`layers`, tested as three.js tests them; `first: true` stops at the
|
|
293
|
+
nearest hit.
|
|
294
|
+
- For gameplay against colliders (ground checks, bullets) use
|
|
295
|
+
`og.physics.raycast`, which reads the physics world instead
|
|
296
|
+
(og-game §13).
|
|
297
|
+
|
|
298
|
+
## 10. The gaps, named
|
|
299
|
+
|
|
300
|
+
- **ShaderMaterial and RawShaderMaterial** have no one-line counterpart.
|
|
301
|
+
A shader is an asset of `type shader` written in WGSL, compiled by the
|
|
302
|
+
cook for every back end: four hooks into the lit shader (vertex offset,
|
|
303
|
+
surface colour, normal, emissive; og-game §12) for what most
|
|
304
|
+
`onBeforeCompile` and ShaderMaterial uses do, or `mode full lit` /
|
|
305
|
+
`mode full unlit` for the whole vertex and fragment stages (og-game §23),
|
|
306
|
+
made with `og.render.shaderMaterial` and fed with
|
|
307
|
+
`og.render.setShaderParam`. A screen-space effect (an EffectComposer
|
|
308
|
+
ShaderPass) is a `type post` asset in PostEffects.custom. GLSL is
|
|
309
|
+
rewritten by hand into WGSL; uniforms become `param` lines.
|
|
310
|
+
- **InstancedMesh is not needed.** Draws are batched per geometry and
|
|
311
|
+
material: spawn one entity per instance with the same Geometry and
|
|
312
|
+
Material handles and the renderer draws them instanced, each culled and
|
|
313
|
+
shadowed on its own. `setMatrixAt(i, m)` is that entity's og.Transform
|
|
314
|
+
(`og.transform.decompose(m)`), `setColorAt` a per-entity colour through
|
|
315
|
+
`Mesh.flash` or a texture-array layer (`Mesh.materialLayer`), or one
|
|
316
|
+
material per colour. A part repeated inside one model is instanced by
|
|
317
|
+
the cook (`type model`'s `at { }` blocks).
|
|
318
|
+
- **No OrbitControls object.** Nothing takes a DOM element or listens to
|
|
319
|
+
events. The og.OrbitCamera component is the same controller as data:
|
|
320
|
+
put it on the entity to orbit, list `...og.systems.cameras` first in
|
|
321
|
+
`GameDesc.systems`, and its fields keep OrbitControls' names
|
|
322
|
+
(`target`, `minDistance`, `maxDistance`, `minPolarAngle`,
|
|
323
|
+
`maxPolarAngle`, `rotateSpeed`, `zoomSpeed`, `autoRotate`,
|
|
324
|
+
`autoRotateSpeed`, `enabled`); `controls.update()` is gone. There is no
|
|
325
|
+
damping and no panning. og.FollowCamera follows a target instead
|
|
326
|
+
(og-feel §8 covers both).
|
|
327
|
+
- **No Euler objects.** A rotation is a quaternion; Euler angles go
|
|
328
|
+
through `quat.fromEuler` once, where they are written.
|
|
329
|
+
- **No mutation helpers on values.** `vector.add(v)`, `clone()`,
|
|
330
|
+
`multiplyScalar(s)` and the other in-place methods are the pure `vec3`
|
|
331
|
+
and `quat` functions.
|
|
332
|
+
- **No dispose.** Geometries, materials and textures are handles the
|
|
333
|
+
world owns; a streaming group frees its assets when it unloads
|
|
334
|
+
(og-game §6). Drop the `dispose()` calls.
|
|
335
|
+
- **Not in the engine at all**: CSS2DRenderer and CSS3DRenderer (use
|
|
336
|
+
og.ui, or `camera.worldToScreen` for a label's position), the
|
|
337
|
+
`TransformControls` gizmos, `Line2` fat lines (`og.render.lines` has
|
|
338
|
+
`width` already), and any direct WebGL call.
|
|
339
|
+
|
|
340
|
+
## 11. `og migrate three`
|
|
341
|
+
|
|
342
|
+
```sh
|
|
343
|
+
og migrate three src/scene.ts --out src/scene.og.ts
|
|
344
|
+
og check .
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
It reads one TypeScript file that imports three.js (`import * as THREE
|
|
348
|
+
from "three"`, named imports, and the `three/addons` and
|
|
349
|
+
`three/examples/jsm` paths) and writes it back with every mechanical
|
|
350
|
+
mapping above applied:
|
|
351
|
+
|
|
352
|
+
- the three.js imports replaced by one import of `og` (and `color` or
|
|
353
|
+
`quat` when the rewrite uses them) from `@origingame/engine`, and a
|
|
354
|
+
`must` helper added when the file has none;
|
|
355
|
+
- the geometry constructors of §4 to their `og.render` calls with the
|
|
356
|
+
positional arguments named, `new THREE.Shape` and `Path` to `og.Shape`
|
|
357
|
+
and `og.Path2`;
|
|
358
|
+
- the material constructors of §5 to `og.render.standardMaterial`, hex
|
|
359
|
+
and `#rrggbb` colours through `color.fromHex`, the side constants to
|
|
360
|
+
their strings;
|
|
361
|
+
- `Vector2`, `Vector3`, `Quaternion` and `Color` constructions to plain
|
|
362
|
+
values; `MathUtils.degToRad` and `radToDeg` to arithmetic;
|
|
363
|
+
- `const x = new THREE.Mesh(g, m)`, `Group` and `Object3D` to a spawn
|
|
364
|
+
(named after the variable) with og.Mesh; the three lights to a spawn
|
|
365
|
+
with their component, a directional or spot light's `position.set`
|
|
366
|
+
also aiming it at the origin as three.js's default target does;
|
|
367
|
+
- `add` to og.Parent, the scene's `add` deleted, `remove` to
|
|
368
|
+
`world.remove` or `world.despawn`; `position.set`, `quaternion.set`,
|
|
369
|
+
`rotation.set`, `scale.set` and `setScalar` to `world.set` of
|
|
370
|
+
og.Transform; `castShadow`, `receiveShadow`, `visible`, `geometry` and
|
|
371
|
+
`material` assignments to `world.set` of the component;
|
|
372
|
+
- the camera to the og.Camera resource handle, its aspect and
|
|
373
|
+
`updateProjectionMatrix` deleted; `scene.background` to the camera's
|
|
374
|
+
background;
|
|
375
|
+
- the scene, the renderer and everything said to the renderer deleted,
|
|
376
|
+
`document.body.appendChild(renderer.domElement)` too;
|
|
377
|
+
- `TextureLoader` loads of a string to `og.load.texture` of the asset
|
|
378
|
+
id (a leading `./`, `/`, `public/` or `assets/` removed).
|
|
379
|
+
|
|
380
|
+
What is not mechanical stays as it was, under a line
|
|
381
|
+
`// og migrate: <what to do> (three-to-og §<n>)` naming the section here,
|
|
382
|
+
and is listed with its line: the render loop and the Clock (§8), the
|
|
383
|
+
glTF loader (§7), the Raycaster (§9), OrbitControls, InstancedMesh and
|
|
384
|
+
ShaderMaterial (§10), ambient and hemisphere lights (§6), Euler and
|
|
385
|
+
in-place vector arithmetic, a material or geometry parameter og does not
|
|
386
|
+
have, and a `new THREE.Mesh` that is not a declaration of its own. The
|
|
387
|
+
output is not a game yet: the rewritten calls take `world`, so move the
|
|
388
|
+
setup into `GameDesc.start(world)` and the loop into systems, then
|
|
389
|
+
`og check` until it is clean. `--write` rewrites the file in place,
|
|
390
|
+
without `--out` or `--write` the result goes to standard output, and
|
|
391
|
+
`--json` prints the list as one `migrate` event (each item's `line`,
|
|
392
|
+
`kind` of `rewritten`, `removed` or `manual`, the three.js text, what it
|
|
393
|
+
became or what to do, and the section).
|
package/knowledge/knowledge.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"about": "Where each part of @origingame/engine-knowledge lands in the platform's production tree (packages/game-knowledge/production): skills as game/skills/<name>/, the style catalogue (looks/) beside og-taste as its looks/, the generated API wiki as the og-game skill's reference/, and the project template as one scaffold overlay. `@template/` is templates/game in the engine repository and scaffold/template/ (text files, copied at prepack) in the published package.",
|
|
3
|
+
"about": "Where each part of @origingame/engine-knowledge lands in the platform's production tree (packages/game-knowledge/production): skills as game/skills/<name>/, the style catalogue (looks/) beside og-taste as its looks/, the generated API wiki as the og-game skill's reference/, the hand-written guides (guides/: three-to-og) as its guides/, and the project template as one scaffold overlay. `@template/` is templates/game in the engine repository and scaffold/template/ (text files, copied at prepack) in the published package.",
|
|
4
4
|
"overlay": "origin-engine-ts",
|
|
5
5
|
"mounts": [
|
|
6
6
|
{ "from": "skills/", "to": "game/skills/" },
|
|
7
7
|
{ "from": "looks/", "to": "game/skills/og-taste/looks/" },
|
|
8
8
|
{ "from": "wiki/", "to": "game/skills/og-game/reference/" },
|
|
9
|
+
{ "from": "guides/", "to": "game/skills/og-game/guides/" },
|
|
9
10
|
{ "from": "@template/", "to": "game-scaffold/origin-engine-ts/" },
|
|
10
11
|
{ "from": "scaffold/origin-engine.json", "to": "game-scaffold/origin-engine-ts/origin-engine.json" },
|
|
11
12
|
{ "from": "scaffold/distribution.json", "to": "game-scaffold/origin-engine-ts/distribution.json" }
|
package/knowledge/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@origingame/engine-knowledge",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Origin Engine knowledge for agents: the API wiki generated from api.ogt, the
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "Origin Engine knowledge for agents: the API wiki generated from api.ogt, the eleven og-* skills, the guides (three-to-og), the style catalogue and the project scaffold description, laid out for the OriginGame platform's knowledge packs. Not published on its own: @origingame/engine carries it as knowledge/ (docs/release.md §2).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"private": true,
|
|
7
7
|
"repository": {
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"files": [
|
|
18
18
|
"wiki",
|
|
19
19
|
"skills",
|
|
20
|
+
"guides",
|
|
20
21
|
"looks",
|
|
21
22
|
"scaffold",
|
|
22
23
|
"rules",
|
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
"substrate": "origin-engine-ts",
|
|
5
5
|
"engine": {
|
|
6
6
|
"package": "@origingame/engine",
|
|
7
|
-
"version": "0.
|
|
7
|
+
"version": "0.4.0",
|
|
8
8
|
"repository": "origingame/origin-engine"
|
|
9
9
|
},
|
|
10
10
|
"template": {
|
|
11
11
|
"source": "templates/game",
|
|
12
12
|
"create": "@origingame/create-game",
|
|
13
|
-
"version": "0.
|
|
13
|
+
"version": "0.4.0"
|
|
14
14
|
},
|
|
15
15
|
"probe": {
|
|
16
16
|
"protocol": 5,
|