kireji 0.6.8 → 0.8.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 (67) hide show
  1. package/package.json +1 -1
  2. package/src/app/kireji/description +1 -1
  3. package/src/app/kireji/editor/point.js +0 -1
  4. package/src/app/kireji/editor/sections/state-space/part.html_.js +5 -5
  5. package/src/app/kireji/editor/static.css +7 -0
  6. package/src/app/kireji/editor/tab-group/mathML-subpart.js +8 -0
  7. package/src/app/kireji/sidebar/static.css +51 -15
  8. package/src/app/kireji/static.css +0 -4
  9. package/src/app/kireji/tool-bar/part.css +1 -1
  10. package/src/build.js +58 -1
  11. package/src/part.css_.js +14 -0
  12. package/src/part.html_.js +1 -1
  13. package/src/parts/abstract/clip/mathML-subpart.js +4 -0
  14. package/src/parts/abstract/match/mathML-subpart.js +9 -0
  15. package/src/parts/abstract/mesh/build.js +84 -0
  16. package/src/parts/abstract/mesh/constants.js +1 -0
  17. package/src/parts/abstract/mesh/data-get.js +11 -0
  18. package/src/parts/abstract/mesh/mathML-subpart.js +10 -0
  19. package/src/parts/abstract/mesh/model_.js +1 -0
  20. package/src/parts/abstract/mesh/part.json +18 -0
  21. package/src/parts/abstract/mesh/point-tri-contains.js +14 -0
  22. package/src/parts/abstract/mesh/point-tri-that-contains.js +10 -0
  23. package/src/parts/abstract/mesh/ray-cast.js +262 -0
  24. package/src/parts/abstract/mesh/routeID-distribute.js +42 -0
  25. package/src/parts/abstract/mesh/routeID-model-to.js +5 -0
  26. package/src/parts/abstract/mesh/type.d.ts +95 -0
  27. package/src/parts/abstract/mix/mathML-subpart.js +9 -0
  28. package/src/parts/abstract/part/mathML-subpart.js +3 -0
  29. package/src/parts/abstract/part/mathML.js +22 -0
  30. package/src/parts/abstract/part/part.json +11 -0
  31. package/src/parts/abstract/part/routeID-update.js +5 -5
  32. package/src/parts/abstract/part/type.d.ts +4 -0
  33. package/src/parts/abstract/part-mask/mathML-subpart.js +1 -0
  34. package/src/parts/abstract/part-outliner/itemHTML-recursive.js +1 -1
  35. package/src/parts/abstract/permutation/mathML-subpart.js +10 -0
  36. package/src/parts/abstract/scroller/mathML-subpart.js +1 -0
  37. package/src/parts/abstract/scroller/onscroll.js +3 -1
  38. package/src/parts/core/hot-keys/async-install.js +18 -8
  39. package/src/parts/core/hot-keys/constants.js +4 -2
  40. package/src/parts/desktop/windows/superset-get.js +1 -1
  41. package/src/{part.css → static.css} +0 -10
  42. package/src/type.d.ts +14 -2
  43. package/src/app/kireji/editor/tab-group/equation.html_.js +0 -42
  44. package/src/parts/abstract/boolean/equation-variable.html +0 -1
  45. package/src/parts/abstract/box/build.js +0 -24
  46. package/src/parts/abstract/box/constants.js +0 -1
  47. package/src/parts/abstract/box/description-abstract +0 -1
  48. package/src/parts/abstract/box/dimensions_.js +0 -1
  49. package/src/parts/abstract/box/equation.html_.js +0 -1
  50. package/src/parts/abstract/box/model_.js +0 -1
  51. package/src/parts/abstract/box/part.json +0 -3
  52. package/src/parts/abstract/box/routeID-distribute.js +0 -7
  53. package/src/parts/abstract/box/routeID-model-to.js +0 -18
  54. package/src/parts/abstract/box/title-abstract +0 -1
  55. package/src/parts/abstract/box/type.d.ts +0 -20
  56. package/src/parts/abstract/match/equation.html_.js +0 -11
  57. package/src/parts/abstract/mix/equation.html_.js +0 -11
  58. package/src/parts/abstract/part/equation-variable.html_.js +0 -1
  59. package/src/parts/abstract/part/equation.html_.js +0 -3
  60. package/src/parts/abstract/part-mask/equation-variable.html_.js +0 -1
  61. package/src/parts/abstract/part-mask/equation.html_.js +0 -1
  62. package/src/parts/abstract/permutation/equation.html_.js +0 -1
  63. package/src/parts/abstract/scroller/equation-variable.html +0 -1
  64. package/src/parts/abstract/scroller/equation.html +0 -1
  65. package/src/parts/user/part.json +0 -3
  66. package/src/parts/user/title +0 -1
  67. package/src/parts/user/type.d.ts +0 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kireji",
