@origingame/engine 0.2.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.
Files changed (118) hide show
  1. package/bin/og.mjs +1 -1
  2. package/dist/web/origin-engine.d.ts +255 -5
  3. package/dist/web/origin-engine.js +1584 -125
  4. package/dist/web/origin-engine_bg.wasm +0 -0
  5. package/dist/web/origin-engine_bg.wasm.d.ts +80 -3
  6. package/dist/web-publish/origin-engine-lanes.js +1288 -82
  7. package/dist/web-publish/origin-engine-lanes_bg.wasm +0 -0
  8. package/dist/web-publish/origin-engine.d.ts +199 -6
  9. package/dist/web-publish/origin-engine.js +1285 -79
  10. package/dist/web-publish/origin-engine_bg.wasm +0 -0
  11. package/dist/web-publish/origin-engine_bg.wasm.d.ts +65 -4
  12. package/dist/web-publish-2d/origin-engine-lanes.js +1285 -79
  13. package/dist/web-publish-2d/origin-engine-lanes_bg.wasm +0 -0
  14. package/dist/web-publish-2d/origin-engine.d.ts +198 -5
  15. package/dist/web-publish-2d/origin-engine.js +1282 -76
  16. package/dist/web-publish-2d/origin-engine_bg.wasm +0 -0
  17. package/dist/web-publish-2d/origin-engine_bg.wasm.d.ts +64 -3
  18. package/knowledge/README.md +2 -1
  19. package/knowledge/guides/three-to-og.md +393 -0
  20. package/knowledge/knowledge.json +2 -1
  21. package/knowledge/looks/catalogue.json +40 -40
  22. package/knowledge/package.json +3 -2
  23. package/knowledge/scaffold/distribution.json +14 -0
  24. package/knowledge/scaffold/origin-engine.json +2 -2
  25. package/knowledge/scaffold/template/README.md +2 -1
  26. package/knowledge/scaffold/template/assets/audio/sting.ogt +10 -0
  27. package/knowledge/scaffold/template/assets/timelines/intro.ogt +101 -0
  28. package/knowledge/scaffold/template/assets/timelines/narration.srt +11 -0
  29. package/knowledge/scaffold/template/host.d.ts +46 -0
  30. package/knowledge/scaffold/template/package.json +1 -1
  31. package/knowledge/scaffold/template/project.ogt +1 -1
  32. package/knowledge/scaffold/template/src/main.ts +1 -1
  33. package/knowledge/scaffold/template/tests/frames.ts +134 -0
  34. package/knowledge/scaffold/template/tests/intro.og.ts +65 -0
  35. package/knowledge/scaffold/template/tests/smoke.og.ts +30 -36
  36. package/knowledge/scaffold/template/tsconfig.json +1 -1
  37. package/knowledge/scripts/mount.ts +2 -1
  38. package/knowledge/scripts/validate.ts +159 -31
  39. package/knowledge/skills/og-audio/SKILL.md +2 -2
  40. package/knowledge/skills/og-build/SKILL.md +29 -7
  41. package/knowledge/skills/og-core/SKILL.md +31 -5
  42. package/knowledge/skills/og-feel/SKILL.md +2 -2
  43. package/knowledge/skills/og-game/SKILL.md +1331 -16
  44. package/knowledge/skills/og-i18n/SKILL.md +7 -7
  45. package/knowledge/skills/og-model/SKILL.md +374 -0
  46. package/knowledge/skills/og-platform-sdk/SKILL.md +2 -1
  47. package/knowledge/skills/og-taste/SKILL.md +82 -73
  48. package/knowledge/skills/og-ui/SKILL.md +80 -58
  49. package/knowledge/wiki/ai.md +20 -20
  50. package/knowledge/wiki/anim.md +392 -41
  51. package/knowledge/wiki/atmosphere.md +36 -13
  52. package/knowledge/wiki/audio.md +18 -18
  53. package/knowledge/wiki/camera.md +19 -13
  54. package/knowledge/wiki/commands.md +19 -13
  55. package/knowledge/wiki/debug.md +414 -0
  56. package/knowledge/wiki/game.md +8 -8
  57. package/knowledge/wiki/i18n.md +7 -7
  58. package/knowledge/wiki/index.md +317 -8
  59. package/knowledge/wiki/input.md +47 -47
  60. package/knowledge/wiki/load.md +238 -70
  61. package/knowledge/wiki/math.md +2607 -0
  62. package/knowledge/wiki/nav.md +34 -34
  63. package/knowledge/wiki/net.md +340 -0
  64. package/knowledge/wiki/path.md +402 -0
  65. package/knowledge/wiki/physics.md +95 -95
  66. package/knowledge/wiki/platform.md +463 -29
  67. package/knowledge/wiki/probe.md +681 -67
  68. package/knowledge/wiki/reflect.md +29 -17
  69. package/knowledge/wiki/render.md +4993 -1998
  70. package/knowledge/wiki/rng.md +14 -14
  71. package/knowledge/wiki/shapes.md +727 -0
  72. package/knowledge/wiki/stream.md +15 -15
  73. package/knowledge/wiki/system.md +8 -8
  74. package/knowledge/wiki/systems.md +2 -2
  75. package/knowledge/wiki/terrain.md +24 -20
  76. package/knowledge/wiki/tilemap.md +13 -13
  77. package/knowledge/wiki/time.md +4 -4
  78. package/knowledge/wiki/timeline.md +396 -0
  79. package/knowledge/wiki/transform.md +8 -8
  80. package/knowledge/wiki/tween.md +17 -17
  81. package/knowledge/wiki/ui.md +560 -654
  82. package/knowledge/wiki/video.md +157 -0
  83. package/knowledge/wiki/world.md +36 -36
  84. package/package.json +4 -3
  85. package/schema/api.schema.json +28151 -19640
  86. package/shell/page.ts +26 -2
  87. package/shell/platform.ts +51 -0
  88. package/shell/player.ts +15 -2
  89. package/shell/transport.ts +6 -0
  90. package/src/depth.ts +71 -0
  91. package/src/e6.ts +32 -1
  92. package/src/env.d.ts +5 -1
  93. package/src/generated/abi.ts +226 -4
  94. package/src/geom.ts +260 -0
  95. package/src/index.ts +32 -4
  96. package/src/light.ts +18 -0
  97. package/src/math.ts +622 -0
  98. package/src/node/index.ts +17 -0
  99. package/src/node/playtest-run.ts +115 -18
  100. package/src/node/polish.ts +13 -3
  101. package/src/node/render.ts +291 -0
  102. package/src/node/run.ts +86 -5
  103. package/src/p2.ts +19 -1
  104. package/src/platform-local.ts +2 -0
  105. package/src/playtest.ts +65 -4
  106. package/src/runtime.ts +100 -9
  107. package/src/targets.ts +28 -0
  108. package/src/trace.ts +169 -0
  109. package/src/ui-kit/huds.ts +34 -34
  110. package/src/ui-kit/menus.ts +12 -12
  111. package/src/ui-kit/settings.ts +11 -2
  112. package/src/ui-kit/store.ts +18 -18
  113. package/src/ui-kit/story.ts +6 -4
  114. package/src/ui-kit/util.ts +8 -8
  115. package/src/web/shell.ts +59 -1
  116. package/src/web/worker.ts +105 -4
  117. package/types/bindings.json +9368 -6619
  118. package/types/index.d.ts +16377 -11520
