@origingame/engine 0.1.0 → 0.2.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 (62) hide show
  1. package/dist/web/origin-engine.js +4 -4
  2. package/dist/web/origin-engine_bg.wasm +0 -0
  3. package/dist/web-publish/origin-engine-lanes.js +6 -6
  4. package/dist/web-publish/origin-engine-lanes_bg.wasm +0 -0
  5. package/dist/web-publish/origin-engine.js +4 -4
  6. package/dist/web-publish/origin-engine_bg.wasm +0 -0
  7. package/dist/web-publish-2d/origin-engine-lanes.js +6 -6
  8. package/dist/web-publish-2d/origin-engine-lanes_bg.wasm +0 -0
  9. package/dist/web-publish-2d/origin-engine.js +4 -4
  10. package/dist/web-publish-2d/origin-engine_bg.wasm +0 -0
  11. package/knowledge/package.json +4 -4
  12. package/knowledge/scaffold/origin-engine.json +2 -2
  13. package/knowledge/scaffold/template/gitignore +8 -0
  14. package/knowledge/scaffold/template/package.json +1 -1
  15. package/knowledge/scaffold/template/project.ogt +1 -1
  16. package/knowledge/scripts/lib.ts +5 -1
  17. package/knowledge/scripts/pack.ts +2 -1
  18. package/knowledge/scripts/validate.ts +2 -1
  19. package/knowledge/skills/og-build/SKILL.md +17 -1
  20. package/knowledge/skills/og-feel/SKILL.md +8 -1
  21. package/knowledge/skills/og-game/SKILL.md +117 -13
  22. package/knowledge/skills/og-i18n/SKILL.md +12 -3
  23. package/knowledge/skills/og-platform-sdk/SKILL.md +3 -1
  24. package/knowledge/skills/og-ui/SKILL.md +19 -6
  25. package/knowledge/wiki/ai.md +20 -20
  26. package/knowledge/wiki/anim.md +41 -41
  27. package/knowledge/wiki/atmosphere.md +13 -13
  28. package/knowledge/wiki/audio.md +18 -18
  29. package/knowledge/wiki/camera.md +13 -13
  30. package/knowledge/wiki/commands.md +11 -11
  31. package/knowledge/wiki/game.md +8 -8
  32. package/knowledge/wiki/i18n.md +7 -7
  33. package/knowledge/wiki/index.md +4 -1
  34. package/knowledge/wiki/input.md +47 -47
  35. package/knowledge/wiki/load.md +45 -45
  36. package/knowledge/wiki/math.md +7 -7
  37. package/knowledge/wiki/nav.md +34 -34
  38. package/knowledge/wiki/physics.md +124 -106
  39. package/knowledge/wiki/platform.md +31 -31
  40. package/knowledge/wiki/probe.md +66 -66
  41. package/knowledge/wiki/reflect.md +15 -15
  42. package/knowledge/wiki/render.md +99 -89
  43. package/knowledge/wiki/rng.md +14 -14
  44. package/knowledge/wiki/stream.md +15 -15
  45. package/knowledge/wiki/system.md +8 -8
  46. package/knowledge/wiki/systems.md +2 -2
  47. package/knowledge/wiki/terrain.md +19 -19
  48. package/knowledge/wiki/tilemap.md +19 -15
  49. package/knowledge/wiki/time.md +4 -4
  50. package/knowledge/wiki/transform.md +8 -8
  51. package/knowledge/wiki/tween.md +17 -17
  52. package/knowledge/wiki/ui.md +289 -245
  53. package/knowledge/wiki/world.md +67 -37
  54. package/package.json +6 -6
  55. package/schema/api.schema.json +134 -9
  56. package/src/index.ts +1 -0
  57. package/src/node/polish.ts +2 -1
  58. package/src/node/run.ts +5 -1
  59. package/src/runtime.ts +2 -0
  60. package/src/ui-kit/huds.ts +18 -14
  61. package/types/bindings.json +61 -26
  62. package/types/index.d.ts +144 -13
@@ -8022,22 +8022,22 @@ function __wbg_get_imports() {
8022
8022
  arg0.writeTexture(arg1, getArrayU8FromWasm0(arg2, arg3), arg4, arg5);
8023
8023
  }, arguments); },
8024
8024
  __wbindgen_generic_0000000000000001: function(arg0, arg1) {
8025
- // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 4796, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
8025
+ // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 4803, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
8026
8026
  const ret = makeMutClosure(arg0, arg1, wasm_bindgen_b8d3fa9391980f8___convert__closures_____invoke___wasm_bindgen_b8d3fa9391980f8___JsValue__core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_b8d3fa9391980f8___JsError___true_);
8027
8027
  return ret;
8028
8028
  },
8029
8029
  __wbindgen_generic_0000000000000002: function(arg0, arg1) {
8030
- // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("GPUDevice")], shim_idx: 2658, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
8030
+ // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("GPUDevice")], shim_idx: 2666, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
8031
8031
  const ret = makeMutClosure(arg0, arg1, wasm_bindgen_b8d3fa9391980f8___convert__closures_____invoke___wasm_bindgen_b8d3fa9391980f8___sys__JsNullable_wgpu_318367e4ed152831___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_b8d3fa9391980f8___JsError___true_);
8032
8032
  return ret;
8033
8033
  },
8034
8034
  __wbindgen_generic_0000000000000003: function(arg0, arg1) {
8035
- // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("any")], shim_idx: 2658, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
8035
+ // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("any")], shim_idx: 2666, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
8036
8036
  const ret = makeMutClosure(arg0, arg1, wasm_bindgen_b8d3fa9391980f8___convert__closures_____invoke___wasm_bindgen_b8d3fa9391980f8___sys__JsNullable_wgpu_318367e4ed152831___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_b8d3fa9391980f8___JsError___true__352);
8037
8037
  return ret;
8038
8038
  },