3
- "version": "0.6.8",
3
+ "version": "0.8.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/",
@@ -4,4 +4,4 @@ By clicking on a part in the sidebar, you can view the properties of that part a
4
4
 
5
5
  The properties also allow you to view the list of the files which are associated with each part and to see the current state of each part and its corresponding base 64 hash. These values update in real-time as you interact with any of the apps.
6
6
 
7
- You can travel away from this application, make changes in other applications, and then return here to see how those cross-origin interactions have impacted each part in the ecosystem.
7
+ You can travel away from this application, make changes in other applications, and then return here to see how those cross-origin interactions have impacted each part of the ecosystem.
@@ -163,7 +163,6 @@ const pointerConfig = {
163
163
  tabGroup.recomputeRouteID(true)
164
164
  } else {
165
165
 
166
- debug("B", tabGroup.previewTabIndex === null, BigInt(tabGroup.openTabs.length), tabGroup.maxTabCount)
167
166
  if (BigInt(tabGroup.openTabs.length) === tabGroup.maxTabCount) {
168
167
  alert("You have too many tabs open!")
169
168
  return
@@ -3,14 +3,14 @@ const cardinalityAsString = instances.includes(activePart) ? activePartCardinali
3
3
 
4
4
  return (
5
5
  instances.includes(activePart) ? (
6
+ `<h3>Equation</h3>` +
7
+ activePart.mathML(1 + (activePart.length <= 4), "variable") +
8
+ `<hr>` +
6
9
  "<h3>Cardinality</h3>" +
7
- `<p>${cardinalityAsString.length < 16 ? cardinalityAsString : scientific(activePartCardinality, true)}</p>` +
10
+ activePart.mathML(0, "value") +
8
11
  `<hr>` +
9
12
  "<h3>Hartley Entropy</h3>" +
10
- `<p>${toCharms(activePartCardinality)} (${toBits(activePartCardinality)})</p>` +
11
- `<hr>` +
12
- `<h3>Equation</h3>` +
13
- "<math>" + activePart["equation-variable.html"] + "<mo>=</mo>" + activePart["equation.html"] + "</math>"
13
+ `<math><mn>${toCharms(activePartCardinality, false)}</mn><mspace width=".5ch"/><mtext>charms</mtext><mspace width=".5ch"/><mo>(</mo><mn>${toBits(activePartCardinality, false)}</mn><mspace width=".5ch"/><mtext>bits</mtext><mo>)</mo></math>`
14
14
  ) : (
15
15
  "<p class=disabled-message>Abstract parts do not have a concrete state space.</p>"
16
16
  )
@@ -354,6 +354,13 @@ body.vintage #kireji_app editor-::after {
354
354
  pointer-events: none;
355
355
  }
356
356
 
357
+ body.vintage #kireji_app #info-state-space>section>math {
358
+ text-align: right;
359
+ margin: calc(.5 * var(--spacing));
360
+ width: min-content;
361
+ justify-self: end;
362
+ }
363
+
357
364
  @container editor-view (width > 350px) {
358
365
  body.vintage #kireji_app #info-state-space>section {
359
366
  display: grid;
@@ -0,0 +1,8 @@
1
+ const n_tabs = allSubjects.length
2
+
3
+ return [
4
+ "<mn>1</mn>",
5
+ "<mo>+</mo>",
6
+ `<munderover><mo>∑</mo><mrow><msub><mi>𝑛</mi><mi>tabs</mi></msub><mo>=</mo><mn>1</mn></mrow><mi>${n_tabs}</mi></munderover><mrow><msub><mi>𝑛</mi><mi>tabs</mi></msub><mo>(</mo><msub><mi>𝑛</mi><mi>tabs</mi></msub><mo>+</mo><mn>1</mn><mo>)</mo></mrow>`,
7
+ `<munderover><mo>∏</mo><mrow><mi>i</mi><mo>=</mo><mn>1</mn></mrow><mrow><msub><mi>𝑛</mi><mi>tabs</mi></msub></mrow></munderover><mrow><mo>(</mo><mi>${n_tabs}</mi><mo>-</mo><mi>i</mi><mo>+</mo><mn>1</mn><mo>)</mo></mrow>`
8
+ ]
@@ -1,4 +1,4 @@
1
- #kireji_app side-bar {
1
+ #kireji_app>side-bar {
2
2
  position: absolute;
3
3
  top: 0;
4
4
  left: var(--tool-bar-width);
@@ -6,6 +6,29 @@
6
6
  bottom: 0;
7
7
  }
8
8
 
9
+ @media (width > 424px) {
10
+
11
+ #kireji_app:has(side-bar) {
12
+ --sidebar-width: calc(var(--tool-bar-width) + var(--sidebar-view-width));
13
+ }
14
+ }
15
+
16
+ @media (width < 425px) {
17
+
18
+ #kireji_app:has(side-bar)>editor- {
19
+ pointer-events: none;
20
+ }
21
+
22
+ #kireji_app>width-handle {
23
+ display: none;
24
+ }
25
+
26
+ #kireji_app>side-bar {
27
+ z-index: 10000;
28
+ width: calc(var(--app-width) - var(--tool-bar-width));
29
+ }
30
+ }
31
+
9
32
  #kireji_app #sidebar-view-header {