@@ -29,7 +29,7 @@ export interface HostAbi<A, V> {
29
29
  og_engine_take_log(engine: number): string;
30
30
  /** Write some fields of a resource as JSON: the runtime's path for a write a publish build refuses (logged once per system). A Result. */
31
31
  og_engine_write_resource(world: number, resource: string, value: string): string;
32
- /** A resource's packed layout, how the runtime reads and writes its fields as bytes: a Result of `{ epoch, size, fields: [{ name, kind, offset, size, readonly, capacity, variants }] }` (`kind`: f32, f64, u32, i32, bool, Vector2, Vector3, Quaternion, Color, Matrix4, handle, str, enum). Refused for og.Time, og.Rng and og.Input, whose handles are computed, and for what is not a registered resource. */
32
+ /** A resource's packed layout, how the runtime reads and writes its fields as bytes: a Result of `{ epoch, size, fields: [{ name, kind, offset, size, readonly, capacity, variants, element }] }` (`kind`: f32, f64, u32, i32, bool, Vector2, Vector3, Quaternion, Color, Matrix4, handle, str, enum, or list: `element` one of f32, f64, u32, i32, handle and `capacity` its elements, a count lane first, each lane the element's size). Refused for og.Time, og.Rng and og.Input, whose handles are computed, and for what is not a registered resource. */
33
33
  og_engine_resource_layout(world: number, resource: string): string;
34
34
  /** A resource's packed bytes, then the layout epoch as a little-endian u32 (it moves when any layout is declared again: a new engine, a reload). Empty when refused (undeclared in the running system, not a resource): the runtime then asks og_world_resource for the reason. */
35
35
  og_engine_read_resource(world: number, resource: string): Uint8Array;
@@ -41,6 +41,12 @@ export interface HostAbi<A, V> {
41
41
  og_platform_answer(engine: number, request: number, answer: string): boolean;
42
42
  /** Say what answers this engine's platform calls: JSON `{ host, capabilities }` (`player`, `local` or `none`; the methods it answers), as og.platform.info reports. */
43
43
  og_platform_set_host(engine: number, info: string): void;
44
+ /** The room ops (IDL `platform` rooms, og.net's lockstep) made since the last call, oldest first, as JSON `[op]`: `{ op: "create", name, capacity }`, `{ op: "join", room, name }`, `{ op: "leave" }`, `{ op: "send", to?, channel?, data? | bytes? }` (bytes base64; a channel starting `og.` is the engine's own). The host carries each in order (docs/design.md §2.8). */
45
+ og_room_take(engine: number): string;
46
+ /** One room event from the host, JSON: `{ type: "joined", room, peer, peers: [{ peer, name }] }`, `{ type: "peer_joined", peer, name }`, `{ type: "peer_left", peer }`, `{ type: "message", from, channel?, data? | bytes? }`, `{ type: "left", reason }` or `{ type: "error", op, code, message }`. Lockstep's messages act between ticks at once; the game's events are sent at the start of the next tick. False for a malformed event. */
47
+ og_room_deliver(engine: number, event: string): boolean;
48
+ /** Say what carries this engine's rooms: JSON `{ host, join? }` (`relay`, `player` or `none`), as og.platform.roomInfo reports; with `none` roomCreate and roomJoin are refused. `join` is the room a Play link named (`?room=<id>`): the engine joins it once, itself, and og.RoomJoined answers. */
49
+ og_room_set_host(engine: number, info: string): void;
44
50
  /** `defineComponent` */
45
51
  og_reflect_define_component(name: string, fields: string): string;
46
52
  /** `defineResource` */
@@ -221,12 +227,70 @@ export interface HostAbi<A, V> {
221
227
  og_render_set_shader_param(world: number, material: number, name: string, value: string): string;
222
228
  /** `og.render.applyLook` */
223
229
  og_render_apply_look(world: number, look: number): string;
230
+ /** `og.render.applyQuality` */
231
+ og_render_apply_quality(world: number, preset: string): string;
224
232
  /** `og.render.look` */
225
233
  og_render_look(world: number): string;
226
234
  /** `og.render.capabilities` */
227
235
  og_render_capabilities(world: number): string;
228
236
  /** `og.render.text` */
229
237
  og_render_text(world: number, desc: string | undefined): string;
238
+ /** `og.render.bufferGeometry` */
239
+ og_render_buffer_geometry(world: number, desc: string | undefined): string;
240
+ /** `og.render.updateGeometry` */
241
+ og_render_update_geometry(world: number, geometry: number, desc: string | undefined): string;
242
+ /** `og.render.geometryInfo` */
243
+ og_render_geometry_info(world: number, geometry: number): string;
244
+ /** `og.render.cylinderGeometry` */
245
+ og_render_cylinder_geometry(world: number, desc: string | undefined): string;
246
+ /** `og.render.coneGeometry` */
247
+ og_render_cone_geometry(world: number, desc: string | undefined): string;
248
+ /** `og.render.capsuleGeometry` */
249
+ og_render_capsule_geometry(world: number, desc: string | undefined): string;
250
+ /** `og.render.torusGeometry` */
251
+ og_render_torus_geometry(world: number, desc: string | undefined): string;
252
+ /** `og.render.ringGeometry` */
253
+ og_render_ring_geometry(world: number, desc: string | undefined): string;
254
+ /** `og.render.circleGeometry` */
255
+ og_render_circle_geometry(world: number, desc: string | undefined): string;
256
+ /** `og.render.tubeGeometry` */
257
+ og_render_tube_geometry(world: number, desc: string | undefined): string;
258
+ /** `og.render.shapeGeometry` */
259
+ og_render_shape_geometry(world: number, desc: string | undefined): string;
260
+ /** `og.render.extrudeGeometry` */
261
+ og_render_extrude_geometry(world: number, desc: string | undefined): string;
262
+ /** `og.render.latheGeometry` */
263
+ og_render_lathe_geometry(world: number, desc: string | undefined): string;
264
+ /** `og.render.polyhedronGeometry` */
265
+ og_render_polyhedron_geometry(world: number, desc: string | undefined): string;
266
+ /** `og.render.icosahedronGeometry` */
267
+ og_render_icosahedron_geometry(world: number, desc: string | undefined): string;
268
+ /** `og.render.dodecahedronGeometry` */
269
+ og_render_dodecahedron_geometry(world: number, desc: string | undefined): string;
270
+ /** `og.render.octahedronGeometry` */
271
+ og_render_octahedron_geometry(world: number, desc: string | undefined): string;
272
+ /** `og.render.tetrahedronGeometry` */
273
+ og_render_tetrahedron_geometry(world: number, desc: string | undefined): string;
274
+ /** `og.render.sweepGeometry` */
275
+ og_render_sweep_geometry(world: number, desc: string | undefined): string;
276
+ /** `og.render.csgGeometry` */
277
+ og_render_csg_geometry(world: number, desc: string | undefined): string;
278
+ /** `og.render.mergeGeometries` */
279
+ og_render_merge_geometries(world: number, desc: string | undefined): string;
280
+ /** `og.render.lines` */
281
+ og_render_lines(world: number, desc: string | undefined): string;
282
+ /** `og.render.points` */
283
+ og_render_points(world: number, desc: string | undefined): string;
284
+ /** `og.render.raycast` */
285
+ og_render_raycast(world: number, ray: string, desc: string | undefined): string;
286
+ /** `og.render.renderTarget` */
287
+ og_render_render_target(world: number, desc: string | undefined): string;
288
+ /** `og.render.setPostParam` */
289
+ og_render_set_post_param(world: number, post: number, name: string, value: string): string;
290
+ /** `og.render.postErrors` */
291
+ og_render_post_errors(world: number): string;
292
+ /** `og.render.bakedLighting` */
293
+ og_render_baked_lighting(world: number): string;
230
294
  /** `og.load.bundle` */
231
295
  og_load_bundle(world: number, path: string): string;
232
296
  /** `og.load.bundleInfo` */
@@ -251,12 +315,14 @@ export interface HostAbi<A, V> {
251
315
  og_load_emitter(world: number, path: string): string;
252
316
  /** `og.load.shader` */
253
317
  og_load_shader(world: number, path: string): string;
318
+ /** `og.load.post` */
319
+ og_load_post(world: number, path: string): string;
254
320
  /** `og.load.texture` */
255
321
  og_load_texture(world: number, path: string): string;
256
322
  /** `og.load.textureArray` */
257
323
  og_load_texture_array(world: number, path: string): string;
258
- /** `og.load.skin` */
259
- og_load_skin(world: number, path: string): string;
324
+ /** `og.load.style` */
325
+ og_load_style(world: number, path: string): string;
260
326
  /** `og.load.look` */
261
327
  og_load_look(world: number, path: string): string;
262
328
  /** `og.load.lookInfo` */
@@ -279,6 +345,14 @@ export interface HostAbi<A, V> {
279
345
  og_load_flipbook(world: number, path: string): string;
280
346
  /** `og.load.tilemap` */
281
347
  og_load_tilemap(world: number, path: string): string;
348
+ /** `og.load.video` */
349
+ og_load_video(world: number, path: string): string;
350
+ /** `og.load.videoInfo` */
351
+ og_load_video_info(world: number, video: number): string;
352
+ /** `og.load.timeline` */
353
+ og_load_timeline(world: number, path: string): string;
354
+ /** `og.load.rig2d` */
355
+ og_load_rig2d(world: number, path: string): string;
282
356
  /** `og.physics.raycast` */
283
357
  og_physics_raycast(world: number, desc: string | undefined): string;
284
358
  /** `og.physics.shapeCast` */
@@ -323,6 +397,10 @@ export interface HostAbi<A, V> {
323
397
  og_anim_humanoid(world: number, desc: string | undefined): string;
324
398
  /** `og.anim.retarget` */
325
399
  og_anim_retarget(world: number, desc: string | undefined): string;
400
+ /** `og.anim.rig2dInfo` */
401
+ og_anim_rig2d_info(world: number, rig: number): string;
402
+ /** `og.anim.skeleton2dBoxes` */
403
+ og_anim_skeleton2d_boxes(world: number, entity: number): string;
326
404
  /** `og.tween.to` */
327
405
  og_tween_to(world: number, desc: string | undefined): string;
328
406
  /** `og.tween.sequence` */
@@ -421,6 +499,20 @@ export interface HostAbi<A, V> {
421
499
  og_platform_info(world: number): string;
422
500
  /** `og.platform.now` */
423
501
  og_platform_now(world: number): number;
502
+ /** `og.platform.roomCreate` */
503
+ og_platform_room_create(world: number, desc: string | undefined): string;
504
+ /** `og.platform.roomJoin` */
505
+ og_platform_room_join(world: number, room: string): string;
506
+ /** `og.platform.roomLeave` */
507
+ og_platform_room_leave(world: number): string;
508
+ /** `og.platform.roomSend` */
509
+ og_platform_room_send(world: number, data: string, to: number | undefined): string;
510
+ /** `og.platform.roomPeers` */
511
+ og_platform_room_peers(world: number): string;
512
+ /** `og.platform.roomInfo` */
513
+ og_platform_room_info(world: number): string;
514
+ /** `og.platform.roomMessage` */
515
+ og_platform_room_message(world: number, message: number): string;
424
516
  /** `og.i18n.load` */
425
517
  og_i18n_load(world: number, path: string): string;
426
518
  /** `og.i18n.setLocale` */
@@ -629,6 +721,14 @@ export interface HostAbi<A, V> {
629
721
  og_engine_probe_listen(engine_probe: number, seconds: number | undefined): string;
630
722
  /** `EngineProbe.memory` */
631
723
  og_engine_probe_memory(engine_probe: number): string;
724
+ /** `EngineProbe.describe` */
725
+ og_engine_probe_describe(engine_probe: number): string;
726
+ /** `EngineProbe.expect` */
727
+ og_engine_probe_expect(engine_probe: number, what: string): string;
728
+ /** `EngineProbe.expectations` */
729
+ og_engine_probe_expectations(engine_probe: number): string;
730
+ /** `EngineProbe.saveScene` */
731
+ og_engine_probe_save_scene(engine_probe: number, write: boolean | undefined, spawned: boolean | undefined): string;
632
732
  /** `og.terrain.load` */
633
733
  og_terrain_load(world: number, path: string): string;
634
734
  /** `og.terrain.sample` */
@@ -651,6 +751,54 @@ export interface HostAbi<A, V> {
651
751
  og_stream_budget(world: number): string;
652
752
  /** `og.stream.setBudget` */
653
753
  og_stream_set_budget(world: number, bytes: number): string;
754
+ /** `og.debug.line` */
755
+ og_debug_line(world: number, from: string, to: string, desc: string | undefined): void;
756
+ /** `og.debug.box` */
757
+ og_debug_box(world: number, center: string, size: string, desc: string | undefined): void;
758
+ /** `og.debug.sphere` */
759
+ og_debug_sphere(world: number, center: string, radius: number, desc: string | undefined): void;
760
+ /** `og.debug.arrow` */
761
+ og_debug_arrow(world: number, from: string, to: string, desc: string | undefined): void;
762
+ /** `og.debug.axes` */
763
+ og_debug_axes(world: number, position: string, size: number, desc: string | undefined): void;
764
+ /** `og.debug.text` */
765
+ og_debug_text(world: number, position: string, text: string, desc: string | undefined): void;
766
+ /** `og.debug.clear` */
767
+ og_debug_clear(world: number): void;
768
+ /** `og.debug.setView` */
769
+ og_debug_set_view(world: number, view: string): void;
770
+ /** `og.debug.view` */
771
+ og_debug_view(world: number): string;
772
+ /** `og.debug.setEnabled` */
773
+ og_debug_set_enabled(world: number, enabled: boolean): void;
774
+ /** `og.debug.enabled` */
775
+ og_debug_enabled(world: number): boolean;
776
+ /** `og.path.create` */
777
+ og_path_create(world: number, desc: string | undefined): string;
778
+ /** `og.path.find` */
779
+ og_path_find(world: number, name: string): string;
780
+ /** `og.path.sample` */
781
+ og_path_sample(world: number, path: number, t: number): string;
782
+ /** `og.path.length` */
783
+ og_path_length(world: number, path: number): string;
784
+ /** `og.path.nearest` */
785
+ og_path_nearest(world: number, path: number, point: string): string;
786
+ /** `og.timeline.info` */
787
+ og_timeline_info(world: number, asset: number): string;
788
+ /** `og.timeline.play` */
789
+ og_timeline_play(world: number, entity: number): string;
790
+ /** `og.timeline.pause` */
791
+ og_timeline_pause(world: number, entity: number): string;
792
+ /** `og.timeline.seek` */
793
+ og_timeline_seek(world: number, entity: number, time: number): string;
794
+ /** `og.timeline.stop` */
795
+ og_timeline_stop(world: number, entity: number): string;
796
+ /** `og.net.submit` */
797
+ og_net_submit(world: number, input: string | undefined): string;
798
+ /** `og.net.status` */
799
+ og_net_status(world: number): string;
800
+ /** `og.net.hash` */
801
+ og_net_hash(world: number): string;
654
802
  }
655
803
 
656
804
  /** Every binding symbol, in binding-table order, then the lifecycle members. */
@@ -745,9 +893,38 @@ export const SYMBOLS: readonly string[] = [
745
893
  "og_render_set_material_shader",
746
894
  "og_render_set_shader_param",
747
895
  "og_render_apply_look",
896
+ "og_render_apply_quality",
748
897
  "og_render_look",
749
898
  "og_render_capabilities",
750
899
  "og_render_text",
900
+ "og_render_buffer_geometry",
901
+ "og_render_update_geometry",
902
+ "og_render_geometry_info",
903
+ "og_render_cylinder_geometry",
904
+ "og_render_cone_geometry",
905
+ "og_render_capsule_geometry",
906
+ "og_render_torus_geometry",
907
+ "og_render_ring_geometry",
908
+ "og_render_circle_geometry",
909
+ "og_render_tube_geometry",
910
+ "og_render_shape_geometry",
911
+ "og_render_extrude_geometry",
912
+ "og_render_lathe_geometry",
913
+ "og_render_polyhedron_geometry",
914
+ "og_render_icosahedron_geometry",
915
+ "og_render_dodecahedron_geometry",
916
+ "og_render_octahedron_geometry",
917
+ "og_render_tetrahedron_geometry",
918
+ "og_render_sweep_geometry",
919
+ "og_render_csg_geometry",
920
+ "og_render_merge_geometries",
921
+ "og_render_lines",
922
+ "og_render_points",
923
+ "og_render_raycast",
924
+ "og_render_render_target",
925
+ "og_render_set_post_param",
926
+ "og_render_post_errors",
927
+ "og_render_baked_lighting",
751
928
  "og_load_bundle",
752
929
  "og_load_bundle_info",
753
930
  "og_load_default_bundle",
@@ -760,9 +937,10 @@ export const SYMBOLS: readonly string[] = [
760
937
  "og_load_environment",
761
938
  "og_load_emitter",
762
939
  "og_load_shader",
940
+ "og_load_post",
763
941
  "og_load_texture",
764
942
  "og_load_texture_array",
765
- "og_load_skin",
943
+ "og_load_style",
766
944
  "og_load_look",
767
945
  "og_load_look_info",
768
946
  "og_load_palette",
@@ -774,6 +952,10 @@ export const SYMBOLS: readonly string[] = [
774
952
  "og_load_rig",
775
953
  "og_load_flipbook",
776
954
  "og_load_tilemap",
955
+ "og_load_video",
956
+ "og_load_video_info",
957
+ "og_load_timeline",
958
+ "og_load_rig2d",
777
959
  "og_physics_raycast",
778
960
  "og_physics_shape_cast",
779
961
  "og_physics_overlap",
@@ -796,6 +978,8 @@ export const SYMBOLS: readonly string[] = [
796
978
  "og_anim_graph",
797
979
  "og_anim_humanoid",
798
980
  "og_anim_retarget",
981
+ "og_anim_rig2d_info",
982
+ "og_anim_skeleton2d_boxes",
799
983
  "og_tween_to",
800
984
  "og_tween_sequence",
801
985
  "og_tween_parallel",
@@ -845,6 +1029,13 @@ export const SYMBOLS: readonly string[] = [
845
1029
  "og_platform_result",
846
1030
  "og_platform_info",
847
1031
  "og_platform_now",
1032
+ "og_platform_room_create",
1033
+ "og_platform_room_join",
1034
+ "og_platform_room_leave",
1035
+ "og_platform_room_send",
1036
+ "og_platform_room_peers",
1037
+ "og_platform_room_info",
1038
+ "og_platform_room_message",
848
1039
  "og_i18n_load",
849
1040
  "og_i18n_set_locale",
850
1041
  "og_i18n_locale",
@@ -949,6 +1140,10 @@ export const SYMBOLS: readonly string[] = [
949
1140
  "og_engine_probe_commands",
950
1141
  "og_engine_probe_listen",
951
1142
  "og_engine_probe_memory",
1143
+ "og_engine_probe_describe",
1144
+ "og_engine_probe_expect",
1145
+ "og_engine_probe_expectations",
1146
+ "og_engine_probe_save_scene",
952
1147
  "og_terrain_load",
953
1148
  "og_terrain_sample",
954
1149
  "og_terrain_bounds",
@@ -960,6 +1155,30 @@ export const SYMBOLS: readonly string[] = [
960
1155
  "og_stream_release",
961
1156
  "og_stream_budget",
962
1157
  "og_stream_set_budget",
1158
+ "og_debug_line",
1159
+ "og_debug_box",
1160
+ "og_debug_sphere",
1161
+ "og_debug_arrow",
1162
+ "og_debug_axes",
1163
+ "og_debug_text",
1164
+ "og_debug_clear",
1165
+ "og_debug_set_view",
1166
+ "og_debug_view",
1167
+ "og_debug_set_enabled",
1168
+ "og_debug_enabled",
1169
+ "og_path_create",
1170
+ "og_path_find",
1171
+ "og_path_sample",
1172
+ "og_path_length",
1173
+ "og_path_nearest",
1174
+ "og_timeline_info",
1175
+ "og_timeline_play",
1176
+ "og_timeline_pause",
1177
+ "og_timeline_seek",
1178
+ "og_timeline_stop",
1179
+ "og_net_submit",
1180
+ "og_net_status",
1181
+ "og_net_hash",
963
1182
  "og_host_set_dispatcher",
964
1183
  "og_engine_create",
965
1184
  "og_engine_destroy",
@@ -977,4 +1196,7 @@ export const SYMBOLS: readonly string[] = [
977
1196
  "og_platform_take",
978
1197
  "og_platform_answer",
979
1198
  "og_platform_set_host",
1199
+ "og_room_take",
1200
+ "og_room_deliver",
1201
+ "og_room_set_host",
980
1202
  ];
package/src/geom.ts ADDED
@@ -0,0 +1,260 @@
1
+ // Procedural modelling (IDL `shapes` and the og-geom members of `render`):
2
+ // og.Shape and og.Path2, three.js's Shape and Path with its methods and its
3
+ // curve formulas, and the render calls that take them. A shape never
4
+ // crosses the wire: it is flattened to points here (three.js's
5
+ // extractPoints(curveSegments)), so og-geom triangulates the same points
6
+ // three.js would.
7
+ //
8
+ // Determinism: the points may end up in world state through the geometry
9
+ // made from them, so the arcs read sincos (basic arithmetic, the camera
10
+ // systems' series), never Math.sin or Math.cos.
11
+
12
+ import type * as Api from "@origingame/engine";
13
+ import type { HostAbi } from "./generated/abi.ts";
14
+ import { boundHost } from "./runtime.ts";
15
+ import { sincos } from "./systems/cameras.ts";
16
+
17
+ type V2 = { x: number; y: number };
18
+ type W = { readonly id: number };
19
+
20
+ const TAU = 2 * 3.141592653589793;
21
+ const EPSILON = 2.220446049250313e-16;
22
+ const v2 = (x: number, y: number): V2 => ({ x, y });
23
+ const equals = (a: V2, b: V2) => a.x === b.x && a.y === b.y;
24
+
25
+ // three.js's Interpolations.
26
+ function catmullRom(t: number, p0: number, p1: number, p2: number, p3: number): number {
27
+ const v0 = (p2 - p0) * 0.5;
28
+ const v1 = (p3 - p1) * 0.5;
29
+ const t2 = t * t;
30
+ const t3 = t * t2;
31
+ return (2 * p1 - 2 * p2 + v0 + v1) * t3 + (-3 * p1 + 3 * p2 - 2 * v0 - v1) * t2 + v0 * t + p1;
32
+ }
33
+ function quadratic(t: number, p0: number, p1: number, p2: number): number {
34
+ const k = 1 - t;
35
+ return k * k * p0 + 2 * (1 - t) * t * p1 + t * t * p2;
36
+ }
37
+ function cubic(t: number, p0: number, p1: number, p2: number, p3: number): number {
38
+ const k = 1 - t;
39
+ return k * k * k * p0 + 3 * k * k * t * p1 + 3 * (1 - t) * t * t * p2 + t * t * t * p3;
40
+ }
41
+
42
+ /** One of three.js's 2D curves, by its getPoint(t) and how finely CurvePath.getPoints divides it. */
43
+ interface Curve {
44
+ point(t: number): V2;
45
+ resolution(divisions: number): number;
46
+ }
47
+
48
+ const line = (a: V2, b: V2): Curve => ({
49
+ // three.js LineCurve.getPoint: the end exactly at 1.
50
+ point: (t) => (t === 1 ? v2(b.x, b.y) : v2((b.x - a.x) * t + a.x, (b.y - a.y) * t + a.y)),
51
+ resolution: () => 1,
52
+ });
53
+
54
+ const quadraticCurve = (a: V2, c: V2, b: V2): Curve => ({
55
+ point: (t) => v2(quadratic(t, a.x, c.x, b.x), quadratic(t, a.y, c.y, b.y)),
56
+ resolution: (d) => d,
57
+ });
58
+
59
+ const cubicCurve = (a: V2, c1: V2, c2: V2, b: V2): Curve => ({
60
+ point: (t) => v2(cubic(t, a.x, c1.x, c2.x, b.x), cubic(t, a.y, c1.y, c2.y, b.y)),
61
+ resolution: (d) => d,
62
+ });
63
+
64
+ function splineCurve(points: readonly V2[]): Curve {
65
+ return {
66
+ point: (t) => {
67
+ const p = (points.length - 1) * t;
68
+ const i = Math.floor(p);
69
+ const w = p - i;
70
+ const p0 = points[i === 0 ? i : i - 1]!;
71
+ const p1 = points[i]!;
72
+ const p2 = points[i > points.length - 2 ? points.length - 1 : i + 1]!;
73
+ const p3 = points[i > points.length - 3 ? points.length - 1 : i + 2]!;
74
+ return v2(catmullRom(w, p0.x, p1.x, p2.x, p3.x), catmullRom(w, p0.y, p1.y, p2.y, p3.y));
75
+ },
76
+ resolution: (d) => d * points.length,
77
+ };
78
+ }
79
+
80
+ function ellipseCurve(x: number, y: number, rx: number, ry: number, start: number, end: number, clockwise: boolean, rotation: number): Curve {
81
+ return {
82
+ point: (t) => {
83
+ let delta = end - start;
84
+ const same = Math.abs(delta) < EPSILON;
85
+ while (delta < 0) delta += TAU;
86
+ while (delta > TAU) delta -= TAU;
87
+ if (delta < EPSILON) delta = same ? 0 : TAU;
88
+ if (clockwise && !same) delta = delta === TAU ? -TAU : delta - TAU;
89
+ const [s, c] = sincos(start + t * delta);
90
+ let px = x + rx * c;
91
+ let py = y + ry * s;
92
+ if (rotation !== 0) {
93
+ const [rs, rc] = sincos(rotation);
94
+ const tx = px - x;
95
+ const ty = py - y;
96
+ px = tx * rc - ty * rs + x;
97
+ py = tx * rs + ty * rc + y;
98
+ }
99
+ return v2(px, py);
100
+ },
101
+ resolution: (d) => d * 2,
102
+ };
103
+ }
104
+
105
+ const point = (p: Api.Vector2): V2 => v2(p.x, p.y);
106
+
107
+ /** three.js's Path: curves from a current point. */
108
+ export class Path2 {
109
+ #curves: Curve[] = [];
110
+ #current: V2 = v2(0, 0);
111
+
112
+ constructor(points?: readonly Api.Vector2[] | null) {
113
+ if (points) this.setFromPoints(points);
114
+ }
115
+
116
+ setFromPoints(points: readonly Api.Vector2[]): this {
117
+ if (points.length === 0) return this;
118
+ this.moveTo(points[0]!.x, points[0]!.y);
119
+ for (let i = 1; i < points.length; i++) this.lineTo(points[i]!.x, points[i]!.y);
120
+ return this;
121
+ }
122
+
123
+ moveTo(x: number, y: number): this {
124
+ this.#current = v2(x, y);
125
+ return this;
126
+ }
127
+
128
+ lineTo(x: number, y: number): this {
129
+ this.#curves.push(line(this.#current, v2(x, y)));
130
+ this.#current = v2(x, y);
131
+ return this;
132
+ }
133
+
134
+ quadraticCurveTo(cpX: number, cpY: number, x: number, y: number): this {
135
+ this.#curves.push(quadraticCurve(this.#current, v2(cpX, cpY), v2(x, y)));
136
+ this.#current = v2(x, y);
137
+ return this;
138
+ }
139
+
140
+ bezierCurveTo(cp1X: number, cp1Y: number, cp2X: number, cp2Y: number, x: number, y: number): this {
141
+ this.#curves.push(cubicCurve(this.#current, v2(cp1X, cp1Y), v2(cp2X, cp2Y), v2(x, y)));
142
+ this.#current = v2(x, y);
143
+ return this;
144
+ }
145
+
146
+ splineThru(points: readonly Api.Vector2[]): this {
147
+ if (points.length === 0) return this;
148
+ this.#curves.push(splineCurve([this.#current, ...points.map(point)]));
149
+ this.#current = point(points[points.length - 1]!);
150
+ return this;
151
+ }
152
+
153
+ arc(x: number, y: number, radius: number, startAngle: number, endAngle: number, clockwise = false): this {
154
+ return this.absarc(x + this.#current.x, y + this.#current.y, radius, startAngle, endAngle, clockwise);
155
+ }
156
+
157
+ absarc(x: number, y: number, radius: number, startAngle: number, endAngle: number, clockwise = false): this {
158
+ return this.absellipse(x, y, radius, radius, startAngle, endAngle, clockwise);
159
+ }
160
+
161
+ ellipse(x: number, y: number, xRadius: number, yRadius: number, startAngle: number, endAngle: number, clockwise = false, rotation = 0): this {
162
+ return this.absellipse(x + this.#current.x, y + this.#current.y, xRadius, yRadius, startAngle, endAngle, clockwise, rotation);
163
+ }
164
+
165
+ absellipse(x: number, y: number, xRadius: number, yRadius: number, startAngle: number, endAngle: number, clockwise = false, rotation = 0): this {
166
+ const curve = ellipseCurve(x, y, xRadius, yRadius, startAngle, endAngle, clockwise, rotation);
167
+ if (this.#curves.length > 0) {
168
+ // A previous curve: join it with a line when the arc starts elsewhere.
169
+ const first = curve.point(0);
170
+ if (!equals(first, this.#current)) this.lineTo(first.x, first.y);
171
+ }
172
+ this.#curves.push(curve);
173
+ this.#current = curve.point(1);
174
+ return this;
175
+ }
176
+
177
+ closePath(): this {
178
+ if (this.#curves.length === 0) return this;
179
+ const start = this.#curves[0]!.point(0);
180
+ const end = this.#curves[this.#curves.length - 1]!.point(1);
181
+ if (!equals(start, end)) this.#curves.push(line(end, start));
182
+ return this;
183
+ }
184
+
185
+ getPoints(divisions = 12): Api.Vector2[] {
186
+ const out: V2[] = [];
187
+ let last: V2 | undefined;
188
+ for (const curve of this.#curves) {
189
+ const resolution = curve.resolution(divisions);
190
+ for (let d = 0; d <= resolution; d++) {
191
+ const p = curve.point(d / resolution);
192
+ if (last && equals(last, p)) continue;
193
+ out.push(p);
194
+ last = p;
195
+ }
196
+ }
197
+ return out;
198
+ }
199
+ }
200
+
201
+ /** three.js's Shape: a path with holes. */
202
+ export class Shape extends Path2 {
203
+ readonly holes: Path2[] = [];
204
+
205
+ extractPoints(divisions = 12): Api.ShapePoints {
206
+ return { shape: this.getPoints(divisions), holes: this.holes.map((h) => h.getPoints(divisions)) };
207
+ }
208
+ }
209
+
210
+ // ── the render calls ────────────────────────────────────────────────────────
211
+
212
+ function abi(): HostAbi<Uint32Array, unknown> {
213
+ const h = boundHost();
214
+ if (!h) throw new Error("no engine host is loaded: start the game through @origingame/engine's web or node loader");
215
+ return h.abi;
216
+ }
217
+
218
+ const parse = <T>(text: string): T => JSON.parse(text) as T;
219
+ const json = (value: unknown): string | undefined => (value === undefined ? undefined : JSON.stringify(value));
220
+
221
+ type Desc = Record<string, unknown>;
222
+
223
+ /** A shape as it crosses: its points and its holes' points. */
224
+ function flat(s: Path2, divisions: number): Api.ShapePoints {
225
+ return s instanceof Shape ? s.extractPoints(divisions) : { shape: s.getPoints(divisions), holes: [] };
226
+ }
227
+
228
+ /** `shapes` (a Shape, a list of them, or the outline's points) as points. */
229
+ function shapes(desc: unknown): string | undefined {
230
+ if (desc === undefined || desc === null || typeof desc !== "object") return json(desc);
231
+ const d: Desc = { ...(desc as Desc) };
232
+ const divisions = typeof d.curveSegments === "number" ? d.curveSegments : 12;
233
+ const v = d.shapes;
234
+ if (v instanceof Path2) d.shapes = [flat(v, divisions)];
235
+ else if (Array.isArray(v) && v.length > 0 && v[0] instanceof Path2) d.shapes = (v as Path2[]).map((s) => flat(s, divisions));
236
+ return JSON.stringify(d);
237
+ }
238
+
239
+ /** A sweep's `section`: a Shape or Path2 flattened, its holes dropped. */
240
+ function section(desc: unknown): string | undefined {
241
+ if (desc === undefined || desc === null || typeof desc !== "object") return json(desc);
242
+ const d: Desc = { ...(desc as Desc) };
243
+ const divisions = typeof d.curveSegments === "number" ? d.curveSegments : 12;
244
+ if (d.section instanceof Path2) d.section = d.section.getPoints(divisions);
245
+ return JSON.stringify(d);
246
+ }
247
+
248
+ export const geomRender = Object.freeze({
249
+ shapeGeometry: (world: W, desc?: unknown) => parse(abi().og_render_shape_geometry(world.id, shapes(desc))),
250
+ extrudeGeometry: (world: W, desc?: unknown) => parse(abi().og_render_extrude_geometry(world.id, shapes(desc))),
251
+ latheGeometry: (world: W, desc?: unknown) => parse(abi().og_render_lathe_geometry(world.id, json(desc))),
252
+ polyhedronGeometry: (world: W, desc?: unknown) => parse(abi().og_render_polyhedron_geometry(world.id, json(desc))),
253
+ icosahedronGeometry: (world: W, desc?: unknown) => parse(abi().og_render_icosahedron_geometry(world.id, json(desc))),
254
+ dodecahedronGeometry: (world: W, desc?: unknown) => parse(abi().og_render_dodecahedron_geometry(world.id, json(desc))),
255
+ octahedronGeometry: (world: W, desc?: unknown) => parse(abi().og_render_octahedron_geometry(world.id, json(desc))),
256
+ tetrahedronGeometry: (world: W, desc?: unknown) => parse(abi().og_render_tetrahedron_geometry(world.id, json(desc))),
257
+ sweepGeometry: (world: W, desc?: unknown) => parse(abi().og_render_sweep_geometry(world.id, section(desc))),
258
+ csgGeometry: (world: W, desc?: unknown) => parse(abi().og_render_csg_geometry(world.id, json(desc))),
259
+ mergeGeometries: (world: W, desc?: unknown) => parse(abi().og_render_merge_geometries(world.id, json(desc))),
260
+ });