8039
8039
  __wbindgen_generic_0000000000000004: function(arg0, arg1) {
8040
- // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("undefined")], shim_idx: 2658, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
8040
+ // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("undefined")], shim_idx: 2666, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
8041
8041
  const ret = makeMutClosure(arg0, arg1, wasm_bindgen_b8d3fa9391980f8___convert__closures_____invoke___wasm_bindgen_b8d3fa9391980f8___sys__JsNullable_wgpu_318367e4ed152831___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_b8d3fa9391980f8___JsError___true__353);
8042
8042
  return ret;
8043
8043
  },
Binary file
@@ -7862,32 +7862,32 @@ function __wbg_get_imports(memory) {
7862
7862
  arg0.writeTexture(arg1, getArrayU8FromWasm0(arg2, arg3), arg4, arg5);
7863
7863
  }, arguments); },
7864
7864
  __wbindgen_generic_0000000000000001: function(arg0, arg1) {
7865
- // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 2021, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
7865
+ // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 2027, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
7866
7866
  const ret = makeMutClosure(arg0, arg1, wasm_bindgen_4274632476068e3f___convert__closures_____invoke___wasm_bindgen_4274632476068e3f___JsValue______true_);
7867
7867
  return ret;
7868
7868
  },
7869
7869
  __wbindgen_generic_0000000000000002: function(arg0, arg1) {
7870
- // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 4356, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
7870
+ // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 4362, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
7871
7871
  const ret = makeMutClosure(arg0, arg1, wasm_bindgen_4274632476068e3f___convert__closures_____invoke___wasm_bindgen_4274632476068e3f___JsValue__core_f9975da687154ecd___result__Result_____wasm_bindgen_4274632476068e3f___JsError___true_);
7872
7872
  return ret;
7873
7873
  },
7874
7874
  __wbindgen_generic_0000000000000003: function(arg0, arg1) {
7875
- // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 4358, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
7875
+ // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 4364, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
7876
7876
  const ret = makeMutClosure(arg0, arg1, wasm_bindgen_4274632476068e3f___convert__closures_____invoke___js_sys_61cb8e1cd79b86e3___futures__task__wait_async_polyfill__MessageEvent______true_);
7877
7877
  return ret;
7878
7878
  },
7879
7879
  __wbindgen_generic_0000000000000004: function(arg0, arg1) {
7880
- // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("GPUDevice")], shim_idx: 2019, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
7880
+ // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("GPUDevice")], shim_idx: 2025, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
7881
7881
  const ret = makeMutClosure(arg0, arg1, wasm_bindgen_4274632476068e3f___convert__closures_____invoke___wasm_bindgen_4274632476068e3f___sys__JsNullable_wgpu_507ee5aabebc46c8___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_f9975da687154ecd___result__Result_____wasm_bindgen_4274632476068e3f___JsError___true_);
7882
7882
  return ret;
7883
7883
  },
7884
7884
  __wbindgen_generic_0000000000000005: function(arg0, arg1) {
7885
- // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("any")], shim_idx: 2019, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
7885
+ // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("any")], shim_idx: 2025, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
7886
7886
  const ret = makeMutClosure(arg0, arg1, wasm_bindgen_4274632476068e3f___convert__closures_____invoke___wasm_bindgen_4274632476068e3f___sys__JsNullable_wgpu_507ee5aabebc46c8___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_f9975da687154ecd___result__Result_____wasm_bindgen_4274632476068e3f___JsError___true__342);
7887
7887
  return ret;
7888
7888
  },
7889
7889
  __wbindgen_generic_0000000000000006: function(arg0, arg1) {
7890
- // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("undefined")], shim_idx: 2019, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
7890
+ // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("undefined")], shim_idx: 2025, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
7891
7891
  const ret = makeMutClosure(arg0, arg1, wasm_bindgen_4274632476068e3f___convert__closures_____invoke___wasm_bindgen_4274632476068e3f___sys__JsNullable_wgpu_507ee5aabebc46c8___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_f9975da687154ecd___result__Result_____wasm_bindgen_4274632476068e3f___JsError___true__343);
7892
7892
  return ret;
7893
7893
  },
@@ -7707,22 +7707,22 @@ function __wbg_get_imports() {
7707
7707
  arg0.writeTexture(arg1, getArrayU8FromWasm0(arg2, arg3), arg4, arg5);
7708
7708
  }, arguments); },
7709
7709
  __wbindgen_generic_0000000000000001: function(arg0, arg1) {
7710
- // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 3961, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
7710
+ // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 3968, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
7711
7711
  const ret = makeMutClosure(arg0, arg1, wasm_bindgen_b8d3fa9391980f8___convert__closures_____invoke___wasm_bindgen_b8d3fa9391980f8___JsValue__core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_b8d3fa9391980f8___JsError___true_);
7712
7712
  return ret;
7713
7713
  },
7714
7714
  __wbindgen_generic_0000000000000002: function(arg0, arg1) {
7715
- // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("GPUDevice")], shim_idx: 1823, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
7715
+ // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("GPUDevice")], shim_idx: 1830, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
7716
7716
  const ret = makeMutClosure(arg0, arg1, wasm_bindgen_b8d3fa9391980f8___convert__closures_____invoke___wasm_bindgen_b8d3fa9391980f8___sys__JsNullable_wgpu_75f3f84ef81abc5a___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_b8d3fa9391980f8___JsError___true_);
7717
7717
  return ret;
7718
7718
  },
7719
7719
  __wbindgen_generic_0000000000000003: function(arg0, arg1) {
7720
- // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("any")], shim_idx: 1823, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
7720
+ // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("any")], shim_idx: 1830, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
7721
7721
  const ret = makeMutClosure(arg0, arg1, wasm_bindgen_b8d3fa9391980f8___convert__closures_____invoke___wasm_bindgen_b8d3fa9391980f8___sys__JsNullable_wgpu_75f3f84ef81abc5a___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_b8d3fa9391980f8___JsError___true__333);
7722
7722
  return ret;
7723
7723
  },