10
33
  position: absolute;
11
34
  z-index: 10;
@@ -92,26 +115,31 @@
92
115
  position: relative;
93
116
  }
94
117
 
95
- #kireji_app #sidebar-view summary>.explore-toggle,
96
- #kireji_app #sidebar-view summary>img,
97
- #kireji_app #sidebar-view svg {
98
- height: var(--tab-icon-size);
99
- width: var(--tab-icon-size);
100
- margin: calc((var(--tab-line-height) - var(--tab-icon-size)) / 2);
101
- }
102
-
103
118
  #kireji_app outliner-spacer {
104
- width: calc(var(--tab-line-height) / 2);
119
+ width: calc(var(--depth) * var(--tab-line-height) / 2);
105
120
  border-radius: 0;
106
- border-right: 1px solid var(--bg-un-mode);
121
+ background:
122
+ linear-gradient(to right, transparent 0%, transparent calc(100% - 1px), var(--bg-un-mode) calc(100% - 1px), var(--bg-un-mode) 100%) 0 0 / calc(var(--tab-line-height) / 2) var(--tab-line-height);
123
+ /* border-right: 1px solid var(--bg-un-mode); */
107
124
  }
108
125
 
109
126
  #kireji_app outliner-spacer:has(+ img) {
110
- margin-right: calc(var(--tab-line-height) / 2);
127
+ width: calc((var(--depth) - 1) * var(--tab-line-height) / 2);
128
+ margin-right: var(--tab-line-height);
111
129
  }
112
130
 
113
- #kireji_app details.empty>summary>outliner-spacer:last-of-type {
114
- border: none;
131
+ /*
132
+ #kireji_app details.empty>summary>outliner-spacer:last-of-type {
133
+ border: none;
134
+ }
135
+ */
136
+
137
+ #kireji_app #sidebar-view summary>.explore-toggle,
138
+ #kireji_app #sidebar-view summary>img,
139
+ #kireji_app #sidebar-view svg {
140
+ height: var(--tab-icon-size);
141
+ width: var(--tab-icon-size);
142
+ margin: calc((var(--tab-line-height) - var(--tab-icon-size)) / 2);
115
143
  }
116
144
 
117
145
  #kireji_app #sidebar-view summary .label {
@@ -152,13 +180,21 @@ body.modern #kireji_app #sidebar-view summary {
152
180
 
153
181
  /* Vintage */
154
182
 
155
- body.vintage #kireji_app side-bar {
183
+ body.vintage #kireji_app>side-bar {
156
184
  top: 6px;
