kireji 0.17.1 → 0.18.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 (101) hide show
  1. package/package.json +1 -1
  2. package/src/app/kireji/issue-tracker/active-overlay/issue-modal/1776207331/priority +1 -0
  3. package/src/app/kireji/issue-tracker/active-overlay/issue-modal/1776212585/status +1 -0
  4. package/src/app/kireji/issue-tracker/active-overlay/issue-modal/1776307785/status +1 -1
  5. package/src/app/kireji/issue-tracker/active-overlay/issue-modal/1780696449/status +1 -1
  6. package/src/app/kireji/issue-tracker/active-overlay/issue-modal/1781522546/affects_.js +3 -0
  7. package/src/app/kireji/issue-tracker/active-overlay/issue-modal/1781522546/description +1 -0
  8. package/src/app/kireji/issue-tracker/active-overlay/issue-modal/1781522546/part.json +3 -0
  9. package/src/app/kireji/issue-tracker/active-overlay/issue-modal/1781522546/priority +1 -0
  10. package/src/app/kireji/issue-tracker/active-overlay/issue-modal/1781522546/status +1 -0
  11. package/src/app/kireji/issue-tracker/active-overlay/issue-modal/1781522546/title +1 -0
  12. package/src/app/kireji/issue-tracker/active-overlay/issue-modal/1782803713/affects_.js +3 -0
  13. package/src/app/kireji/issue-tracker/active-overlay/issue-modal/1782803713/description +1 -0
  14. package/src/app/kireji/issue-tracker/active-overlay/issue-modal/1782803713/part.json +3 -0
  15. package/src/app/kireji/issue-tracker/active-overlay/issue-modal/1782803713/priority +1 -0
  16. package/src/app/kireji/issue-tracker/active-overlay/issue-modal/1782803713/status +1 -0
  17. package/src/app/kireji/issue-tracker/active-overlay/issue-modal/1782803713/title +1 -0
  18. package/src/app/kireji/issue-tracker/active-overlay/issue-modal/1782803799/affects_.js +3 -0
  19. package/src/app/kireji/issue-tracker/active-overlay/issue-modal/1782803799/description +1 -0
  20. package/src/app/kireji/issue-tracker/active-overlay/issue-modal/1782803799/part.json +3 -0
  21. package/src/app/kireji/issue-tracker/active-overlay/issue-modal/1782803799/priority +1 -0
  22. package/src/app/kireji/issue-tracker/active-overlay/issue-modal/1782803799/status +1 -0
  23. package/src/app/kireji/issue-tracker/active-overlay/issue-modal/1782803799/title +1 -0
  24. package/src/app/kireji/issue-tracker/active-overlay/issue-modal/1782804028/affects_.js +3 -0
  25. package/src/app/kireji/issue-tracker/active-overlay/issue-modal/1782804028/description +7 -0
  26. package/src/app/kireji/issue-tracker/active-overlay/issue-modal/1782804028/part.json +3 -0
  27. package/src/app/kireji/issue-tracker/active-overlay/issue-modal/1782804028/priority +1 -0
  28. package/src/app/kireji/issue-tracker/active-overlay/issue-modal/1782804028/status +1 -0
  29. package/src/app/kireji/issue-tracker/active-overlay/issue-modal/1782804028/title +1 -0
  30. package/src/part.css_.js +4 -0
  31. package/src/part.html_.js +2 -0
  32. package/src/parts/abstract/gltf-game/async-load-level.js +10 -2
  33. package/src/parts/abstract/gltf-game/build.js +1 -0
  34. package/src/parts/abstract/gltf-game/camera/buffer_.js +34 -95
  35. package/src/parts/abstract/gltf-game/debug-toggle.js +8 -0
  36. package/src/parts/abstract/gltf-game/levels/level/data-get.js +22 -0
  37. package/src/parts/abstract/gltf-game/levels/level/type.d.ts +2 -0
  38. package/src/parts/abstract/gltf-game/loop.js +1 -1
  39. package/src/parts/abstract/gltf-game/part.html_.js +1 -1
  40. package/src/parts/abstract/gltf-game/part.json +0 -1
  41. package/src/parts/abstract/gltf-game/point-action.js +1 -0
  42. package/src/parts/abstract/gltf-game/render.js +1 -1
  43. package/src/parts/abstract/gltf-game/type.d.ts +3 -0
  44. package/src/parts/abstract/gltf-game/unlit.wgsl +3 -2
  45. package/src/parts/abstract/gltf-game/view-hydrate.js +8 -1
  46. package/src/parts/abstract/type.d.ts +1 -0
  47. package/src/parts/abstract/walkable/part.json +3 -1
  48. package/src/parts/abstract/walkable/point-tri-that-contains.js +2 -0
  49. package/src/parts/abstract/walkable/type.d.ts +7 -2
  50. package/src/parts/core/debug/hide-debug/data-state +1 -0
  51. package/src/parts/core/debug/hide-debug/id +1 -0
  52. package/src/parts/core/debug/hide-debug/part.json +3 -0
  53. package/src/parts/core/debug/hide-debug/title +1 -0
  54. package/src/parts/core/debug/open-is_.js +1 -0
  55. package/src/parts/core/debug/part.html_.js +4 -0
  56. package/src/parts/core/debug/part.json +10 -0
  57. package/src/parts/core/debug/point.js +8 -0
  58. package/src/parts/core/debug/show-debug/data-state +1 -0
  59. package/src/parts/core/debug/show-debug/id +1 -0
  60. package/src/parts/core/debug/show-debug/part.json +3 -0
  61. package/src/parts/core/debug/show-debug/title +1 -0
  62. package/src/parts/core/debug/title +1 -0
  63. package/src/parts/core/debug/type.d.ts +12 -0
  64. package/src/parts/core/era/modern/part.css +3 -2
  65. package/src/parts/core/era/vintage/part.css_.js +2 -0
  66. package/src/parts/core/math/matrix/build.js +49 -0
  67. package/src/parts/core/math/matrix/chain.js +1 -0
  68. package/src/parts/core/math/matrix/columnMajor-from.js +15 -0
  69. package/src/parts/core/math/matrix/compose.js +3 -0
  70. package/src/parts/core/math/matrix/identity.js +6 -0
  71. package/src/parts/core/math/matrix/part.json +48 -0
  72. package/src/parts/core/math/matrix/perspective.js +8 -0
  73. package/src/parts/core/math/matrix/rotationQuaternion.js +11 -0
  74. package/src/parts/core/math/matrix/rotationX.js +8 -0
  75. package/src/parts/core/math/matrix/rotationY.js +8 -0
  76. package/src/parts/core/math/matrix/rotationZ.js +8 -0
  77. package/src/parts/core/math/matrix/scaling.js +6 -0
  78. package/src/parts/core/math/matrix/translation.js +6 -0
  79. package/src/parts/core/math/matrix/type.d.ts +45 -0
  80. package/src/parts/core/math/vector/type.d.ts +27 -26
  81. package/src/parts/core/sound/build.js +104 -0
  82. package/src/parts/core/sound/description +1 -0
  83. package/src/parts/core/sound/frequency-tone-to.js +1 -0
  84. package/src/parts/core/sound/now_.js +1 -0
  85. package/src/parts/core/sound/output_.js +1 -0
  86. package/src/parts/core/sound/part.json +14 -0
  87. package/src/parts/core/sound/reverb.js +15 -0
  88. package/src/parts/core/sound/sync-install.js +5 -0
  89. package/src/parts/core/sound/title +1 -0
  90. package/src/parts/core/sound/type.d.ts +56 -0
  91. package/src/parts/core/task-bar/tray/item/tray.html_.js +1 -1
  92. package/src/parts/core/task-bar/tray/stats/part.json +2 -1
  93. package/src/parts/core/windows/HTML-render-task.js +1 -1
  94. package/src/parts/desktop/about/part.css +159 -149
  95. package/src/parts/desktop/about/part.html_.js +6 -1
  96. package/src/parts/desktop/about/scroller/part.json +3 -0
  97. package/src/parts/desktop/about/scroller/precision_.js +1 -0
  98. package/src/parts/desktop/about/scroller/query +1 -0
  99. package/src/parts/desktop/about/type.d.ts +3 -0
  100. package/src/parts/desktop/about/update-color.js +10 -6
  101. package/src/parts/desktop/about/update-era.js +3 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kireji",