7724
7724
  __wbindgen_generic_0000000000000004: function(arg0, arg1) {
7725
- // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("undefined")], shim_idx: 1823, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
7725
+ // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("undefined")], shim_idx: 1830, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
7726
7726
  const ret = makeMutClosure(arg0, arg1, wasm_bindgen_b8d3fa9391980f8___convert__closures_____invoke___wasm_bindgen_b8d3fa9391980f8___sys__JsNullable_wgpu_75f3f84ef81abc5a___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_b8d3fa9391980f8___JsError___true__334);
7727
7727
  return ret;
7728
7728
  },
@@ -7862,32 +7862,32 @@ function __wbg_get_imports(memory) {
7862
7862
  arg0.writeTexture(arg1, getArrayU8FromWasm0(arg2, arg3), arg4, arg5);
7863
7863
  }, arguments); },
7864
7864
  __wbindgen_generic_0000000000000001: function(arg0, arg1) {
7865
- // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 1873, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
7865
+ // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 1881, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
7866
7866
  const ret = makeMutClosure(arg0, arg1, wasm_bindgen_4274632476068e3f___convert__closures_____invoke___wasm_bindgen_4274632476068e3f___JsValue______true_);
7867
7867
  return ret;
7868
7868
  },
7869
7869
  __wbindgen_generic_0000000000000002: function(arg0, arg1) {
7870
- // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 4209, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
7870
+ // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 4216, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
7871
7871
  const ret = makeMutClosure(arg0, arg1, wasm_bindgen_4274632476068e3f___convert__closures_____invoke___wasm_bindgen_4274632476068e3f___JsValue__core_f9975da687154ecd___result__Result_____wasm_bindgen_4274632476068e3f___JsError___true_);
7872
7872
  return ret;
7873
7873
  },
7874
7874
  __wbindgen_generic_0000000000000003: function(arg0, arg1) {
7875
- // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 4211, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
7875
+ // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 4218, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
7876
7876
  const ret = makeMutClosure(arg0, arg1, wasm_bindgen_4274632476068e3f___convert__closures_____invoke___js_sys_61cb8e1cd79b86e3___futures__task__wait_async_polyfill__MessageEvent______true_);
7877
7877
  return ret;
7878
7878
  },
7879
7879
  __wbindgen_generic_0000000000000004: function(arg0, arg1) {
7880
- // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("GPUDevice")], shim_idx: 1871, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
7880
+ // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("GPUDevice")], shim_idx: 1879, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
7881
7881
  const ret = makeMutClosure(arg0, arg1, wasm_bindgen_4274632476068e3f___convert__closures_____invoke___wasm_bindgen_4274632476068e3f___sys__JsNullable_wgpu_55e897b7c9dc4975___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_f9975da687154ecd___result__Result_____wasm_bindgen_4274632476068e3f___JsError___true_);
7882
7882
  return ret;
7883
7883
  },
7884
7884
  __wbindgen_generic_0000000000000005: function(arg0, arg1) {
7885
- // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("any")], shim_idx: 1871, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
7885
+ // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("any")], shim_idx: 1879, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
7886
7886
  const ret = makeMutClosure(arg0, arg1, wasm_bindgen_4274632476068e3f___convert__closures_____invoke___wasm_bindgen_4274632476068e3f___sys__JsNullable_wgpu_55e897b7c9dc4975___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_f9975da687154ecd___result__Result_____wasm_bindgen_4274632476068e3f___JsError___true__342);
7887
7887
  return ret;
7888
7888
  },
7889
7889
  __wbindgen_generic_0000000000000006: function(arg0, arg1) {
7890
- // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("undefined")], shim_idx: 1871, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
7890
+ // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("undefined")], shim_idx: 1879, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
7891
7891
  const ret = makeMutClosure(arg0, arg1, wasm_bindgen_4274632476068e3f___convert__closures_____invoke___wasm_bindgen_4274632476068e3f___sys__JsNullable_wgpu_55e897b7c9dc4975___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_f9975da687154ecd___result__Result_____wasm_bindgen_4274632476068e3f___JsError___true__343);
7892
7892
  return ret;
7893
7893
  },
@@ -7707,22 +7707,22 @@ function __wbg_get_imports() {
7707
7707
  arg0.writeTexture(arg1, getArrayU8FromWasm0(arg2, arg3), arg4, arg5);
7708
7708
  }, arguments); },
7709
7709
  __wbindgen_generic_0000000000000001: function(arg0, arg1) {
7710
- // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 3816, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
7710
+ // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 3822, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
7711
7711
  const ret = makeMutClosure(arg0, arg1, wasm_bindgen_b8d3fa9391980f8___convert__closures_____invoke___wasm_bindgen_b8d3fa9391980f8___JsValue__core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_b8d3fa9391980f8___JsError___true_);
7712
7712
  return ret;
7713
7713
  },
7714
7714
  __wbindgen_generic_0000000000000002: function(arg0, arg1) {
7715
- // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("GPUDevice")], shim_idx: 1679, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
7715
+ // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("GPUDevice")], shim_idx: 1685, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
7716
7716
  const ret = makeMutClosure(arg0, arg1, wasm_bindgen_b8d3fa9391980f8___convert__closures_____invoke___wasm_bindgen_b8d3fa9391980f8___sys__JsNullable_wgpu_d2fbdff2c91c8b93___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_b8d3fa9391980f8___JsError___true_);
7717
7717
  return ret;
7718
7718
  },