157
185
  width: calc(var(--sidebar-view-width) - (var(--handle-thickness) / 2) - 2px);
158
186
  left: calc(6px + var(--tool-bar-width));
159
187
  bottom: 6px;
160
188
  }
161
189
 
190
+
191
+ @media (width < 425px) {
192
+
193
+ body.vintage #kireji_app>side-bar {
194
+ width: calc(var(--app-width) - var(--tool-bar-width) - 12px);
195
+ }
196
+ }
197
+
162
198
  body.vintage #kireji_app side-bar::after {
163
199
  content: "";
164
200
  position: absolute;
@@ -5,10 +5,6 @@
5
5
  overscroll-behavior: none;
6
6
  }
7
7
 
8
- #kireji_app:has(side-bar) {
9
- --sidebar-width: calc(var(--tool-bar-width) + var(--sidebar-view-width));
10
- }
11
-
12
8
  body.modern {
13
9
  --tab-group-height: calc(var(--tab-line-height) + var(--spacing) / 1.5);
14
10
  --tab-line-height: 26px;
@@ -27,7 +27,7 @@ body.modern #kireji_app tool-bar {
27
27
  }
28
28
 
29
29
  body.modern #kireji_app:has(side-bar) tool-bar>button[data-active] {
30
- box-shadow: inset 3px 0 0 -1px var(--accent);
30
+ box-shadow: inset -5px 0 0 -1px var(--accent);
31
31
  }
32
32
 
33
33
  body.vintage #kireji_app tool-bar {
package/src/build.js CHANGED
@@ -90,6 +90,62 @@ function ƒ(_, compressedSubjectOrigins) {
90
90
  result[dimension] = vector[dimension] / magnitude
91
91
  return result
92
92
  }
93
+ static sign(vector) {
94
+ const result = {}
95
+ for (const dimension in vector)
96
+ result[dimension] = Math.sign(vector[dimension])
97
+ return result
98
+ }
99
+ static floor(vector) {
100
+ const result = {}
101
+ for (const dimension in vector)
102
+ result[dimension] = Math.floor(vector[dimension])
103
+ return result
104
+ }
105
+ static round(vector) {
106
+ const result = {}
107
+ for (const dimension in vector)
108
+ result[dimension] = Math.round(vector[dimension])
109
+ return result
110
+ }
111
+ static operate(value1, value2, operation) {
112
+ if (typeof value1 === "number" || typeof value2 === "number") {
113
+ if (typeof value1 === "number" && typeof value2 === "number")
114
+ return operation(value1, value2)
115
+
116
+ const result = {}
117
+ const number = typeof value1 === "number" ? value1 : value2
118
+ const vector = typeof value1 === "object" ? value1 : value2
119
+
120
+ for (const dimension in vector)
121
+ result[dimension] = operation(vector[dimension], number)
122
+
123
+ return result
124
+ }
125
+
126
+ const result = {}
127
+ const dimensions = Object.keys(value1)
128
+
129
+ if (dimensions.some(key => !(key in value2)) || Object.keys(value2).some(key => !(key in value1)))
130
+ throw new Error(`Vector Operation Error: the two vectors do not have the same keys.`)
131
+
132
+ for (const dimension of dimensions)
133
+ result[dimension] = operation(value1[dimension], value2[dimension])
134
+
135
+ return result
136
+ }
137
+ static add(value1, value2) {
138
+ return this.operate(value1, value2, (a, b) => a + b)
139
+ }
140
+ static subtract(value1, value2) {
141
+ return this.operate(value1, value2, (a, b) => a - b)
142
+ }
143
+ static multiply(value1, value2) {
144
+ return this.operate(value1, value2, (a, b) => a * b)
145
+ }
146
+ static dot(vector1, vector2) {
147
+ return vector1.x * vector2.x + vector1.y * vector2.y
148
+ }
93
149
  }
94
150
  class FenwickTree {
95
151
  static LSB = []
@@ -933,5 +989,6 @@ function ƒ(_, compressedSubjectOrigins) {
933
989
  hangHydration: "0",
934
990
  haltHydration: "0",
935
991
  defaultApplicationHost: "kireji.app",
936
- port: "3000"
992
+ port: "3000",
993
+ showWarning: "1"
937
994
  })