3
- "version": "0.17.1",
3
+ "version": "0.18.0",
4
4
  "description": "A web framework for stateful, entropy-perfect, multi-origin web apps. Currently in alpha. Expect breaking changes for version 0. Use with caution!",
5
5
  "files": [
6
6
  "src/",
@@ -0,0 +1 @@
1
+ Add a global debug part. Control it via a toggle in the About app. It should enable things like the debug map overlay for Orbital and position overlays for both walkable games. It should also toggle the FPS meter in the task bar tray.
@@ -0,0 +1 @@
1
+ Add a sound manager which can be used to hold sound utilities and a global audio context.
@@ -0,0 +1 @@
1
+ Right now, mesh instances aren't rendered and all meshes in a GLTF file have to have their transforms applied so that they will render in the correct location in the game. This needs to be updated to fully leverage the GLTF format's potential: geometry instancing will save file space and use less memory on the GPU than having duplicate copies of the same data. This will make adding reusable props and archetecture easy and performant and will make editing the game levels in Blender easier too.
@@ -0,0 +1 @@
1
+ Support Instancing and Node Transforms in GLTF Game
@@ -0,0 +1,7 @@
1
+ Right now, only one scene (scene 0) is usable for each GLTF. This wastes the potential of having the scenes represent different levels so that a single GLTF can represent an entire game and geometry instances can be rightly shared between levels.
2
+
3
+ Also, right now, the very first walkable mesh in the mesh list is used as the sole walkable collision surface for a GLTF game. Instead, scene transitions should be used to switch between multiple walkable meshes.
4
+
5
+ Further, walkable meshes must currently have all of their transforms applied in order for collision to be in the correct position in the game. This should be changed to support transforms on collision nodes.
6
+
7
+ Also, multiple collision meshes in a single scene should be aggregated into a single collision mesh space. Take note that multiple instances of the same collision mesh might be used across multiple scenes and it might make sense and save space to incorperate the scene and transform into the game state so that there is only one runtime copy of each triangle collision mesh while at the same time there is a walkable mesh transform matrix which can be multiplied by the geometry along with the camera matrix.
@@ -0,0 +1 @@
1
+ Support Multiple Scenes and Walkable Mesh Nodes in GLTF Game
package/src/part.css_.js CHANGED
@@ -393,6 +393,10 @@ task-menu {
393
393
  font-size: var(--default-font-size);
394
394
  }
395
395
 
396
+ body.hide-debug .debug {
397
+ display: none !important;
398
+ }
399
+
396
400
  /* --- Media Elements --- */
397
401
 
398
402
  img[src^="data:image/svg+xml;inert;"] {
package/src/part.html_.js CHANGED
@@ -11,6 +11,8 @@ if (_.includeEra !== "none")
11
11
  if (_.includeColor !== 'none')
12
12
  classes.push(Color.arm.key)
13
13
 
14
+ classes.push(Debug.arm.key)
15
+
14
16
  if (includeMenu)
15
17
  classes.push(Menu.classes)
16
18
 
@@ -1,11 +1,13 @@
1
1
  thisGLTFGame.loading = true
2
2
 
3
3
  // Create new level buffers, pipeline, bind group and render pass definitions.
4
- const { gltf } = thisGLTFGame.levels.arm
4
+ const gltf = thisGLTFGame.levels.arm.gltf
5
5
 
6
6
  thisGLTFGame.renderPassDefinitions.length = 0
7
7
 
8
- for (const mesh of gltf.meshes) {
8
+ for (const [meshIndex, instanceMatrices] of gltf.scenes[gltf.scene ?? 0].transformsMap) {
9
+
10
+ const mesh = gltf.meshes[meshIndex]
9
11
 
10
12
  if (mesh.name.startsWith("walkable_"))
11
13
  continue
@@ -161,11 +163,16 @@ for (const mesh of gltf.meshes) {
161
163
  },
162
164
  })
163
165
 
166
+ // ------
164
167
 
168
+ const instanceData = new Float32Array(instanceMatrices.length * 16)
169
+ instanceMatrices.forEach((m, i) => instanceData.set(m.data, i * 16))
170
+ const instanceBuffer = Graphics.createBuffer(instanceData, GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST)
165
171
  thisGLTFGame.renderPassDefinitions.push({
166
172
  vertexBuffers,
167
173
  pipeline,
168
174
  indexCount: indexArray.length,
175
+ instanceCount: instanceMatrices.length,
169
176
  indexBuffer: Graphics.createBuffer(indexArray, GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST),
170
177
  bindGroup: Graphics.device.createBindGroup({
171
178
  layout: pipeline.getBindGroupLayout(0),
@@ -173,6 +180,7 @@ for (const mesh of gltf.meshes) {
173
180
  { binding: 0, resource: { buffer: thisGLTFGame.uniformBuffer } },
174
181
  { binding: 1, resource: gpuTexture.createView() },
175
182
  { binding: 2, resource: gpuSampler },
183
+ { binding: 3, resource: { buffer: instanceBuffer } },
176
184
  ]
177
185
  }),
178
186
  indexArray
@@ -1,6 +1,7 @@
1
1
  define(thisGLTFGame, {
2
2
  loading: { value: false, writable: true },
3
3
  loadedLevel: { value: null, writable: true },
4
+ disabledSound: { value: null, writable: true },
4
5
  uniformBuffer: { value: null, writable: true },
5
6
  onscreenContext: { value: null, writable: true },
6
7
  offscreenContext: { value: null, writable: true },
@@ -1,98 +1,37 @@
1
- const { cos, sin } = Math
2
- const myGLTFGame = thisGLTFGameCamera[".."]
3
-
4
- // ── World scale ───────────────────────────────────────────────────────────────
5
- // Express near/far/scope in real-world meters and convert to world units here.
6
- // To change unit scale later, only this constant needs updating.
7
- const unitScale = 1 // world units per meter
8
-
9
- const near = thisGLTFGameCamera.manifest.near * unitScale
10
- const far = thisGLTFGameCamera.manifest.far * unitScale
11
- const scope = thisGLTFGameCamera.manifest.scope * unitScale
12
-
13
- // ── Matrix constructors (row-major, row-vector convention) ────────────────────
14
- const matrix = {
15
- multiply: (a, b) => new Float32Array([
16
- a[0] * b[0] + a[1] * b[4] + a[2] * b[8] + a[3] * b[12],
17
- a[0] * b[1] + a[1] * b[5] + a[2] * b[9] + a[3] * b[13],
18
- a[0] * b[2] + a[1] * b[6] + a[2] * b[10] + a[3] * b[14],
19
- a[0] * b[3] + a[1] * b[7] + a[2] * b[11] + a[3] * b[15],
20
-
21
- a[4] * b[0] + a[5] * b[4] + a[6] * b[8] + a[7] * b[12],
22
- a[4] * b[1] + a[5] * b[5] + a[6] * b[9] + a[7] * b[13],
23
- a[4] * b[2] + a[5] * b[6] + a[6] * b[10] + a[7] * b[14],
24
- a[4] * b[3] + a[5] * b[7] + a[6] * b[11] + a[7] * b[15],
25
-
26
- a[8] * b[0] + a[9] * b[4] + a[10] * b[8] + a[11] * b[12],
27
- a[8] * b[1] + a[9] * b[5] + a[10] * b[9] + a[11] * b[13],
28
- a[8] * b[2] + a[9] * b[6] + a[10] * b[10] + a[11] * b[14],
29
- a[8] * b[3] + a[9] * b[7] + a[10] * b[11] + a[11] * b[15],
30
-
31
- a[12] * b[0] + a[13] * b[4] + a[14] * b[8] + a[15] * b[12],
32
- a[12] * b[1] + a[13] * b[5] + a[14] * b[9] + a[15] * b[13],
33
- a[12] * b[2] + a[13] * b[6] + a[14] * b[10] + a[15] * b[14],
34
- a[12] * b[3] + a[13] * b[7] + a[14] * b[11] + a[15] * b[15],
35
- ]),
36
-
37
- rx: a => [
38
- 1, 0, 0, 0,
39
- 0, cos(a), sin(a), 0,
40
- 0, -sin(a), cos(a), 0,
41
- 0, 0, 0, 1
42
- ],
43
-
44
- ry: a => [
45
- cos(a), 0, -sin(a), 0,
46
- 0, 1, 0, 0,
47
- sin(a), 0, cos(a), 0,
48
- 0, 0, 0, 1
49
- ],
50
-
51
- rz: a => [
52
- cos(a), sin(a), 0, 0,
53
- -sin(a), cos(a), 0, 0,
54
- 0, 0, 1, 0,
55
- 0, 0, 0, 1
56
- ],
57
-
58
- t: (x, y, z) => [
59
- 1, 0, 0, 0,
60
- 0, 1, 0, 0,
61
- 0, 0, 1, 0,
62
- x, y, z, 1
63
- ]
64
- }
65
-
66
- // ── Perspective projection (WebGPU NDC depth range: 0 to 1) ───────────────────
67
- const f = 1.0 / Math.tan((thisGLTFGameCamera.manifest.fov * Math.PI / 180) / 2)
68
- const aspect = myGLTFGame.onscreenContext.canvas.width /
69
- myGLTFGame.onscreenContext.canvas.height
70
- const nf = 1 / (near - far)
71
-
72
- const perspective = [
73
- f / aspect, 0, 0, 0,
74
- 0, f, 0, 0,
75
- 0, 0, far * nf, -1,
76
- 0, 0, far * near * nf, 0
77
- ]
78
-
79
- // ── View transform chain ──────────────────────────────────────────────────────
80
- // Reading right to left: translate to player, rotate, pull back by scope.
81
- // In row-vector convention the rightmost matrix is applied last (closest to P).
82
- const rotation = thisGLTFGameCamera.model
83
- const position = myGLTFGame.levels.arm.model
84
-
85
- const t = matrix.t(-position.x, -thisGLTFGameCamera.manifest.height - position.y, -position.z)
86
- const ry = matrix.ry(rotation.y * Math.PI / 180)
87
- const rx = matrix.rx(rotation.x * Math.PI / 180)
88
- const rz = matrix.rz(rotation.z * Math.PI / 180)
89
-
90
- // Chain: t → ry → rx → rz → perspective
91
- // reduceRight so leftmost matrix is outermost (applied last)
92
- const viewProj = [perspective, rz, rx, ry, t]
93
- .reduceRight(matrix.multiply)
1
+ const {
2
+ manifest: {
3
+ near,
4
+ far,
5
+ fov,
6
+ height
7
+ },
8
+ model: rotation,
9
+ [".."]: {
10
+ levels: {
11
+ arm: {
12
+ model: position
13
+ }
14
+ },
15
+ onscreenContext: {
16
+ canvas: {
17
+ width: canvasWidth,
18
+ height: canvasHeight
19
+ }
20
+ }
21
+ }
22
+ } = thisGLTFGameCamera
94
23
 
95
24
  return new Float32Array([
96
- ...viewProj,
97
- _.now / 1000 // globalClock
25
+
26
+ // Perspective matrix.
27
+ ...Matrix.chain(
28
+ Matrix.translation(-position.x, -height - position.y, -position.z),
29
+ Matrix.rotationY(rotation.y * Math.PI / 180),
30
+ Matrix.rotationX(rotation.x * Math.PI / 180),
31
+ Matrix.rotationZ(rotation.z * Math.PI / 180),
32
+ Matrix.perspective(fov, canvasWidth / canvasHeight, near, far)
33
+ ).data,
34
+
35
+ // Time.
36
+ _.now / 1000
98
37
  ])
@@ -0,0 +1,8 @@
1
+ if (Debug.arm === Debug.showDebug)
2
+ Q(`#${thisGLTFGame.domains.join("_")}>canvas`).after((() => {
3
+ const offscreen = document.createElement("div")
4
+ offscreen.innerHTML = thisGLTFGame.levels.arm["part.html"]
5
+ return offscreen.querySelector("world-")
6
+ })())
7
+
8
+ else Q(`#${thisGLTFGame.domains.join("_")} world-`).remove()
@@ -66,6 +66,28 @@ const data = {
66
66
  gltf: json
67
67
  }
68
68
 
69
+ for (const scene of json.scenes) {
70
+ scene.transformsMap = new Map()
71
+
72
+ const gatherNodeTransforms = (nodeIndex, parentWorld) => {
73
+ const node = json.nodes[nodeIndex]
74
+ const local = node.matrix ? Matrix.fromColumnMajor(node.matrix) : Matrix.compose(node.translation, node.rotation, node.scale)
75
+ const world = parentWorld ? Matrix.chain(local, parentWorld) : local
76
+
77
+ if (node.mesh !== undefined) {
78
+ if (!scene.transformsMap.has(node.mesh))
79
+ scene.transformsMap.set(node.mesh, [])
80
+ scene.transformsMap.get(node.mesh).push(world)
81
+ }
82
+
83
+ for (const child of node.children ?? [])
84
+ gatherNodeTransforms(child, world)
85
+ }
86
+
87
+ for (const rootIndex of scene.nodes)
88
+ gatherNodeTransforms(rootIndex, null)
89
+ }
90
+
69
91
  const walkableIndices = json.meshes.reduce((indices, mesh, index) => {
70
92
  if (mesh.name.startsWith('walkable_'))
71
93
  indices.push(index)
@@ -175,6 +175,8 @@ interface GLTFNode {
175
175
  interface GLTFScene {
176
176
  nodes: number[]
177
177
  name?: string
178
+ /** A runtime property that stores the array of node transforms around each mesh in the scene. */
179
+ transformsMap: Map<number, IMatrix4[]>
178
180
  }
179
181
 
180
182
  // ── Root glTF document ────────────────────────────────────────────────────────
@@ -28,5 +28,5 @@ thisGLTFGame.reactToKeyboardInput()
28
28
  thisGLTFGame.updateUniformBuffer()
29
29
  thisGLTFGame.render()
30
30
 
31
- if (thisGLTFGame.manifest.debug)
31
+ if (Debug.arm === Debug.showDebug)
32
32
  thisGLTFGame.updateDebugView()
@@ -1,6 +1,6 @@
1
1
  return /* html */`<canvas id="onscreen-canvas">
2
2
  Your browser does not support the HTML canvas tag.
3
3
  </canvas>
4
- ${thisGLTFGame.manifest.debug ? thisGLTFGame.levels.arm["part.html"] : ""}
4
+ ${Debug.arm === Debug.showDebug ? thisGLTFGame.levels.arm["part.html"] : ""}
5
5
  <section id=hud>${thisGLTFGame["hud.html"]}</section>
6
6
  <section id=pause-menu>${thisGLTFGame["pause-menu.html"]}</section>`
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "abstract": true,
3
3
  "extends": "app",
4
- "debug": false,
5
4
  "walkingSpeed": 142,
6
5
  "sprintingSpeed": 240,
7
6
  "mouseSensitivity": 0.5,
@@ -4,6 +4,7 @@ Pointer.handle({
4
4
  label.classList.remove("blinked")
5
5
  label.offsetWidth // force reflow to restart css animation
6
6
  label.classList.add("blinked")
7
+ thisGLTFGame.disabledSound.play(Sound.now)
7
8
  },
8
9
  POINTER_EVENT,
9
10
  TARGET_ELEMENT
@@ -30,7 +30,7 @@ for (const renderPassDefinition of thisGLTFGame.renderPassDefinitions) {
30
30
  pass.setBindGroup(0, renderPassDefinition.bindGroup)
31
31
  pass.setIndexBuffer(renderPassDefinition.indexBuffer, renderPassDefinition.indexArray instanceof Uint32Array ? 'uint32' : 'uint16')
32
32
  renderPassDefinition.vertexBuffers.forEach((buffer, index) => pass.setVertexBuffer(index, buffer))
33
- pass.drawIndexed(renderPassDefinition.indexCount)
33
+ pass.drawIndexed(renderPassDefinition.indexCount, renderPassDefinition.instanceCount)
34
34
  }
35
35
  pass.end()
36
36
  Graphics.device.queue.submit([encoder.finish()])
@@ -50,6 +50,8 @@ declare interface IGLTFGame<TOwner>
50
50
  readonly currentTurnSpeed: number
51
51
  readonly canvasSizeChanged: boolean
52
52
  readonly renderPassDefinitions: GPURenderPassDefinition[]
53
+ /** The sound that plays when the player uses the action button with no interactive object in focus. */
54
+ readonly disabledSound?: SoundWave
53
55
  }
54
56
 
55
57
  declare interface IGLTFGameManifest
@@ -67,6 +69,7 @@ declare interface IGLTFGameManifest
67
69
 
68
70
  declare interface GPURenderPassDefinition {
69
71
  readonly indexCount: number
72
+ readonly instanceCount: number
70
73
  readonly vertexBuffers: [
71
74
  slot: GPUIndex32,
72
75
  buffer:
@@ -6,15 +6,16 @@ struct Camera {
6
6
  @group(0) @binding(0) var<uniform> camera : Camera;
7
7
  @group(0) @binding(1) var t_diffuse: texture_2d<f32>;
8
8
  @group(0) @binding(2) var s_diffuse: sampler;
9
+ @group(0) @binding(3) var<storage, read> instances: array<mat4x4<f32>>;
9
10
 
10
11
  struct VertexOutput {
11
12
  @builtin(position) position: vec4<f32>,
12
13
  @location(0) uv: vec2<f32>,
13
14
  };
14
15
 
15
- @vertex fn v({$0}) -> VertexOutput {
16
+ @vertex fn v({$0}, @builtin(instance_index) instanceIndex: u32) -> VertexOutput {
16
17
  var out: VertexOutput;
17
- out.position = camera.projection * vec4<f32>(POSITION, 1.0);
18
+ out.position = camera.projection * (instances[instanceIndex] * vec4<f32>(POSITION, 1.0));
18
19
  out.uv = TEXCOORD_0;
19
20
  return out;
20
21
  }
@@ -39,4 +39,11 @@ document.addEventListener('pointerlockchange', reactivePause)
39
39
  document.addEventListener('pointerlockerror', reactivePause)
40
40
  document.addEventListener('visibilitychange', reactivePause)
41
41
  window.addEventListener('blur', reactivePause)
42
- window.addEventListener('focus', reactivePause)
42
+ window.addEventListener('focus', reactivePause)
43
+
44
+ Debug.attach("update", thisGLTFGame, "toggleDebug")
45
+
46
+ thisGLTFGame.disabledSound = new Sound.Wave()
47
+ thisGLTFGame.disabledSound.duration = 0.125
48
+ thisGLTFGame.disabledSound.tone = 40
49
+ thisGLTFGame.disabledSound.type = "sawtooth"
@@ -9,6 +9,7 @@ declare interface IAbstract
9
9
  readonly comingSoon: IComingSoonApp<IAbstract>
10
10
  readonly error: IErrorApp<IAbstract>
11
11
  readonly facet: IFacet<IAbstract, null>
12
+ readonly gltfGame: IGLTFGame<IAbstract>
12
13
  readonly issue: ITrackedIssue<IAbstract>
13
14
  readonly match: IMatch<IAbstract, null>
14
15
  readonly walkable: IWalkable<IAbstract>
@@ -11,7 +11,9 @@
11
11
  "ray-cast": [
12
12
  "FORCE_VECTOR",
13
13
  "DELTA_TIME",
14
- "ENABLE_SLIDING"
14
+ "ENABLE_SLIDING",
15
+ "ENABLED_GRAVITY",
16
+ "MAX_CLIMB"
15
17
  ]
16
18
  }
17
19
  }
@@ -7,4 +7,6 @@ for (let triIndex = 0; triIndex < thisWalkable.triTable.length; triIndex++)
7
7
  if (triIndex !== thisWalkable.triIndex && thisWalkable.triContainsPoint(triIndex, POINT))
8
8
  return triIndex
9
9
 
10
+ // Among all triangles at the candidate XZ point, sorted by ascending surfaceY, select the one with the highest surfaceY that satisfies surfaceY ≤ PLAYER_REFERENCE_Y + climbThreshold.
11
+
10
12
  return -1
@@ -3,8 +3,13 @@ declare interface IWalkable<TOwner>
3
3
 
4
4
  // Components.
5
5
  readonly getData(): IWalkableData
6
- /** Casts a ray from the current walkable position along the force vector direction for the given delta time and returns a summary of the results. @param FORCE_VECTOR the force vector represent the position the uninterrupted ray will arrive at in one second. @param DELTA_TIME the duration of the time cast in seconds. @param ENABLE_SLIDING whether or not to enable the ray to "wrap" along the walkable boundary instead of stopping cold. */
7
- readonly castRay(FORCE_VECTOR: Vector3, DELTA_TIME: number, ENABLE_SLIDING: boolean): IWalkableRayCastResult
6
+ /** Casts a ray from the current walkable position along the force vector direction for the given delta time and returns a summary of the results.
7
+ * @param FORCE_VECTOR the force vector represent the position the uninterrupted ray will arrive at in one second.
8
+ * @param DELTA_TIME the duration of the time cast in seconds.
9
+ * @param ENABLE_SLIDING if true, the ray will "wrap" along a boundary instead of stopping cold.
10
+ * @param GRAVITY if defined, the ray will not be snapped to the Y-position of the walkable surface but will accelerate downward toward it at the given rate (in Y units per second).
11
+ * @param MAX_CLIMB if defined, ray casts which land on a triangle whose Y-position is higher than the start position will be considered boundary walls unless they are less than this number. */
12
+ readonly castRay(FORCE_VECTOR: Vector3, DELTA_TIME: number, ENABLE_SLIDING: boolean, GRAVITY: number, MAX_CLIMB: number): IWalkableRayCastResult
8
13
  /** Checks if a point (x, y, z) rounds to a valid pixel within the specified tri's memoized row data. */
9
14
  readonly triContainsPoint(TRI_INDEX: IWalkableTriIndex, POINT: Vector3): boolean
10
15
  /** Returns whether or not the given point is in a tri. @returns the index of the tri that contains the point. -1 otherwise. */
@@ -0,0 +1 @@
1
+ disabled
@@ -0,0 +1 @@
1
+ debug-control
@@ -0,0 +1,3 @@
1
+ {
2
+ "extends": "body-mode"
3
+ }
@@ -0,0 +1 @@
1
+ Hide
@@ -0,0 +1 @@
1
+ return true
@@ -0,0 +1,4 @@
1
+ return `<span ${Debug.pointAttr()} id="debug-control" tabIndex=0 data-state="${Debug.arm.stateData}" class="toggle-control">
2
+ <span class="label">${Debug.title}:</span><flex-spacer></flex-spacer>
3
+ <span class="base"><span class="handle"></span></span>
4
+ </span>`
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "Debug",
3
+ "extends": "match",
4
+ "actions": {
5
+ "point": [
6
+ "POINTER_EVENT",
7
+ "TARGET_ELEMENT"
8
+ ]
9
+ }
10
+ }
@@ -0,0 +1,8 @@
1
+ Pointer.handle({
2
+ click() {
3
+ Debug.setRID(1n, true)
4
+ },
5
+ POINTER_EVENT,
6
+ TARGET_ELEMENT,
7
+ focus: "click"
8
+ })
@@ -0,0 +1 @@
1
+ enabled
@@ -0,0 +1 @@
1
+ debug-control
@@ -0,0 +1,3 @@
1
+ {
2
+ "extends": "body-mode"
3
+ }
@@ -0,0 +1 @@
1
+ Show
@@ -0,0 +1 @@
1
+ Debug Views
@@ -0,0 +1,12 @@
1
+ declare interface IDebug
2
+ extends IMatch<IDesktop, IBodyMode<IEra>>,
3
+ IWebView {
4
+
5
+ // Subparts.
6
+ readonly hideDebug: IBodyMode<IDebug>
7
+ readonly showDebug: IBodyMode<IDebug>
8
+ }
9
+
10
+ /** Toggles helper views for developers. */
11
+ declare const Debug: IDebug
12
+ type Debug = T
@@ -42,9 +42,8 @@ title-bar>.part-icon {
42
42
  .toggle-control .base {
43
43
  width: 100%;
44
44
  border-radius: var(--spacing);
45
- background: var(--light-bg);
46
45
  width: calc(var(--spacing) * 2);
47
- box-shadow: inset 0px 0px 12px #000;
46
+ box-shadow: 0 0 0 1px var(--bg-light), inset 0px 0px 12px #000a;
48
47
  flex: 0 0 auto;
49
48
  overflow: hidden;
50
49
  display: flex;
@@ -229,7 +228,9 @@ tray- {
229
228
  }
230
229
 
231
230
  #clock-tray-item {
231
+ white-space: nowrap;
232
232
  overflow: hidden;
233
+ width: max-content;
233
234
  }
234
235
 
235
236
  #clock-tray-item,
@@ -345,7 +345,9 @@ tray- {
345
345
  }
346
346
 
347
347
  #clock-tray-item {
348
+ white-space: nowrap;
348
349
  overflow: hidden;
350
+ width: max-content;
349
351
  }
350
352
 
351
353
  #clock-tray-item,