7719
7719
  __wbindgen_generic_0000000000000003: function(arg0, arg1) {
7720
- // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("any")], shim_idx: 1679, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
7720
+ // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("any")], shim_idx: 1685, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
7721
7721
  const ret = makeMutClosure(arg0, arg1, wasm_bindgen_b8d3fa9391980f8___convert__closures_____invoke___wasm_bindgen_b8d3fa9391980f8___sys__JsNullable_wgpu_d2fbdff2c91c8b93___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_b8d3fa9391980f8___JsError___true__333);
7722
7722
  return ret;
7723
7723
  },
7724
7724
  __wbindgen_generic_0000000000000004: function(arg0, arg1) {
7725
- // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("undefined")], shim_idx: 1679, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
7725
+ // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("undefined")], shim_idx: 1685, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
7726
7726
  const ret = makeMutClosure(arg0, arg1, wasm_bindgen_b8d3fa9391980f8___convert__closures_____invoke___wasm_bindgen_b8d3fa9391980f8___sys__JsNullable_wgpu_d2fbdff2c91c8b93___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_b8d3fa9391980f8___JsError___true__334);
7727
7727
  return ret;
7728
7728
  },
@@ -1,17 +1,17 @@
1
1
  {
2
2
  "name": "@origingame/engine-knowledge",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Origin Engine knowledge for agents: the API wiki generated from api.ogt, the ten og-* skills, 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": {
8
8
  "type": "git",
9
- "url": "git+https://github.com/fran0220/origin-engine.git",
9
+ "url": "git+https://github.com/originai-game/origin-engine.git",
10
10
  "directory": "packages/knowledge"
11
11
  },
12
- "homepage": "https://github.com/fran0220/origin-engine#readme",
12
+ "homepage": "https://github.com/originai-game/origin-engine#readme",
13
13
  "bugs": {
14
- "url": "https://github.com/fran0220/origin-engine/issues"
14
+ "url": "https://github.com/originai-game/origin-engine/issues"
15
15
  },
16
16
  "type": "module",
17
17
  "files": [
@@ -4,13 +4,13 @@
4
4
  "substrate": "origin-engine-ts",
5
5
  "engine": {
6
6
  "package": "@origingame/engine",
7
- "version": "0.1.0",
7
+ "version": "0.2.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.1.0"
13
+ "version": "0.2.0"
14
14
  },
15
15
  "probe": {
16
16
  "protocol": 5,
@@ -0,0 +1,8 @@
1
+ # og cook output: rebuilt from assets/, never committed.
2
+ cooked/
3
+ # og build output.
4
+ dist/
5
+ # og run and og test output, and og's bundled entry.
6
+ og-out/
7
+ .og/
8
+ node_modules/
@@ -13,6 +13,6 @@
13
13
  "test": "og test ."
14
14
  },
15
15
  "dependencies": {
16
- "@origingame/engine": "0.1.0"
16
+ "@origingame/engine": "0.2.0"
17
17
  }
18
18
  }
@@ -7,7 +7,7 @@ version 1
7
7
  name "Origin Game"
8
8
  id "origin-game"
9
9
  # The engine this game is written against (design §9: upgrades are explicit).
10
- engine "0.1.0"
10
+ engine "0.2.0"
11
11
  entry "src/main.ts"
12
12
  # 2d (orthographic camera, sprites, 2D physics) or 3d.
13
13
  profile "3d"
@@ -90,7 +90,11 @@ export const TEMPLATE_SKIP: ReadonlySet<string> = new Set(["cooked", "dist", "og
90
90
  * overlay as `.gitattributes`, which in the engine repository would route
91
91
  * the template's plain-blob media through LFS.
92
92
  */
93
- export const TEMPLATE_RENAMED: ReadonlyMap<string, string> = new Map([["gitattributes", ".gitattributes"]]);
93
+ export const TEMPLATE_RENAMED: ReadonlyMap<string, string> = new Map([
94
+ ["gitattributes", ".gitattributes"],
95
+ // npm drops .gitignore from a tarball: the published scaffold/template carries it as `gitignore` (scripts/pack.ts).
96
+ ["gitignore", ".gitignore"],
97
+ ]);
94
98
 
95
99
  const fatal = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true });
96
100
 
@@ -16,7 +16,8 @@ rmSync(target, { recursive: true, force: true });
16
16
  let n = 0;