@@ -0,0 +1,14 @@
1
+ return /* css */`
2
+
3
+ html, body {
4
+ --warning-height: ${+_.showWarning ? "26px" : "0px"};
5
+ }${+_.showWarning ? `
6
+
7
+ @media (width < 390px) {
8
+
9
+ html,
10
+ body {
11
+ --warning-height: 49px;
12
+ }
13
+ }` : ""}
14
+ ` + _["static.css"]
package/src/part.html_.js CHANGED
@@ -20,7 +20,7 @@ return _.injectImages(/* html */`<!DOCTYPE html>
20
20
  <style id="application-css">${application["part.css"]}</style>
21
21
  </head>
22
22
  <body class="unhydrated ${[era.arm.key, color.arm.key, ...taskBar.menu.classes, ...application.classes].join(" ")}">
23
- <warning->🚧 App in Alpha. Features subject to change/break without notice.</warning->
23
+ ${+_.showWarning ? `<warning->🚧 App in Alpha. Features subject to change/break without notice.</warning->` : ""}
24
24
  <title-bar autofocus tabIndex=0>
25
25
  <img class="part-icon" src="${icon}"/>
26
26
  <span id=application-title>${title}</span>
@@ -0,0 +1,4 @@
1
+ if (DEPTH <= 0)
2
+ return [/* xml */`<mi>frames</mi><mo>(</mo><msub><mi>𝑝</mi><mi>${clip.key}</mi></msub><mo>)</mo>`]
3
+
4
+ return [`<mn>${clip.cardinality}</mn>`]
@@ -0,0 +1,9 @@
1
+ const defaultTerm = /* xml */`<mn>1</mn>`
2
+
3
+ if (DEPTH <= 0 || part.length === 0)
4
+ // Strip the "<math>" tags off.
5
+ return [match.length ? /* xml */`<mo largeop="true">∑</mo><msub><mi>𝑘</mi><msub><mi>𝑝</mi><mi>${part.key ?? "ecosystem"}</mi></msub></msub>` : defaultTerm]
6
+
7
+ const operator = "<mo>+</mo>"
8
+ const addends = part.map(addend => addend.mathML(DEPTH - 1, "none", LABELS, true, false))
9
+ return addends.length ? addends.flatMap(addend => [addend, operator]).slice(0, -1) : [defaultTerm]
@@ -0,0 +1,84 @@
1
+ mesh.define({
2
+ triTable: { value: [] },
3
+ triIndex: { value: -1, writable: true },
4
+ position: { value: { x: null, y: null } },
5
+ cardinality: {
6
+ resolve() {
7
+ let meshCardinality = 0n
8
+
9
+ // Obtain the raw data for this mesh.
10
+ const [pointList, tris] = mesh.getData()
11
+
12
+ // Iterate over each tri (array of three point indices) in the data.
13
+ for (const tri of tris) {
14
+
15
+ // Prepare the per-tri cardinality sum.
16
+ let triCardinality = 0n
17
+
18
+ // Recover the true points of the tri.
19
+ const points = tri.map(pointID => pointList[pointID])
20
+
21
+ // Get just the y-coordinate of all the points.
22
+ const yPoints = points.map(point => point[1])
23
+
24
+ // Estimate the y-range of this tri.
25
+ const range = {
26
+ min: Math.min(...yPoints),
27
+ max: Math.max(...yPoints)
28
+ }
29
+
30
+ // Iterate over the range inclusively to populate each row subspace.
31
+ const rows = []
32
+ for (let rowID = range.min; rowID <= range.max; rowID++) {
33
+
34
+ // This irrational offset ensures that all grid points lie vertically in at most one triangular region.
35
+ const offsetRowID = rowID + (Math.PI / 3.141 - 0.5)
36
+
37
+ // Iterate over the 3 lines in order to determine where the edges intersect the given row.
38
+ const intersections = []
39
+ for (let edgeID = 0; edgeID < 3; edgeID++) {
40
+
41
+ const pointA = points[edgeID]
42
+ const pointB = points[(edgeID + 1) % 3]
43
+
44
+ if ((pointA[1] <= offsetRowID && pointB[1] > offsetRowID) || (pointB[1] <= offsetRowID && pointA[1] > offsetRowID))
45
+ intersections.push(pointA[0] + ((offsetRowID - pointA[1]) / (pointB[1] - pointA[1])) * (pointB[0] - pointA[0]))
46
+ }
47
+
48
+ if (intersections.length < 2) {
49
+ // This row doesn't have a full pixel. Adjust the range.
50
+ if (rowID <= range.min + 1) range.min = rowID + 1
51
+ else if (rowID >= range.max - 1) range.max = rowID - 1
52
+ else throw new Error("Unexpected tri geometry found in mesh.")
53
+ continue
54
+ }
55
+
56
+ /** @type {IMeshTriDataRow} */
57
+ const row = {
58
+ y: rowID,
59
+ range: {
60
+ min: Math.ceil(Math.min(...intersections)),
61
+ max: Math.ceil(Math.max(...intersections)) - 1,
62
+ },
63
+ offset: triCardinality
64
+ }
65
+ rows.push(row)
66
+ triCardinality += BigInt(row.range.max - row.range.min + 1)
67
+ }
68
+
69
+ // Store the tri.
70
+ mesh.triTable.push({
71
+ points,
72
+ range,
73
+ rows,
74
+ offset: meshCardinality,
75
+ cardinality: triCardinality
76
+ })
77
+
78
+ meshCardinality += triCardinality
79
+ }
80
+
81
+ return meshCardinality
82
+ }
83
+ }
84
+ })
@@ -0,0 +1 @@
1
+ const mesh = this
@@ -0,0 +1,11 @@
1
+ const { points, tris } = mesh.manifest
2
+
3
+ const data = [[], []]
4
+
5
+ for (let index = 0; index < points.length; index += 2)
6
+ data[0].push([points[index], points[index + 1]])
7
+
8
+ for (let index = 0; index < tris.length; index += 3)
9
+ data[1].push([tris[index], tris[index + 1], tris[index + 2]])
10
+
11
+ return data
@@ -0,0 +1,10 @@
1
+ if (DEPTH <= 0)
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>`,
4
+ `<munder><mo>∑</mo><mrow><mi>r</mi><mo>∈</mo><mi>rows</mi><mo>(</mo><mi>t</mi><mo>)</mo></mrow></munder>`,
5
+ `<msub><mi>𝑘</mi><mi>r</mi></msub>`
6
+ ]
7
+
8
+ return /*mesh.triTable.length > 20 ? base(DEPTH) :*/ mesh.triTable.flatMap(triData => {
9
+ return [`<mn>${triData.cardinality}</mn>`, "<mo>+</mo>"]
10
+ }).slice(0, -1)
@@ -0,0 +1 @@
1
+ return { ...mesh.position }
@@ -0,0 +1,18 @@
1
+ {
2
+ "abstract": true,
3
+ "methods": {
4
+ "data-get": [],
5
+ "point-tri-contains": [
6
+ "TRI_INDEX",
7
+ "POINT"
8
+ ],
9
+ "point-tri-that-contains": [
10
+ "POINT"
11
+ ],
12
+ "ray-cast": [
13
+ "FORCE_VECTOR",
14
+ "DELTA_TIME",
15
+ "ENABLE_SLIDING"
16
+ ]
17
+ }
18
+ }
@@ -0,0 +1,14 @@
1
+ const roundedY = Math.floor(POINT.y)
2
+ const triData = mesh.triTable[TRI_INDEX]
3
+
4
+ if (roundedY < triData.range.min || roundedY > triData.range.max)
5
+ return false
6
+
7
+ const row = triData.rows[roundedY - triData.range.min]
8
+
9
+ if (!row)
10
+ return false
11
+
12
+ const roundedX = Math.floor(POINT.x)
13
+
14
+ return roundedX >= row.range.min && roundedX <= row.range.max
@@ -0,0 +1,10 @@
1
+ // Check current tri first.
2
+ if (mesh.triIndex !== -1 && mesh.triContainsPoint(mesh.triIndex, POINT))
3
+ return mesh.triIndex
4
+
5
+ // Check all tris. TODO: Memoize neighbors.
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