kireji 0.13.0 → 0.15.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 (42) hide show
  1. package/package.json +1 -1
  2. package/src/app/kireji/issue-tracker/sections/issues/1776205973/affects_.js +1 -1
  3. package/src/app/kireji/issue-tracker/sections/issues/1776205973/description +3 -3
  4. package/src/app/kireji/issue-tracker/sections/issues/1776205973/title +1 -1
  5. package/src/app/kireji/issue-tracker/sections/issues/1776206413/affects_.js +1 -1
  6. package/src/build.js +8 -0
  7. package/src/parts/abstract/part/attr-click.js +1 -0
  8. package/src/parts/abstract/part/model-reset.js +12 -0
  9. package/src/parts/abstract/part/model-set.js +4 -1
  10. package/src/parts/abstract/part/part.json +5 -0
  11. package/src/parts/abstract/part/type.d.ts +5 -1
  12. package/src/parts/abstract/scroller/onresize.js +1 -1
  13. package/src/parts/abstract/scroller/wrap.js +1 -1
  14. package/src/parts/abstract/type.d.ts +1 -1
  15. package/src/parts/abstract/{mesh → walkable}/build.js +12 -12
  16. package/src/parts/abstract/walkable/constants.js +1 -0
  17. package/src/parts/abstract/walkable/data-get.js +11 -0
  18. package/src/parts/abstract/walkable/description-abstract +1 -0
  19. package/src/parts/abstract/{mesh → walkable}/mathML-subpart.js +2 -2
  20. package/src/parts/abstract/walkable/model_.js +1 -0
  21. package/src/parts/abstract/{mesh → walkable}/point-tri-contains.js +1 -1
  22. package/src/parts/abstract/walkable/point-tri-that-contains.js +10 -0
  23. package/src/parts/abstract/{mesh → walkable}/ray-cast.js +17 -20
  24. package/src/parts/abstract/{mesh → walkable}/routeID-distribute.js +9 -9
  25. package/src/parts/abstract/{mesh → walkable}/routeID-model-to.js +2 -2
  26. package/src/parts/abstract/walkable/type.d.ts +109 -0
  27. package/src/parts/core/address-bar/{sync-install.js → async-install.js} +2 -0
  28. package/src/parts/core/client/async-install.js +1 -4
  29. package/src/parts/core/client/clicks-block.js +17 -0
  30. package/src/parts/core/client/part.json +3 -0
  31. package/src/parts/core/client/type.d.ts +2 -0
  32. package/src/parts/core/pointer/handle.js +3 -1
  33. package/src/parts/core/server/sync-install.js +1 -1
  34. package/src/parts/desktop/era/vintage/static.css +34 -5
  35. package/src/static.css +139 -1
  36. package/src/type.d.ts +56 -14
  37. package/src/parts/abstract/mesh/constants.js +0 -1
  38. package/src/parts/abstract/mesh/data-get.js +0 -11
  39. package/src/parts/abstract/mesh/model_.js +0 -1
  40. package/src/parts/abstract/mesh/point-tri-that-contains.js +0 -10
  41. package/src/parts/abstract/mesh/type.d.ts +0 -109
  42. /package/src/parts/abstract/{mesh → walkable}/part.json +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kireji",
3
- "version": "0.13.0",
3
+ "version": "0.15.0",
4
4
  "description": "A web framework for stateful, entropy-perfect, multi-origin web applications. Currently in alpha. Expect breaking changes for version 0. Use with caution!",