17
17
  for (const full of walk(source, TEMPLATE_SKIP)) {
18
18
  if (!isText(new Uint8Array(readFileSync(full)))) continue;
19
- const to = join(target, relative(source, full));
19
+ // npm drops .gitignore from a tarball; TEMPLATE_RENAMED maps it back at mount.
20
+ const to = join(target, relative(source, full) === ".gitignore" ? "gitignore" : relative(source, full));
20
21
  mkdirSync(dirname(to), { recursive: true });
21
22
  cpSync(full, to);
22
23
  n++;
@@ -546,11 +546,12 @@ export function readKeys(region: string): string[] {
546
546
  }
547
547
 
548
548
  /**
549
- * The grammars the skills write out (og-game §8 tilesets and maps, §9 a
549
+ * The grammars the skills write out (og-game §8 flipbooks, tilesets and maps, §9 a
550
550
  * model's animation settings and the animation graph, §10 emitters; og-ai
551
551
  * §1 the navmesh, §3 behaviours) and the parsers they come from.
552
552
  */
553
553
  export const GRAMMARS: readonly Grammar[] = [
554
+ { type: "flipbook", source: "crates/og-anim/src/flipbook.rs", region: [/impl FlipMode/, /pub fn to_text/], names: { frame: 1, clip: 1 } },
554
555
  { type: "tileset", source: "crates/og-tilemap/src/tileset.rs" },
555
556
  { type: "tilemap", source: "crates/og-tilemap/src/map.rs", region: [/pub fn parse\(text/, /^pub fn world_to_cell/m] },
556
557
  { type: "particles", source: "crates/og-cook/src/fx.rs", unnamed: { key: "colorOverLife's lines: the parser reads their five numbers whatever the key" } },
@@ -74,7 +74,16 @@ a number and a sound (taste 98, feel 79).
74
74
  matched count. A system that matched 0 entities is usually a missing
75
75
  component on the spawn, not a logic bug.
76
76
 
77
- Where there is no renderer (a sandbox with no GPU: `og run --json` says
77
+ Headless means no window, not no rendering: `og run`, `og test` and
78
+ `og polish` still render every tick when an adapter is available. A
79
+ sandbox without a GPU may have Mesa lavapipe (`vulkan-cpu` in
80
+ `og doctor`), which renders on the CPU and can take minutes per
81
+ game-second. Use `OG_RENDERER=none og test .` (likewise `og run` and
82
+ `og polish`) for simulation-only iteration there. Do not treat this as
83
+ visual approval: record and compare frames on the retained reference
84
+ tier, and run visual polish with a renderer.
85
+
86
+ Where there is no renderer (`OG_RENDERER=none`, or no usable adapter: `og run --json` says
78
87
  `"tier": "none"`, `og doctor` says the renderer is `none`), the run is
79
88
  the same run: the same ticks, dumps and world hash. A `screenshot`
80
89
  writes no PNG and logs "no renderer, frame unchecked" with the file it
@@ -117,6 +126,13 @@ step's file by the name the step gave (`run.json("shop.json")`,
117
126
  `run.png("title.png")`); give each step's file its own name. A test that ran no checks fails. Run it before
118
127
  claiming a change works.
119
128
 
129
+ While iterating, `og test . --filter tests/lobby.og.ts` runs only that
130
+ suite. The filter is a case-sensitive substring of the project-relative
131
+ file path, using `/` separators: `--filter lobby` selects every matching
132
+ `.og.ts` and `.test.ts` file; it does not match test titles or use globs.
133
+ No matching files is a failure, not a passing empty run. The project's
134
+ type check still runs. Drop the filter for the complete regression run.
135
+
120
136
  Put every check that reads a frame (`run.png`, a decoded screenshot, a
121
137
  comparison with `references/`) inside `t.frame(files, () => ...)`:
122
138
 
@@ -297,7 +297,14 @@ starting from these (the defaults are the first column):
297
297
  bounce, `jumpSpeed` from the height you want: `sqrt(2 × 9.81 × h)`.
298
298
  - Read `og.CharacterEvent` for juice: `CHARACTER_LANDED` with its `speed`
299
299
  scales the landing squash and dust; `CHARACTER_JUMPED` plays the jump
300
- stretch (§5) and sound on the same tick.
300
+ stretch (§5) and sound. The controllers move in the physics step, after
301
+ the game's systems, so their events are read **the tick after**: the
302
+ press's tick starts the jump (§1 holds), the next tick plays its juice,
303
+ one tick (17 ms at 60 Hz) late. Where that tick shows (a rhythm jump, a
304
+ sound on a beat), start the stretch and sound in the system that sets
305
+ `jump`, on the press while the controller can jump (`grounded`, or
306
+ `coyote` above 0), and leave the event's `CHARACTER_JUMPED` to the
307
+ buffered and air jumps.
301
308
  - Ragdolls: `blendTime` 0.15–0.3 s from the animation to the bones; set
302
309
  `weight` 1 on the killing blow's tick, with its hit stop, so the fall
303
310
  starts from the hit pose.
@@ -43,7 +43,11 @@ change, without a warning, and its refusals named the line and the fix.
43
43
  The order the games found productive:
44
44
 
45
45
  1. **`project.ogt`** (§2): name, id, the engine pin, the profile, tick and
46
- seed. The scaffold writes it; change it there and nowhere else.
46
+ seed. The scaffold writes it (`npm create @origingame/game --profile
47
+ 2d` writes the 2D starter, a platformer with sprites, a tilemap and 2D
48
+ physics, as does a premise that says 2D, platformer, side-scroller,
49
+ metroidvania or pixel art; `3d`, the default, the 3D template; an
50
+ archetype brings its own); change it there and nowhere else.
47
51
  2. **`GameDesc`** in `src/main.ts` (§3): the scene, the look, the systems,
48
52
  and from the start a command for each state a test must reach (`play`,
49
53
  `warp:<where>`) and facts for what it must check.
@@ -393,7 +397,8 @@ else ignores it. The stamp is world state, so a replay reproduces it.
393
397
  sprites only.
394
398
  - **Sprite sheets** are `.ogt` files of `type flipbook` next to the PNG
395
399
  (grid or named frames, or an Aseprite / TexturePacker JSON `atlas`; clips
396
- with `fps`, `mode loop | pingPong | once` and `event <frame> "name"`).
400
+ with `fps`, `mode loop | pingPong | once` and `event <frame> "name"`;
401
+ every line is the grammar at the end of this section).
397
402
  `og.load.flipbook(world, "sprites/hero.ogt")` answers the sheet and its
398
403
  clips; `og.Flipbook { sheet, clip: og.anim.clip(info, "walk") }` on the
399
404
  sprite's entity plays it, and `og.FlipbookEvent` reports the frames named
@@ -436,7 +441,11 @@ else ignores it. The stamp is world state, so a replay reproduces it.
436
441
  `og.tilemap.setTile` edits a cell (terrain layers re-tile their
437
442
  neighbours, colliders follow); `getTile` answers the tile there (on a
438
443
  terrain layer the one auto-tiling chose, -1 when empty), `cellAt` and
439
- `cellCenter` convert positions. Layers scroll by their `parallax`;
444
+ `cellCenter` convert positions. Every collision layer's colliders sit
445
+ on `og.Tilemap.colliderLayers` unless the layer names its own
446
+ `colliderLayers` and `colliderMask` (grammar below): a layer of grates
447
+ on the bit of the platformer's `oneWayLayers` is one-way while the
448
+ walls on another layer stay solid. Layers scroll by their `parallax`;
440
449
  `repeat x` tiles a background (`reference/tilemap.md`). Every line of a
441
450
  tileset and a map, and what the cook reads of a Tiled map, is the
442
451
  grammar at the end of this section.
@@ -451,6 +460,55 @@ this; `templates/archetypes/roguelike` carves a tilemap at run time from
451
460
  og.Rng and keeps its fog of war on a layer, and
452
461
  `templates/archetypes/tower-defense` writes placements to a map's layer.
453
462
 
463
+ ### Flipbooks: the grammar
464
+
465
+ A **flipbook** is an `.ogt` of `type flipbook` beside its PNG (give the
466
+ PNG `texture { kind pixel }` import settings for pixel art). Its frames
467
+ are the grid's (row-major from the top left, named `0`, `1`, ... by
468
+ their index), then the `frame` lines', then an atlas's; its clips are
469
+ numbered in file order from 0, and that index is what
470
+ `og.anim.clip(info, "walk")` answers and what `og.Flipbook.clip` holds,
471
+ so a system that compares `og.Flipbook.clip` with a constant relies on
472
+ that order (look the indices up with `og.anim.clip` in `start` instead).
473
+ Every line, with its default:
474
+
475
+ ```text
476
+ type flipbook
477
+ version 1
478
+ ---
479
+ texture "hero.png" # the sheet (required): beside the .ogt when that file exists, else an asset id
480
+ size 256 80 # the texture in pixels: the cook fills it in from the PNG
481
+ filter nearest # nearest (default, pixel art) | linear
482
+ array false # true: the frames become the layers of a texture array, one draw for every sprite (one size each)
483
+ pivot 0.5 0 # the point of each frame at the entity's position, from its bottom left (default 0.5 0.5): 0.5 0 stands on the feet
484
+ margin 0 # grid only: pixels round the grid (default 0)
485
+ spacing 2 # grid only: pixels between cells (default 0)
486
+ grid 32 40 8 2 # <cell width px> <cell height px> [<columns> <rows>]: frames 0.., row-major
487
+ frame slash 0 80 48 40 0.25 0 # a named frame: <name> x y w h [pivot x y], x y from the texture's top left
488
+ atlas "hero.json" # an Aseprite or TexturePacker JSON: its frames (and Aseprite's tags as clips)
489
+ clip idle { # clip 0
490
+ frames 14 15 # frame indices or names, in order (required)
491
+ fps 2 # frames a second (default 12) ...
492
+ }
493
+ clip run { # clip 1
494
+ frames 0 1 2 3 4 5 6 7
495
+ durations 0.07 0.07 0.1 0.07 0.07 0.07 0.1 0.07 # ... or seconds per frame, one per frame
496
+ mode loop # loop (default) | pingPong (or pingpong) | once (holds the last frame, sets og.Flipbook.finished)
497
+ event 2 "step" # entering clip frame 2 sends og.FlipbookEvent "step" (at most 63 bytes)
498
+ event 6 "step"
499
+ }
500
+ ```
501
+
502
+ An **atlas** names a JSON exported beside the PNG: Aseprite's (Export
503
+ Sprite Sheet, JSON hash or array: frames in the natural order of their
504
+ names with their own durations, and each `frameTags` entry a clip, its
505
+ direction `forward`, `reverse` or `pingpong`) or TexturePacker's (JSON
506
+ hash or array, its pivots taken; rotated frames are refused). The tags'
507
+ clips come first, in the atlas's order, then the sheet's own `clip`
508
+ blocks; a clip the sheet declares wins over a tag of the same name (to
509
+ give it `event` lines or another `mode`). `templates/archetypes/runner`'s
510
+ `assets/sprites/courier.ogt` is a grid sheet with five clips.
511
+
454
512
  ### Tilesets, maps and Tiled: the grammar
455
513
 
456
514
  A **tileset** is an `.ogt` of `type tileset` beside its atlas PNG (give the
@@ -539,6 +597,8 @@ layer walls {
539
597
  opacity 1 # (default 1)
540
598
  visible true # (default true)
541
599
  collision true # its tiles' collision becomes static colliders (default false)
600
+ colliderLayers 4 # those colliders' og.Collider.layers bits (default: og.Tilemap.colliderLayers)
601
+ colliderMask 3 # the layers they collide with, og.Collider.mask bits (default: every layer)
542
602
  lit false # the layer takes no 2D light (og.Lighting2D); default true: lit like a sprite in the lit range
543
603
  repeat x # x, y or both: tile the layer endlessly (a background)
544
604
  terrain wall # a terrain layer: cells are 1 (filled) or 0, the terrain picks the tiles
@@ -571,6 +631,7 @@ cook reads of a layer and an object:
571
631
  |---|---|---|
572
632
  | `autotile` | tile layer custom property (string) | the layer is a terrain layer of that terrain of its tileset; any tile in a cell marks it filled, the terrain picks the drawn tile |
573
633
  | `collision` | tile layer custom property (bool) | the layer's tile collision becomes static colliders |
634
+ | `colliderLayers`, `colliderMask` | tile layer custom properties (int) | the og.Collider `layers` and `mask` bits of that layer's colliders (default: og.Tilemap.colliderLayers, every layer) |
574
635
  | `lit` | tile layer custom property (bool) | false keeps the layer out of og.Lighting2D (a sky or window layer); default true |
575
636
  | `z` | tile layer custom property (int) | the sprite layer offset from og.Tilemap.layer (default: the layer's index among the tile layers) |
576
637
  | `repeatx`, `repeaty` | tile layer custom properties (bool), or Tiled's own layer fields | the layer repeats along x or y (`repeat` is not a name the cook reads) |
@@ -583,7 +644,7 @@ cook reads of a layer and an object:
583
644
 
584
645
  `og cook` warns on every custom property it does not read, naming the
585
646
  property, its layer, object or tile and the names read there: a tile
586
- layer's other than the six names above (or one whose value has another
647
+ layer's other than the eight names above (or one whose value has another
587
648
  type: a `collision` written as the string "true"), a tile's other than
588
649
  `solid`, the map's, a group's, an object layer's or an image layer's own
589
650
  (none is imported), and an object's class-typed one (no text to give). A
@@ -945,10 +1006,14 @@ round false # sprite mode: fade each particle to a round edge over
945
1006
  speeds are in world units like a sprite's, and the particles take the
946
1007
  sprite batch's order and glow like any sprite.
947
1008
  - A one-shot effect (a hit, a pickup, landing dust) is `rate 0`,
948
- `looping false`, one `burst 0 <count>` and a short `duration`; restart
949
- it by writing the tick to its `og.ParticleSystem.startTick` (moving the
950
- entity first). A lasting one (embers, motes, rain) keeps the defaults
951
- `looping true` and a `rate`.
1009
+ `looping false`, one `burst 0 <count>` and a short `duration`; fire
1010
+ and restart it by writing the tick to its `og.ParticleSystem.startTick`
1011
+ (moving the entity first). Spawn it in `start` without a `startTick`:
1012
+ the default, `PARTICLES_ARMED`, means never written, so it waits
1013
+ armed and emits nothing until its first use (write `PARTICLES_ARMED`
1014
+ back to re-arm one without firing it). A lasting one (embers, motes,
1015
+ rain) keeps the defaults `looping true` and a `rate`, and emits from
1016
+ tick 0 without a `startTick`.
952
1017
  - `sheet` animates a sprite sheet texture: `life 1` plays its frames once
953
1018
  over each particle's life, `fps 12` at a rate, `random` one frame per
954
1019
  particle. `array` does the same over a texture array's layers (§8), one
@@ -1139,6 +1204,17 @@ there. `world.set(e, og.Velocity, ...)` refuses on
1139
1204
  an entity without one (a body in `start`, before its first step):
1140
1205
  `world.insert` it there, which adds and sets it.
1141
1206
 
1207
+ `og.CollisionStarted` is read on the tick after the physics step. Its
1208
+ `normal` points from `a` to `b`; the bodies' `og.Velocity` already contains
1209
+ the solver's outgoing velocity, not their incoming impact velocity. Do
1210
+ not derive impact weight from those velocities: bodies may already be
1211
+ separating. There is no contact-time velocity or impulse on this event.
1212
+ For driven bodies, retain the velocity handed to physics in a component
1213
+ and read that cache before the next drive system overwrites it (as in
1214
+ `examples/rumpus-isle/src/critters.ts`). Project `velocityA - velocityB`
1215
+ onto the event normal for closing speed. This estimates linear approach
1216
+ speed, not contact-point speed from rotation or forces during the step.
1217
+
1142
1218
  ```ts
1143
1219
  const hit = og.physics.raycast(world, { origin: eye, direction: { x: 0, y: 0, z: -1 }, maxDistance: 30, filter: { mask: 0b10, exclude: player } });
1144
1220
  if (hit.ok && hit.value) { /* hit.value.entity, distance, point, normal */ }
@@ -1170,7 +1246,7 @@ deterministic and part of snapshots (`reference/physics.md`):
1170
1246
  - `og.CharacterController` (3D, or top-down with `gravityScale` 0) — set
1171
1247
  `move` every tick and `jump` to jump; it climbs `maxSlope` and
1172
1248
  `stepHeight`, snaps to the ground, rides moving platforms, slides along
1173
- walls, pushes bodies; read `grounded`, `velocity`, `ground`. Its
1249
+ walls, pushes dynamic bodies; read `grounded`, `velocity`, `ground`. Its
1174
1250
  og.Collider's `layers` and `mask` decide what blocks it, as for bodies
1175
1251
  (a ghost through a gate: leave the gate's layer out of its `mask`); the
1176
1252
  same for the PlatformerController.
@@ -1180,6 +1256,13 @@ deterministic and part of snapshots (`reference/physics.md`):
1180
1256
  `impulse` (m/s, taken once on the next step) knocks it back or launches
1181
1257
  it;
1182
1258
  `og.CharacterEvent` reports jumps and landings for dust and sounds.
1259
+ Both controllers push the dynamic bodies they move into (`pushBodies`,
1260
+ on by default) with at most `pushStrength` (1,000 N): the push is mass
1261
+ times the speed asked of the body, capped, so mass tells. Give a crate
1262
+ its `og.RigidBody.mass`: 2 kg is shoved at the run speed, 100 kg creeps,
1263
+ a tonne on the ground holds (friction beats the push). Lower
1264
+ `pushStrength` for a weak hero; `pushBodies: false` for a hero that
1265
+ never shoves (a crate then blocks like a wall).
1183
1266
  `templates/archetypes/runner`'s courier is one.
1184
1267
  - `og.Vehicle` — a raycast car (3D, `throttle`, `steer`, `brake`; wheels
1185
1268
  from `og.physics.vehicleWheels`) or a car on wheel joints (2D). Its
@@ -1450,15 +1533,36 @@ to 64 KiB a key: a record in one key, the world in a slot
1450
1533
  its tick: restored, the next step completes that tick (the systems
1451
1534
  after the saver and the physics step), so a replay from it (the
1452
1535
  countdown's world restored, the taped inputs fed again) runs the saved
1453
- race tick for tick. Take it as the system's last write of the tick:
1536
+ race tick for tick. The command channel's scheduled steps keep their
1537
+ remaining delays across a restore (og.Time takes the saved tick), so a
1538
+ playtest that taps Continue onto a save of a later tick, or an earlier
1539
+ one, runs the rest of its script and ends at its last step or `quit`.
1540
+ Take it as the system's last write of the tick:
1454
1541
  what the system does after the call is not in it. A saved type whose fields changed since (a
1455
1542
  release added one) is refused naming the type and fields; pass
1456
1543
  `{ migrate: true }` to map it by field name (new fields take their
1457
1544
  defaults), and keep a saved type's fields stable between releases where
1458
1545
  you can. Keep progress in components and resources, never in module
1459
- variables (they are not in the save), and keep request numbers and the
1460
- session's own state (a best score read from the store, an open menu)
1461
- where a restore cannot roll them back: reset them after it. Asset
1546
+ variables (they are not in the save). Everything in the world rolls
1547
+ back with it, request numbers and the session's own state (a best score
1548
+ read from the store, the settings, an open menu) included, so reset
1549
+ them after it: the tick after a restore delivers `og.WorldRestored`
1550
+ (`from`, the tick the world was at; `tick`, the saved one). A system
1551
+ that reads it (`reads: [og.WorldRestored]`, `world.events(og.WorldRestored)`)
1552
+ forgets the request numbers, asks the store again and closes what the
1553
+ player had open:
1554
+
1555
+ ```ts
1556
+ if (world.events(og.WorldRestored).length > 0) {
1557
+ g.progressRequest = 0; // answered long ago, in another session
1558
+ const asked = og.platform.storeGet(world, "settings");
1559
+ g.settingsRequest = asked.ok ? asked.value : 0; // the language and volumes live on in the session
1560
+ }
1561
+ ```
1562
+
1563
+ It is sent as that tick starts, so the world between the restore and
1564
+ that tick hashes as the save did; after a save taken mid-tick it comes
1565
+ with the first whole tick after the completing step. Asset
1462
1566
  handles are saved as numbers: load in `start`, in the same order every
1463
1567
  launch.
1464
1568
  - **A record** (`storeSet(world, { key: "save", value: { chimes, glimmers,
@@ -70,7 +70,9 @@ string "results.time" "タイム {time}"
70
70
  - Numbers, times and prices go through arguments, not string building.
71
71
  - og.ui's templates have words of their own (Retry, Share, "Best 1,200",
72
72
  "New best", Cancel, Settings, Buy, Skip, "1 of 3", a racing HUD's
73
- "lap", "Best 1:36.233", Pause and Boost): each is a field of
73
+ "lap", "Best 1:36.233", Pause and Boost, the other HUDs' Jump, Fire,
74
+ "kills", "moves left", "Target 1,000", "Lv 3" and "+12/s"): each is a
75
+ field of
74
76
  the template's desc with the English default, so a localised game passes
75
77
  its table's: `ResultsDesc.bestLabel`, `newBestLabel`, `shareLabel`,
76
78
  `actions`; `ConfirmDesc.confirmLabel`, `cancelLabel`; `SettingsDesc.title`,
@@ -90,12 +92,19 @@ string "results.time" "タイム {time}"
90
92
  ("Best {best}", the best lap as m:ss.mmm), `pauseLabel` (the pause
91
93
  button's name), `boostLabel`, `brakeLabel`, `leftLabel`, `rightLabel`
92
94
  (the touch pedals and arrows) and `unit`, and its `splits`' labels
93
- (`S1`) are the game's. `bestLabel: og.i18n.t(world, "results.best")`
95
+ (`S1`) are the game's; `PlatformerHudDesc.pauseLabel`, `jumpLabel`
96
+ (the touch Jump); `ShooterHudDesc.killsLabel` (after the count),
97
+ `fireLabel`, `pauseLabel`; `PuzzleHudDesc.movesLabel` (under the moves
98
+ left), `targetLabel` ("Target {target}"), `pauseLabel`;
99
+ `IdleHudDesc.tapLabel`, `levelLabel` ("Lv {level}", a generator's
100
+ badge), `rateLabel` ("+{rate}/s"), `pauseLabel`. Names, levels,
101
+ weapons, currencies and a map's label are the game's data, from its
102
+ table too. `bestLabel: og.i18n.t(world, "results.best")`
94
103
  with `"Best {best}"` / `"最佳 {best}"` in the tables (the template fills
95
104
  `{best}`, formatted); `stepLabel` the same with `"{step} of {count}"` /
96
105
  `"第 {step} 步,共 {count} 步"`. templates/ui-kit passes every one of
97
106
  these words from its five tables (`settings.*`, `shop.*`, `inventory.*`,
98
- `leaderboard.*`, `tutorial.*`, `cutscene.*`).
107
+ `leaderboard.*`, `tutorial.*`, `cutscene.*`, the HUDs' `hud.*`).
99
108
  - Emphasis inside a sentence is rich-text markup in the message itself
100
109
  (`"Your progress in slot [b]{slot}[/b] will be lost."`, shown with
101
110
  `og.ui.richText`): each translation bolds or colours its own words, in
@@ -61,7 +61,9 @@ if (answer.ok && typeof answer.data.value === "number") run.best[i] = Math.max(r
61
61
  - Answers are host input, like key presses: a replay records them, so the
62
62
  same answers give the same world.
63
63
  - Every answer carries `time` (UTC ms): the host's clock when it was
64
- answered. `og.platform.now(world)` is the host's clock at the last
64
+ answered (a `saveSlot` or `loadSlot` answer, the time of the store
65
+ answer that ended it, so a slot's load is as good a clock as a
66
+ `storeGet`). `og.platform.now(world)` is the host's clock at the last
65
67
  answer (or when the platform attached) advanced by the ticks since, so
66
68
  it is the one wall clock a game may read: the time away is a store
67
69
  answer's `time` less the time the save wrote down