5
5
  "files": [
6
6
  "src/",
@@ -1,3 +1,3 @@
1
1
  return [
2
- _.parts.abstract.mesh
2
+ _.parts.abstract.walkable
3
3
  ]
@@ -1,6 +1,6 @@
1
- There are four potential improvements that can be used to refine mesh raycasting to improve edge sliding and potentially performance (if necessary).
1
+ There are four potential improvements that can be used to refine walkable raycasting to improve edge sliding and potentially performance (if necessary).
2
2
 
3
- 1. When the angle of the line through the opposing neighbors appears exactly straight, consider searching in a wider radius for asymmetry in the mesh boundary. This can help prevent dead stops when the force vector is exactly perpendicular to a straight portion of a very gently angled edge.
4
- 2. Consider memoizing triangle neighbors and offering a NEIGHBORS_ONLY argument into the function that determines which triangle a given point falls on. This might improve raytracing performance but it might also introduce edge cases (for example, for meshes with tris that are very thin slivers).
3
+ 1. When the angle of the line through the opposing neighbors appears exactly straight, consider searching in a wider radius for asymmetry in the walkable boundary. This can help prevent dead stops when the force vector is exactly perpendicular to a straight portion of a very gently angled edge.
4
+ 2. Consider memoizing triangle neighbors and offering a NEIGHBORS_ONLY argument into the function that determines which triangle a given point falls on. This might improve raytracing performance but it might also introduce edge cases (for example, for walkable with tris that are very thin slivers).
5
5
  3. For accurate "friction", we should reduce the speed of the vector-to-nearest-boundary-neighbor proportionally to how far that vector deviates from true force vector.
6
6
  4. When the ray casting time limit does not provide enough time to make a full diagonal move, consider moving to one of the two 4-point neighbors that sits between the current ray position and the target diagonal neighbor.
@@ -1 +1 @@
1
- Refine Mesh Ray Casting
1
+ Refine Walkable Ray Casting
@@ -1,3 +1,3 @@
1
1
  return [
2
- _.parts.abstract.mesh
2
+ _.parts.abstract.walkable
3
3
  ]
package/src/build.js CHANGED
@@ -82,6 +82,12 @@ function ƒ(_, compressedSubjectOrigins) {
82
82
 
83
83
  // Math Utilities
84
84
  class Vector {
85
+ static 2(x = 0, y = 0) {
86
+ return { x, y }
87
+ }
88
+ static 3(x = 0, y = 0, z = 0) {
89
+ return { x, y, z }
90
+ }
85
91
  static magnitude(vector) {
86
92
  return Math.hypot(...Object.values(vector))
87
93
  }
@@ -757,6 +763,8 @@ function ƒ(_, compressedSubjectOrigins) {
757
763
  const constant = this
758
764
  constant.path = SOURCE_PATH
759
765
  constant.line = SOURCE_LINE
766
+ if (!constant.line.endsWith(";"))
767
+ constant.line += ";"
760
768
  constant.lineNumber = SOURCE_LINE_NUMBER
761
769
  constant.source = sourceFile.addSource(SOURCE_PATH, SOURCE_LINE)
762
770
  constant.equalsIndex = SOURCE_LINE.indexOf("=")
@@ -0,0 +1 @@
1
+ return `data-onclick="${sanitizeAttr(JSON.stringify([part.host, METHOD_NAME, ...ARGS]))}"`
@@ -0,0 +1,12 @@
1
+ let landingModel = _.landingModel
2
+
3
+ for (const domain of [...part.domains].reverse()) {
4
+ if (domain in landingModel)
5
+ landingModel = landingModel[domain]
6
+ else {
7
+ part.setRouteID(0n)
8
+ return
9
+ }
10
+ }
11
+
12
+ part.setModel(landingModel)
@@ -1 +1,4 @@
1
- part.setRouteID(part.modelToRouteID(MODEL))
1
+ const newRouteID = part.modelToRouteID(MODEL)
2
+
3
+ if (part.routeID !== newRouteID)
4
+ part.setRouteID(newRouteID)
@@ -13,6 +13,7 @@
13
13
  "MODEL",
14
14
  "SKIP_RUNTIME_STATE_DISTRIBUTION = false"
15
15
  ],
16
+ "model-reset": [],
16
17
  "routeID-collect": [
17
18
  "SUBPARTS",
18
19
  "DEPTH"
@@ -73,6 +74,10 @@
73
74
  "METHOD_NAME = 'point'",
74
75
  "...ARGS"
75
76
  ],
77
+ "attr-click": [
78
+ "METHOD_NAME = 'onclick'",
79
+ "...ARGS"
80
+ ],
76
81
  "manifest-resolve-owner-of": [
77
82
  "PROPERTY_KEY"
78
83
  ],
@@ -33,8 +33,10 @@ declare interface IPart<TOwner, TSubpart>
33
33
  readonly "runtimeReference": string
34
34
  /** An optional display name for the part. */
35
35
  readonly "title"?: string
36
- /** Generates the attribute string that sets up an onpointerdown listener that calls `part[METHOD_NAME](event,this,...ARGS)`. */
36
+ /** Generates the attribute string that sets up an onpointerdown listener that calls `part[METHOD_NAME](event,this,...ARGS)`. Typically, use `pointer.handle({ ... })` within that method to react to manage complex events drag-and-drop, clicks, double clicks, etc. @remarks This approach will always use the pointer events (not click, touch or mouse events). Use `clickAttr` instead of `pointAttr` to create a traditional click event handler. */
37
37
  readonly pointAttr(METHOD_NAME: string = "point", ...ARGS: any[])
38
+ /** Generates the attribute string that sets up an onclick listener that calls `part[METHOD_NAME](event,this,...ARGS)`. Using `pointAttr` with `pointer.handle({ ... })` is the preferred method of reacting to clicks but this event can be used for special cases like requesting a pointerlock, where the browser requires a proper click event. */
39
+ readonly clickAttr(METHOD_NAME: string = "onclick", ...ARGS: any[])
38
40
  /** Registers a listener that calls RECEIVER[CALLBACK_NAME](this) after the event of the given type occurs. */
39
41
  readonly attach(EVENT_TYPE: string, RECEIVER: IPartAny, CALLBACK_NAME: string): void
40
42
  /** Unregisters the listener that calls RECEIVER[CALLBACK_NAME](this) after the event of the given type occurs. */
@@ -66,6 +68,8 @@ declare interface IPart<TOwner, TSubpart>
66
68
  readonly startBuild(): void
67
69
  /** Performs `part.modelToRouteID()` on MODEL and then performs `part.setRouteID()` on the resulting route ID. */
68
70
  readonly setModel(MODEL: any, SKIP_RUNTIME_STATE_DISTRIBUTION: boolean = false)
71
+ /** Sets the route ID on the part to match the landing model (or route ID 0n, if the part is not mentioned in the landing model). */
72
+ readonly resetModel(MODEL: any, SKIP_RUNTIME_STATE_DISTRIBUTION: boolean = false)
69
73
  /** Sets the part's routeID, propagating it leafward and rootward and updating all views.
70
74
  *
71
75
  * If DELTA is true, ROUTE_ID is added to the part's current route ID.
@@ -2,7 +2,7 @@ scroller.onscroll()
2
2
  const ratio = scroller.container.scrollHeight / scroller.container.clientHeight
3
3
  const precisionFactor = 100_000
4
4
 
5
- scroller.scrollBar.style.setProperty("--ratio", ratio)
5
+ scroller.scrollBar.style.setProperty("--scroll-thumb-ratio", ratio)
6
6
 
7
7
  if (Math.round(ratio * precisionFactor) === precisionFactor)
8
8
  scroller.scrollBar.setAttribute("disabled", "")
@@ -1 +1 @@
1
- return `<scroller-><scroll-content>${INNER_HTML}</scroll-content></scroller-><scroll-bar ${scroller.pointAttr("buttonPoint")} style="--fraction:${scroller.fraction};--ratio:1" disabled><button ${scroller.pointAttr("buttonPoint")} class=scroll-up></button><thumb- ${scroller.pointAttr("thumbPoint")}></thumb-><button ${scroller.pointAttr("buttonPoint")} class=scroll-down></button></scroll-bar>`
1
+ return `<scroller-><scroll-content>${INNER_HTML}</scroll-content></scroller-><scroll-bar ${scroller.pointAttr("buttonPoint")} style="--fraction:${scroller.fraction};--scroll-thumb-ratio:1" disabled><button ${scroller.pointAttr("buttonPoint")} class=scroll-up></button><thumb- ${scroller.pointAttr("thumbPoint")}></thumb-><button ${scroller.pointAttr("buttonPoint")} class=scroll-down></button></scroll-bar>`
@@ -11,7 +11,7 @@ declare interface IAbstract
11
11
  readonly facet: IFacet<IAbstract, null>
12
12
  readonly issue: ITrackedIssue<IAbstract>
13
13
  readonly match: IMatch<IAbstract, null>
14
- readonly mesh: IMesh<IAbstract>
14
+ readonly walkable: IWalkable<IAbstract>
15
15
  readonly mix: IMix<IAbstract, null>
16
16
  readonly part: IPart<IAbstract, null>
17
17
  readonly partMask: IPartMask<IAbstract, null>
@@ -1,18 +1,18 @@
1
- mesh.define({
1
+ walkable.define({
2
2
  triTable: { value: [] },
3
3
  triIndex: { value: -1, writable: true },
4
- position: { value: { x: null, y: null, z: null } },
4
+ position: { value: Vector[3]() },
5
5
  data: {
6
6
  resolve() {
7
- return mesh.getData()
7
+ return walkable.getData()
8
8
  }
9
9
  },
10
10
  cardinality: {
11
11
  resolve() {
12
- let meshCardinality = 0n
12
+ let walkableCardinality = 0n
13
13
 
14
- // Obtain the raw data for this collision mesh.
15
- const [pointList, tris] = this.data.collision
14
+ // Obtain the raw data for this walkable.
15
+ const [pointList, tris] = this.data.walkable
16
16
 
17
17
  // Iterate over each tri (array of three point indices) in the data.
18
18
  for (const tri of tris) {
@@ -59,7 +59,7 @@ mesh.define({
59
59
  // This row doesn't have a full pixel. Adjust the z-range.
60
60
  if (z <= zRange.min + 1) zRange.min = z + 1
61
61
  else if (z >= zRange.max - 1) zRange.max = z - 1
62
- else throw new Error("Unexpected tri geometry found in mesh.")
62
+ else throw new Error("Unexpected tri geometry found in walkable.")
63
63
  continue
64
64
  }
65
65
 
@@ -70,7 +70,7 @@ mesh.define({
70
70
  min.x = Math.ceil(min.x)
71
71
  max.x = Math.ceil(max.x) - 1
72
72
 
73
- /** @type {IMeshTriDataRow} */
73
+ /** @type {IWalkableTriDataRow} */
74
74
  const row = {
75
75
  z,
76
76
  xyRange: { min, max },
@@ -82,18 +82,18 @@ mesh.define({
82
82
  }
83
83
 
84
84
  // Store the tri.
85
- mesh.triTable.push({
85
+ walkable.triTable.push({
86
86
  points,
87
87
  zRange,
88
88
  rows,
89
- offset: meshCardinality,
89
+ offset: walkableCardinality,
90
90
  cardinality: triCardinality
91
91
  })
92
92
 
93
- meshCardinality += triCardinality
93
+ walkableCardinality += triCardinality
94
94
  }
95
95
 
96
- return meshCardinality
96
+ return walkableCardinality
97
97
  }
98
98
  }
99
99
  })
@@ -0,0 +1 @@
1
+ const walkable = this
@@ -0,0 +1,11 @@
1
+ const { points, tris } = walkable.manifest
2
+
3
+ const data = { walkable: [[], []] }
4
+
5
+ for (let index = 0; index < points.length; index += 2)
6
+ data.walkable[0].push([Math.round(points[index]), 0, Math.round(points[index + 1])])
7
+
8
+ for (let index = 0; index < tris.length; index += 3)
9
+ data.walkable[1].push([tris[index], tris[index + 1], tris[index + 2]])
10
+
11
+ return data
@@ -0,0 +1 @@
1
+ This part represents a state space that is formed by quantizing the { x, z } positions of a 3D trianglated mesh. It is equipped with a per-frame ray-tracing method that uses a movement vector to handle the trade-off from triangle to triangle and converts route IDs to { x, y, z } coordinates. This is useful for for 2D and 3D games because it creates a state space that includes all of the positions a character is allowed to walk on and does not include any points that lie outside the mesh boundaries.
@@ -1,10 +1,10 @@
1
1
  if (DEPTH <= 0)
2
2
  return [
3
- `<munder><mo>∑</mo><mrow><mi>t</mi><mo>∈</mo><mi>tris</mi><mo>(</mo><msub><mi>𝑝</mi><mi>${mesh.key}</mi></msub><mo>)</mo></mrow></munder>`,
3
+ `<munder><mo>∑</mo><mrow><mi>t</mi><mo>∈</mo><mi>tris</mi><mo>(</mo><msub><mi>𝑝</mi><mi>${walkable.key}</mi></msub><mo>)</mo></mrow></munder>`,
4
4
  `<munder><mo>∑</mo><mrow><mi>r</mi><mo>∈</mo><mi>rows</mi><mo>(</mo><mi>t</mi><mo>)</mo></mrow></munder>`,
5
5
  `<msub><mi>𝑘</mi><mi>r</mi></msub>`
6
6
  ]
7
7
 
8
- return /*mesh.triTable.length > 20 ? base(DEPTH) :*/ mesh.triTable.flatMap(triData => {
8
+ return /*walkable.triTable.length > 20 ? base(DEPTH) :*/ walkable.triTable.flatMap(triData => {
9
9
  return [`<mn>${triData.cardinality}</mn>`, "<mo>+</mo>"]
10
10
  }).slice(0, -1)
@@ -0,0 +1 @@
1
+ return { ...walkable.position }
@@ -1,5 +1,5 @@
1
1
  const flooredZ = Math.floor(POINT.z)
2
- const triData = mesh.triTable[TRI_INDEX]
2
+ const triData = walkable.triTable[TRI_INDEX]
3
3
 
4
4
  if (flooredZ < triData.zRange.min || flooredZ > triData.zRange.max)
5
5
  return false
@@ -0,0 +1,10 @@
1
+ // Check current tri first.
2
+ if (walkable.triIndex !== -1 && walkable.triContainsPoint(walkable.triIndex, POINT))
3
+ return walkable.triIndex
4
+
5
+ // Check all tris.
6
+ for (let triIndex = 0; triIndex < walkable.triTable.length; triIndex++)
7
+ if (triIndex !== walkable.triIndex && walkable.triContainsPoint(triIndex, POINT))
8
+ return triIndex
9
+
10
+ return -1
@@ -1,13 +1,13 @@
1
1
  // Define a safe result: the current position before casting.
2
- /** @type {IMeshRayCastResult} */
2
+ /** @type {IWalkableRayCastResult} */
3
3
  const safeIterationResult = {
4
4
  hit: false,
5
- triIndex: mesh.triIndex,
6
- point: {
7
- x: mesh.position.x,
8
- y: 0, // Exclude y from ray cast calculations for now.
9
- z: mesh.position.z
10
- },
5
+ triIndex: walkable.triIndex,
6
+ point: Vector[3](
7
+ walkable.position.x,
8
+ 0, // Exclude y coordinate from the ray casting algorithm for now.
9
+ walkable.position.z
10
+ ),
11
11
  forceVector: FORCE_VECTOR
12
12
  }
13
13
 
@@ -18,7 +18,7 @@ const speed = Vector.magnitude(FORCE_VECTOR)
18
18
  if (speed !== 0) {
19
19
 
20
20
  // Initialize timing data as though the vector doesn't intersect any grid lines.
21
- const timeOfNextIntersection = { x: Infinity, z: Infinity }
21
+ const timeOfNextIntersection = Vector[3](Infinity, Infinity, Infinity)
22
22
  const timeBetweenIntersections = { ...timeOfNextIntersection }
23
23
 
24
24
  // Set the clock to zero.
@@ -62,7 +62,7 @@ if (speed !== 0) {
62
62
 
63
63
  // Emergency exit the loop.
64
64
  if (_.now - start >= 2000) {
65
- warn("Mesh ray cast calculation exceeded the maximum allowable processing time of 2 seconds.", { processingTime: _.now - start, iteration, DELTA_TIME, FORCE_VECTOR, speed, safeIterationResult, timeOfNextIntersection, timeBetweenIntersections })
65
+ warn("Walkable ray cast calculation exceeded the maximum allowable processing time of 2 seconds.", { processingTime: _.now - start, iteration, DELTA_TIME, FORCE_VECTOR, speed, safeIterationResult, timeOfNextIntersection, timeBetweenIntersections })
66
66
  break castRay
67
67
  }
68
68
 
@@ -94,8 +94,8 @@ if (speed !== 0) {
94
94
  // Construct the next point along the ray, given the elapsed time.
95
95
  const point = Vector.add(safeIterationResult.point, Vector.multiply(FORCE_VECTOR, timeElapsedDuringThisIteration))
96
96
 
97
- // Check if the point is outside the mesh boundary.
98
- const triIndex = mesh.triThatContainsPoint(point)
97
+ // Check if the point is outside the walkable boundary.
98
+ const triIndex = walkable.triThatContainsPoint(point)
99
99
 
100
100
  // If it is...
101
101
  if (triIndex === -1) {
@@ -113,10 +113,7 @@ if (speed !== 0) {
113
113
  dot: -Infinity,
114
114
  point: null,
115
115
  triIndex: null,
116
- direction: {
117
- x: null,
118
- z: null
119
- }
116
+ direction: Vector[3](null, null, null)
120
117
  }
121
118
 
122
119
  let boundaryAppearsFlat = false
@@ -139,9 +136,9 @@ if (speed !== 0) {
139
136
 
140
137
  // Get the position of the center of the neighbor.
141
138
  const point = Vector.add(Vector.floor(Vector.add(safeIterationResult.point, direction)), 0.5)
142
- const triIndex = mesh.triThatContainsPoint(point)
139
+ const triIndex = walkable.triThatContainsPoint(point)
143
140
 
144
- // If it isn't part of the mesh, exclude it from consideration.
141
+ // If it isn't part of the walkable, exclude it from consideration.
145
142
  if (triIndex === -1)
146
143
  continue
147
144
 
@@ -199,7 +196,7 @@ if (speed !== 0) {
199
196
 
200
197
  // Construct the point along the way to the neighbor.
201
198
  const point = Vector.add(safeIterationResult.point, Vector.multiply(forceVectorToNeighbor, timeElapsedDuringThisIteration))
202
- const triIndex = mesh.triThatContainsPoint(point)
199
+ const triIndex = walkable.triThatContainsPoint(point)
203
200
  safeIterationResult.forceVector = forceVectorToNeighbor
204
201
 
205
202
  if (triIndex === -1) {
@@ -265,8 +262,8 @@ if (speed !== 0) {
265
262
  }
266
263
  }
267
264
 
268
- // Interpolate the y position of the collision mesh at the given { x, y } coordinates.
269
- const triData = mesh.triTable[safeIterationResult.triIndex]
265
+ // Interpolate the y position of the walkable at the given { x, y } coordinates.
266
+ const triData = walkable.triTable[safeIterationResult.triIndex]
270
267
  const flooredZ = Math.floor(safeIterationResult.point.z)
271
268
  const row = triData.rows[flooredZ - triData.zRange.min]
272
269
  const t = (safeIterationResult.point.x - row.xyRange.min.x) / Number(row.cardinality)
@@ -1,19 +1,19 @@
1
- mesh.updateRouteID(ROUTE_ID)
1
+ walkable.updateRouteID(ROUTE_ID)
2
2
 
3
3
  if (SKIP_RUNTIME_STATE_DISTRIBUTION)
4
4
  return
5
5
 
6
6
  // Binary search better than embedded match.
7
- mesh.triIndex = (() => {
7
+ walkable.triIndex = (() => {
8
8
 
9
9
  let low = 0
10
- let high = mesh.triTable.length - 1
10
+ let high = walkable.triTable.length - 1
11
11
 
12
12
  while (low <= high) {
13
13
 
14
14
  const mid = (low + high) >>> 1
15
- const triData = mesh.triTable[mid]
16
- const nextTriData = mesh.triTable[mid + 1]
15
+ const triData = walkable.triTable[mid]
16
+ const nextTriData = walkable.triTable[mid + 1]
17
17
 
18
18
  if (ROUTE_ID < triData.offset)
19
19
  high = mid - 1
@@ -27,10 +27,10 @@ mesh.triIndex = (() => {
27
27
  return 0
28
28
  })()
29
29
 
30
- ROUTE_ID -= mesh.triTable[mesh.triIndex].offset
30
+ ROUTE_ID -= walkable.triTable[walkable.triIndex].offset
31
31
 
32
32
  // Embedded match can become binary search later.
33
- for (const row of mesh.triTable[mesh.triIndex].rows) {
33
+ for (const row of walkable.triTable[walkable.triIndex].rows) {
34
34
 
35
35
  if (!row)
36
36
  continue
@@ -38,8 +38,8 @@ for (const row of mesh.triTable[mesh.triIndex].rows) {
38
38
  const rowWidth = BigInt(row.xyRange.max.x - row.xyRange.min.x + 1)
39
39
 
40
40
  if (ROUTE_ID < row.offset + rowWidth) {
41
- mesh.position.x = row.xyRange.min.x + Number(ROUTE_ID - row.offset)
42
- mesh.position.z = row.z
41
+ walkable.position.x = row.xyRange.min.x + Number(ROUTE_ID - row.offset)
42
+ walkable.position.z = row.z
43
43
  break
44
44
  }
45
45
  }
@@ -1,4 +1,4 @@
1
- const triIndex = mesh.triThatContainsPoint(MODEL)
2
- const triData = mesh.triTable[triIndex]
1
+ const triIndex = walkable.triThatContainsPoint(MODEL)
2
+ const triData = walkable.triTable[triIndex]
3
3
  const row = triData.rows[Math.floor(MODEL.z) - triData.zRange.min]
4
4
  return triData.offset + row.offset + BigInt(Math.floor(MODEL.x) - row.xyRange.min.x)
@@ -0,0 +1,109 @@
1
+ declare interface IWalkable<TOwner>
2
+ extends IPart<TOwner, null> {
3
+
4
+ // Serialized Properties.
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: IVector3, DELTA_TIME: number, ENABLE_SLIDING: boolean): IWalkableRayCastResult
8
+ /** Checks if a point (x, y, z) rounds to a valid pixel within the specified tri's memoized row data. */
9
+ readonly triContainsPoint(TRI_INDEX: IWalkableTriIndex, POINT: IVector3): boolean
10
+ /** Returns whether or not the given point is in a tri. @returns the index of the tri that contains the point. -1 otherwise. */
11
+ readonly triThatContainsPoint(POINT: IVector3): IWalkableTriIndex
12
+
13
+ // Runtime Properties.
14
+ /** The memoization data of every tri in the walkable, stored by tri index at build-time. */
15
+ readonly triTable: IWalkableTriData[]
16
+ /** The index of the current tri in the walkable. */
17
+ readonly triIndex?: IWalkableTriIndex
18
+ /** The current position of the state in the walkable. */
19
+ readonly position: IVector3
20
+ readonly manifest: IWalkableManifest
21
+ /** A cache of the pre-processed geometry data obtained by running the getData method. */
22
+ readonly data: IWalkableData
23
+ }
24
+
25
+ declare interface IWalkableRayCastResult {
26
+ /** Whether or not the ray hit the walkable boundary. */
27
+ readonly hit: boolean
28
+ /** The tri the ray most recently occupied when it hit the boundary or the index of the boundary where the ray stopped if there is no hit. */
29
+ readonly triIndex: IWalkableTriIndex
30
+ /** The rounded cell position where the cast ray landed. */
31
+ readonly point: IVector3
32
+ /** The force vector used to cast the ray, which might be different from the input if sliding is enabled as it may point along the direction of the most recent sliding iteration. */
33
+ readonly forceVector: IVector3
34
+ }
35
+
36
+ declare interface IWalkableTriData {
37
+ /** The original point array of the tri as taken from `walkable.getData()`. */
38
+ readonly points: IWalkableTriPoints
39
+ /** The z-axis range of the tri. */
40
+ readonly zRange: {
41
+ /** The z position of the top-most row of the tri. */
42
+ readonly min: number
43
+ /** The z position of the bottom-most row of the tri. */
44
+ readonly max: number
45
+ }
46
+ /** The rows of pixels in the tri. */
47
+ readonly rows: IWalkableTriDataRow[]
48
+ /** The offset of the tri in the overall walkable. */
49
+ readonly offset: bigint
50
+ /** The total number of pixels in the tri. */
51
+ readonly cardinality: bigint
52
+ }
53
+
54
+ declare interface IWalkableTriDataRow {
55
+ /** The z position of this row of the tri's space. */
56
+ readonly z: number
57
+ /** The x-axis range of the row stored with the corresponding y-axis coordinate at those two points. */
58
+ readonly xyRange: {
59
+ /** The smallest x position that is within the tri row. */
60
+ readonly min: {
61
+ readonly x: number,
62
+ readonly y: number
63
+ }
64
+ /** The largest x position that is within the tri row. */
65
+ readonly max: {
66
+ readonly x: number,
67
+ readonly y: number
68
+ }
69
+ }
70
+ /** The bigint offset of this row in the overall tri. */
71
+ readonly offset: bigint
72
+ /** The number of points in the given row. */
73
+ readonly cardinality: bigint
74
+ }
75
+
76
+
77
+ declare interface IWalkableManifest
78
+ extends IPartManifest {
79
+ /** The available walkable vertices as a flat array of 2D coordinates. Used for defining the world's walkable tris. */
80
+ readonly points: number[],
81
+ /** The list of walkable triangles, as a flat array of point triples. Used to define the walkable area of the world. */
82
+ readonly tris: number[]
83
+ }
84
+
85
+ declare type IWalkableData = {
86
+ readonly walkable: [IWalkablePoint[], IWalkableTri[]]
87
+ }
88
+
89
+ declare type IWalkableTri =
90
+ [IWalkablePointIndex, IWalkablePointIndex, IWalkablePointIndex]
91
+
92
+ declare type IWalkablePointIndex =
93
+ number
94
+
95
+ declare type IWalkableTriPoints =
96
+ [IWalkablePoint, IWalkablePoint, IWalkablePoint]
97
+
98
+ declare type IWalkablePoint =
99
+ [x: number, y: number, z: number]
100
+
101
+ declare type IWalkableTriIndex =
102
+ number
103
+
104
+ declare type IWalkableAny =
105
+ IWalkable<IPartAny>
106
+
107
+ declare const walkable: IWalkableAny
108
+
109
+ declare const TRI: IWalkableTriData
@@ -1,3 +1,5 @@
1
+ await agent.promise
2
+
1
3
  addressBar.define({
2
4
  throttleDuration: { value: agent.isSafari ? 350 : 75 },
3
5
  throttleStartTime: { value: _.now, writable: true }
@@ -61,10 +61,7 @@ logScope(0, "Finalizing Hydration", log => {
61
61
  })
62
62
 
63
63
  // Prevent normal click events to ensure the pointerdown event always takes precedence.
64
- document.addEventListener("click", pointerEvent => {
65
- pointerEvent.preventDefault()
66
- pointerEvent.stopPropagation()
67
- }, { capture: true })
64
+ document.addEventListener("click", client.blockClicks, { capture: true })
68
65
 
69
66
  log("Setting Initial State")
70
67
  // Propagate the initial state (matched to the snapshot exactly).
@@ -0,0 +1,17 @@
1
+ const clickHandler = POINTER_EVENT.target.getAttribute("data-onclick")
2
+
3
+ if (clickHandler) {
4
+
5
+ const [partHost, methodName, ...args] = JSON.parse(clickHandler)
6
+ const part = partsByHost[partHost]
7
+
8
+ if (part[methodName] && typeof part[methodName] === "function")
9
+ part[methodName](...args)
10
+ else
11
+ throw new ReferenceError(`ClickAttr Error: could not find a method called "${methodName}" on part ${partHost}.`)
12
+
13
+ return
14
+ }
15
+
16
+ POINTER_EVENT.preventDefault()
17
+ POINTER_EVENT.stopPropagation()
@@ -3,6 +3,9 @@
3
3
  "methods": {
4
4
  "loop-request": [
5
5
  "REQUEST_TIME"
6
+ ],
7
+ "clicks-block": [
8
+ "POINTER_EVENT"
6
9
  ]
7
10
  }
8
11
  }
@@ -4,6 +4,8 @@ declare interface IClient
4
4
  // Serialized Properties.
5
5
  /** Requests an animation frame that distributes the loop function throughout the ecosystem and calls itself again. @remarks Can only be run on the client. */
6
6
  readonly requestLoop(REQUEST_TIME: DOMHighResTimeStamp): void
7
+ /** The click event handler that is used globally on the client to prevent the click event from taking precedence over pointer events. */
8
+ readonly blockClicks(POINTER_EVENT: PointerEvent): void
7
9
 
8
10
  // Runtime Properties.
9
11
  /** Whether or not the server-rendered page has been fully "taken over" by the client-side framework. @remarks Can only become true in the client environment. */
@@ -94,9 +94,11 @@ const
94
94
  document.addEventListener("pointermove", drag, { capture: true, signal: controller.signal })
95
95
  document.addEventListener("pointerup", drop, { capture: true, signal: controller.signal })
96
96
  document.addEventListener("pointercancel", reset, { capture: true, signal: controller.signal })
97
+ pointer.id = POINTER_CONFIG.POINTER_EVENT.pointerId
97
98
 
98
99
  // Don't allow anything else to start picking up events.
99
- POINTER_CONFIG.TARGET_ELEMENT.setPointerCapture(pointer.id = POINTER_CONFIG.POINTER_EVENT.pointerId)
100
+ if (!document.pointerLockElement)
101
+ POINTER_CONFIG.TARGET_ELEMENT.setPointerCapture(pointer.id)
100
102
 
101
103
  // Allow CSS styles to target the element while its down.
102
104
  POINTER_CONFIG.TARGET_ELEMENT.classList.add("down")
@@ -62,7 +62,7 @@ const
62
62
 
63
63
  // color.device.light = !prefersDarkMode
64
64
  _.setRoute(`https://${host}${pathname}`)
65
- status = +(host in _.menuApplications ? 200 : _.applications[host].status ?? 503)
65
+ status = +(host in _.menuApplications ? 200 : _.applications[host].status ?? 200)
66
66
  const customHeaders = _.applications[host].customHeaders ?? {}
67
67
  head = { ...indexHeader, ...customHeaders }
68
68
  body = _['part.html']
@@ -6,6 +6,40 @@ html {
6
6
  linear-gradient(45deg, var(--bg) 25%, transparent 25%, transparent 75%, var(--bg) 75%, var(--bg)) 1px 1px / 2px 2px;
7
7
  }
8
8
 
9
+ wallpaper->* {
10
+ --deep-inset-dpx:
11
+ inset var(--d-1px) var(--d-1px) var(--bg-light-est),
12
+ inset var(--d1px) var(--d1px) var(--bg-dark),
13
+ inset var(--d-2px) var(--d-2px) var(--bg-light-er),
14
+ inset var(--d2px) var(--d2px) black;
15
+ --deep-outset-dpx:
16
+ inset var(--d-1px) var(--d-1px) black,
17
+ inset var(--d1px) var(--d1px) var(--bg-light-er),
18
+ inset var(--d-2px) var(--d-2px) var(--bg-dark),
19
+ inset var(--d2px) var(--d2px) var(--bg-light-est);
20
+ --bg-checker-dpx-color: var(--bg);
21
+ --bg-checker-dpx:
22
+ linear-gradient(45deg, var(--bg-checker-dpx-color) 25%, transparent 25%, transparent 75%, var(--bg-checker-dpx-color) 75%, var(--bg-checker-dpx-color)) 0 0 / var(--d2px) var(--d2px),
23
+ linear-gradient(45deg, var(--bg-checker-dpx-color) 25%, transparent 25%, transparent 75%, var(--bg-checker-dpx-color) 75%, var(--bg-checker-dpx-color)) var(--d1px) var(--d1px) / var(--d2px) var(--d2px);
24
+ }
25
+
26
+ body.dark wallpaper->* {
27
+ --deep-inset-dpx:
28
+ inset var(--d-1px) var(--d-1px) var(--bg-light-est),
29
+ inset var(--d1px) var(--d1px) var(--bg-dark),
30
+ inset var(--d-2px) var(--d-2px) var(--bg-light-er),
31
+ inset var(--d2px) var(--d2px) black;
32
+ --deep-outset-dpx:
33
+ inset var(--d-1px) var(--d-1px) black,
34
+ inset var(--d1px) var(--d1px) var(--bg-light),
35
+ inset var(--d-2px) var(--d-2px) var(--bg-dark),
36
+ inset var(--d2px) var(--d2px) var(--bg-light-er);
37
+ --bg-checker-dpx-color: var(--bg);
38
+ --bg-checker-dpx:
39
+ linear-gradient(45deg, var(--bg-checker-dpx-color) 25%, transparent 25%, transparent 75%, var(--bg-checker-dpx-color) 75%, var(--bg-checker-dpx-color)) 0 0 / var(--d2px) var(--d2px),
40
+ linear-gradient(45deg, var(--bg-checker-dpx-color) 25%, transparent 25%, transparent 75%, var(--bg-checker-dpx-color) 75%, var(--bg-checker-dpx-color)) var(--d1px) var(--d1px) / var(--d2px) var(--d2px);
41
+ }
42
+
9
43
  scroll-bar {
10
44
  background: var(--bg-checker), white;
11
45
  }
@@ -197,11 +231,6 @@ task-bar {
197
231
  }
198
232
 
199
233
  body.dark {
200
- --deep-inset:
201
- inset -1px -1px var(--bg-light-est),
202
- inset 1px 1px var(--bg-dark),
203
- inset -2px -2px var(--bg-light-er),
204
- inset 2px 2px black;
205
234
  --deep-outset:
206
235
  inset -1px -1px black,
207
236
  inset 1px 1px var(--bg-light),
package/src/static.css CHANGED
@@ -47,6 +47,30 @@ body {
47
47
  -ms-user-select: none;
48
48
  }
49
49
 
50
+ html {
51
+ /* Default safe fallback (1x screens or older browsers) */
52
+ --dppx: 1;
53
+ --css-length-of-device-pixel: calc(1px / var(--dppx));
54
+ }
55
+
56
+ @media (min-resolution: 2dppx) {
57
+ html {
58
+ --dppx: 2;
59
+ }
60
+ }
61
+
62
+ @media (min-resolution: 3dppx) {
63
+ html {
64
+ --dppx: 3;
65
+ }
66
+ }
67
+
68
+ @media (min-resolution: 4dppx) {
69
+ html {
70
+ --dppx: 4;
71
+ }
72
+ }
73
+
50
74
  wallpaper- {
51
75
  --app-height: var(--wallpaper-height);
52
76
  --app-width: var(--wallpaper-width);
@@ -58,6 +82,120 @@ wallpaper- {
58
82
  overflow: hidden;
59
83
  overflow: clip;
60
84
  touch-action: manipulation;
85
+ container-type: size;
86
+ container-name: design;
87
+ }
88
+
89
+ @container design (aspect-ratio >1 / 1) {
90
+
91
+ wallpaper->* {
92
+ --design-tiles-along-app-width: 16;
93
+ --design-tiles-along-app-height: 9;
94
+ }
95
+ }
96
+
97
+ @container design (aspect-ratio <=1 / 1) {
98
+
99
+ wallpaper->* {
100
+ --design-tiles-along-app-width: 9;
101
+ --design-tiles-along-app-height: 16;
102
+ }
103
+ }
104
+
105
+ wallpaper->* {
106
+
107
+ /* UI Design based on a simple 16 x 9 or 9 x 16 square layout,
108
+ with each tile having this many "design pixels". */
109
+ --design-pixels-per-tile: 20;
110
+
111
+ --design-pixels-along-app-width:
112
+ calc(var(--design-tiles-along-app-width) * var(--design-pixels-per-tile));
113
+
114
+ --design-pixels-along-app-height:
115
+ calc(var(--design-tiles-along-app-height) * var(--design-pixels-per-tile));
116
+
117
+ --css-length-of-design-pixel-if-using-app-width:
118
+ calc(var(--app-width) / var(--design-pixels-along-app-width));
119
+
120
+ --css-length-of-design-pixel-if-using-app-height:
121
+ calc(var(--app-height) / var(--design-pixels-along-app-height));
122
+
123
+ --css-length-of-design-pixel:
124
+ min(var(--css-length-of-design-pixel-if-using-app-width), var(--css-length-of-design-pixel-if-using-app-height));
125
+
126
+
127
+ /* Now, round the design pixel down to align the pixel art to
128
+ the user device's physical screen pixels. */
129
+ --design-pixel:
130
+ max(var(--css-length-of-device-pixel), round(down, var(--css-length-of-design-pixel), var(--css-length-of-device-pixel)));
131
+
132
+ /* Now, we can define the actual size of the design area in CSS pixels. */
133
+ --ui-width: calc(var(--d1px) * var(--design-pixels-along-app-width));
134
+ --ui-height: calc(var(--d1px) * var(--design-pixels-along-app-height));
135
+
136
+ /* The design area is likely smaller than the actual container,
137
+ so we determine the offset needed to center it. */
138
+ --ui-left: calc((var(--app-width) - var(--ui-width)) / 2);
139
+ --ui-top: calc((var(--app-height) - var(--ui-height)) / 2);
140
+
141
+ /* Add some shortcuts to common design pixel amounts. */
142
+ --d1px: calc(1 * var(--design-pixel));
143
+ --d2px: calc(2 * var(--d1px));
144
+ --d3px: calc(3 * var(--d1px));
145
+ --d4px: calc(4 * var(--d1px));
146
+ --d5px: calc(5 * var(--d1px));
147
+ --d6px: calc(6 * var(--d1px));
148
+ --d7px: calc(7 * var(--d1px));
149
+ --d8px: calc(8 * var(--d1px));
150
+ --d16px: calc(16 * var(--d1px));
151
+ --d-1px: calc(-1 * var(--d1px));
152
+ --d-2px: calc(-2 * var(--d1px));
153
+ --d-3px: calc(-3 * var(--d1px));
154
+ --d-4px: calc(-4 * var(--d1px));
155
+ --d-5px: calc(-5 * var(--d1px));
156
+ --d-6px: calc(-6 * var(--d1px));
157
+ --d-7px: calc(-7 * var(--d1px));
158
+ --d-8px: calc(-8 * var(--d1px));
159
+ --d-16px: calc(-16 * var(--d1px));
160
+
161
+ /* Compute the scalar ratio between a CSS pixel and a design pixel. */
162
+ --design-scale: calc(var(--d1px) / 1px);
163
+ }
164
+
165
+ @property --ui-width {
166
+ syntax: "<length>";
167
+ initial-value: 0px;
168
+ inherits: true;
169
+ }
170
+
171
+ @property --ui-height {
172
+ syntax: "<length>";
173
+ initial-value: 0px;
174
+ inherits: true;
175
+ }
176
+
177
+ @property --ui-left {
178
+ syntax: "<length>";
179
+ initial-value: 0px;
180
+ inherits: true;
181
+ }
182
+
183
+ @property --ui-top {
184
+ syntax: "<length>";
185
+ initial-value: 0px;
186
+ inherits: true;
187
+ }
188
+
189
+ @property --d1px {
190
+ syntax: "<length>";
191
+ initial-value: 0px;
192
+ inherits: true;
193
+ }
194
+
195
+ wallpaper->* {
196
+ /* Cross-platform bug fix for Firefox's inability
197
+ to divide two values if both have units. */
198
+ --design-scale: calc(10000 * tan(atan2(var(--d1px), 10000px))) !important;
61
199
  }
62
200
 
63
201
  @media (width < 640px) {
@@ -136,7 +274,7 @@ scroll-bar>:is(.scroll-up, thumb-, .scroll-down) {
136
274
 
137
275
  scroll-bar>thumb- {
138
276
  top: calc(var(--thumb-start) + var(--track-height) * var(--fraction));
139
- height: calc(var(--track-height) / var(--ratio));
277
+ height: calc(var(--track-height) / var(--design-scale));
140
278
  }
141
279
 
142
280
  body:not(.unhydrated) scroller- {
package/src/type.d.ts CHANGED
@@ -56,7 +56,7 @@ declare interface IEcosystem
56
56
  /** The hash of the desired landing page, as computed from data parameters during the initial boot process. */
57
57
  readonly landingHash: string
58
58
  /** The model of the desired landing page, used during the initial boot process to compute `_.landingHash` and `_.landingRouteID`. */
59
- readonly landingModel: string
59
+ readonly landingModel: object
60
60
  /** The routeID of the desired landing page, as computed from data parameters during the initial boot process. */
61
61
  readonly landingRouteID: bigint
62
62
  /** A boolean that is set to `true` as soon as the route ID is set for the first time. */
@@ -398,21 +398,63 @@ declare class FenwickTree {
398
398
  }
399
399
  /** A utility class for handling arbitrary-length vectors. Any object with entirely numeric values can be treated as a vector. */
400
400
  declare class Vector {
401
- static magnitude(vector: IVector): number
402
- static normalize(vector: IVector): IVector
403
- static sign(vector: IVector): IVector
404
- static floor(vector: IVector): IVector
405
- /** Performs the given binary operation on the two values, which can each be either a vector or a number. If at least one of the values is a vector, returns a vector. Otherwise, returns a number. */
406
- static operate(value1: IVector | number, value2: IVector | number, operation: (a, b) => number): IVector | number
407
- /** Adds the two values, which can each be either a vector or a number. If at least one of the values is a vector, returns a vector. Otherwise, returns a number. */
408
- static add(value1: IVector | number, value2: IVector | number): IVector | number
409
- /** Subtracts the two values, which can each be either a vector or a number. If at least one of the values is a vector, returns a vector. Otherwise, returns a number. */
410
- static subtract(value1: IVector | number, value2: IVector | number): IVector | number
411
- /** Multiplies the two values, which can each be either a vector or a number. If at least one of the values is a vector, returns a vector. Otherwise, returns a number. */
412
- static multiply(value1: IVector | number, value2: IVector | number): IVector | number
413
- static dot(vector1: IVector, vector2: IVector): number
401
+
402
+ /** Creates the vector object `{ x, y }`. */
403
+ static 2(x: number = 0, y: number = 0): IVector2
404
+ /** Creates the vector object `{ x: 0, y: 0, z: 0 }`. */
405
+ static 3(x: number = 0, y: number = 0, z: number = 0): IVector3
406
+
407
+ /** Provides the absolute value (length) of the the given vector. Returns a number. */
408
+ static magnitude<TVector extends IVector>(vector: TVector): number
409
+ /** Normalizes the given vector so that its magnitude is exactly 1. Returns a vector of the same dimension. */
410
+ static normalize<TVector extends IVector>(vector: TVector): TVector
411
+ /** Returns the sign of the given vector. Returns a vector of the same dimension. */
412
+ static sign<TVector extends IVector>(vector: TVector): TVector
413
+ /** Returns a vector of the same dimension with all components floored. */
414
+ static floor<TVector extends IVector>(vector: TVector): TVector
415
+
416
+ /** Performs the given binary operation on vector a and number b. Returns a vector of the same dimension as vector a. */
417
+ static operate<TVector extends IVector>(a: TVector, b: number, operation: TOperation): TVector
418
+ /** Performs the given binary operation on number a and vector b. Returns a vector of the same dimension as vector b. */
419
+ static operate<TVector extends IVector>(a: number, b: TVector, operation: TOperation): TVector
420
+ /** Performs the given binary operation on vectors a and b. They must have the same dimension. Returns a vector of the same dimension. */
421
+ static operate<TVector extends IVector>(a: TVector, b: TVector, operation: TOperation): TVector
422
+ /** Performs the given binary operation on numbers a and b. Returns a number. */
423
+ static operate(a: number, b: number, operation: TOperation): number
424
+
425
+ /** Adds vector a to number b. Returns a vector of the same dimension as vector a. */
426
+ static add<TVector extends IVector>(a: TVector, b: number): TVector
427
+ /** Adds number a to bector b. Returns a vector of the same dimension as vector b. */
428
+ static add<TVector extends IVector>(a: number, b: TVector): TVector
429
+ /** Adds vectors a to b. They must have the same dimension. Returns a vector of the same dimension. */
430
+ static add<TVector extends IVector>(a: TVector, b: TVector): TVector
431
+ /** Adds numbers a to b. Returns a number. */
432
+ static add(a: number, b: number): number
433
+
434
+ /** Subtracts number b from vector a. Returns a vector of the same dimension as vector a. */
435
+ static subtract<TVector extends IVector>(a: TVector, b: number): TVector
436
+ /** Subtracts vector b from number a. Returns a vector of the same dimension as vector b. */
437
+ static subtract<TVector extends IVector>(a: number, b: TVector): TVector
438
+ /** Subtracts vector b from vector a. They must have the same dimension. Returns a vector of the same dimension. */
439
+ static subtract<TVector extends IVector>(a: TVector, b: TVector): TVector
440
+ /** Subtracts number b from number a. Returns a number. */
441
+ static subtract(a: number, b: number): number
442
+
443
+ /** Multiplies vector a by number b. Returns a vector of the same dimension as vector a. */
444
+ static multiply<TVector extends IVector>(a: TVector, b: number): TVector
445
+ /** Multiplies number a by bector b. Returns a vector of the same dimension as vector b. */
446
+ static multiply<TVector extends IVector>(a: number, b: TVector): TVector
447
+ /** Multiplies vectors a and b. They must have the same dimension. Returns a vector of the same dimension. */
448
+ static multiply<TVector extends IVector>(a: TVector, b: TVector): TVector
449
+ /** Multiplies numbers a and b. Returns a number. */
450
+ static multiply(a: number, b: number): number
451
+
452
+ /** Returns the dot product of the two vectors. The vectors must have the same dimension. Returns a number. */
453
+ static dot<TVector>(vector1: TVector, vector2: TVector): number
414
454
  }
415
455
 
456
+ declare type TOperation = (a: number, b: number) => number
457
+
416
458
  declare type IVector = Record<string, number>
417
459
  declare type IVector2 = { x: number, y: number }
418
460
  declare type IVector3 = { x: number, y: number, z: number }
@@ -1 +0,0 @@
1
- const mesh = this
@@ -1,11 +0,0 @@
1
- const { points, tris } = mesh.manifest
2
-
3
- const data = { collision: [[], []] }
4
-
5
- for (let index = 0; index < points.length; index += 2)
6
- data.collision[0].push([Math.round(points[index]), 0, Math.round(points[index + 1])])
7
-
8
- for (let index = 0; index < tris.length; index += 3)
9
- data.collision[1].push([tris[index], tris[index + 1], tris[index + 2]])
10
-
11
- return data
@@ -1 +0,0 @@
1
- return { ...mesh.position }
@@ -1,10 +0,0 @@
1
- // Check current tri first.
2
- if (mesh.triIndex !== -1 && mesh.triContainsPoint(mesh.triIndex, POINT))
3
- return mesh.triIndex
4
-
5
- // Check all tris.
6
- for (let triIndex = 0; triIndex < mesh.triTable.length; triIndex++)
7
- if (triIndex !== mesh.triIndex && mesh.triContainsPoint(triIndex, POINT))
8
- return triIndex
9
-
10
- return -1
@@ -1,109 +0,0 @@
1
- declare interface IMesh<TOwner>
2
- extends IPart<TOwner, null> {
3
-
4
- // Serialized Properties.
5
- readonly getData(): IMeshData
6
- /** Casts a ray from the current mesh 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 mesh boundary instead of stopping cold. */
7
- readonly castRay(FORCE_VECTOR: IVector3, DELTA_TIME: number, ENABLE_SLIDING: boolean): IMeshRayCastResult
8
- /** Checks if a point (x, y, z) rounds to a valid pixel within the specified tri's memoized row data. */
9
- readonly triContainsPoint(TRI_INDEX: IMeshTriIndex, POINT: IVector3): boolean
10
- /** Returns whether or not the given point is in a tri. @returns the index of the tri that contains the point. -1 otherwise. */
11
- readonly triThatContainsPoint(POINT: IVector3): IMeshTriIndex
12
-
13
- // Runtime Properties.
14
- /** The memoization data of every tri in the mesh, stored by tri index at build-time. */
15
- readonly triTable: IMeshTriData[]
16
- /** The index of the current tri in the mesh. */
17
- readonly triIndex?: IMeshTriIndex
18
- /** The current position of the state in the mesh. */
19
- readonly position: IVector3
20
- readonly manifest: IMeshManifest
21
- /** A cache of the pre-processed geometry data obtained by running the getData method. */
22
- readonly data: IMeshData
23
- }
24
-
25
- declare interface IMeshRayCastResult {
26
- /** Whether or not the ray hit the mesh boundary. */
27
- readonly hit: boolean
28
- /** The tri the ray most recently occupied when it hit the boundary or the index of the boundary where the ray stopped if there is no hit. */
29
- readonly triIndex: IMeshTriIndex
30
- /** The rounded cell position where the cast ray landed. */
31
- readonly point: IVector3
32
- /** The force vector used to cast the ray, which might be different from the input if sliding is enabled as it may point along the direction of the most recent sliding iteration. */
33
- readonly forceVector: IVector3
34
- }
35
-
36
- declare interface IMeshTriData {
37
- /** The original point array of the tri as taken from `mesh.getData()`. */
38
- readonly points: IMeshTriPoints
39
- /** The z-axis range of the tri. */
40
- readonly zRange: {
41
- /** The z position of the top-most row of the tri. */
42
- readonly min: number
43
- /** The z position of the bottom-most row of the tri. */
44
- readonly max: number
45
- }
46
- /** The rows of pixels in the tri. */
47
- readonly rows: IMeshTriDataRow[]
48
- /** The offset of the tri in the overall mesh. */
49
- readonly offset: bigint
50
- /** The total number of pixels in the tri. */
51
- readonly cardinality: bigint
52
- }
53
-
54
- declare interface IMeshTriDataRow {
55
- /** The z position of this row of the tri's space. */
56
- readonly z: number
57
- /** The x-axis range of the row stored with the corresponding y-axis coordinate at those two points. */
58
- readonly xyRange: {
59
- /** The smallest x position that is within the tri row. */
60
- readonly min: {
61
- readonly x: number,
62
- readonly y: number
63
- }
64
- /** The largest x position that is within the tri row. */
65
- readonly max: {
66
- readonly x: number,
67
- readonly y: number
68
- }
69
- }
70
- /** The bigint offset of this row in the overall tri. */
71
- readonly offset: bigint
72
- /** The number of points in the given row. */
73
- readonly cardinality: bigint
74
- }
75
-
76
-
77
- declare interface IMeshManifest
78
- extends IPartManifest {
79
- /** The available collision vertices as a flat array of 2D coordinates. Used for defining the world's collision tris. */
80
- readonly points: number[],
81
- /** The list of collision tris, as a flat array of point triples. Used to define the walkable area of the world. */
82
- readonly tris: number[]
83
- }
84
-
85
- declare type IMeshData = {
86
- readonly collision: [IMeshPoint[], IMeshTri[]]
87
- }
88
-
89
- declare type IMeshTri =
90
- [IMeshPointIndex, IMeshPointIndex, IMeshPointIndex]
91
-
92
- declare type IMeshPointIndex =
93
- number
94
-
95
- declare type IMeshTriPoints =
96
- [IMeshPoint, IMeshPoint, IMeshPoint]
97
-
98
- declare type IMeshPoint =
99
- [x: number, y: number, z: number]
100
-
101
- declare type IMeshTriIndex =
102
- number
103
-
104
- declare type IMeshAny =
105
- IMesh<IPartAny>
106
-
107
- declare const mesh: IMeshAny
108
-
109
- declare const TRI: IMeshTriData
File without changes