kireji 0.12.0 → 0.13.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.
- package/package.json +1 -1
- package/src/app/kireji/issue-tracker/pathname-translate-canonical.js +0 -10
- package/src/build.js +10 -1
- package/src/parts/abstract/mesh/build.js +32 -22
- package/src/parts/abstract/mesh/data-get.js +1 -2
- package/src/parts/abstract/mesh/point-tri-contains.js +4 -4
- package/src/parts/abstract/mesh/ray-cast.js +209 -186
- package/src/parts/abstract/mesh/routeID-distribute.js +3 -3
- package/src/parts/abstract/mesh/routeID-model-to.js +2 -2
- package/src/parts/abstract/mesh/type.d.ts +35 -25
- package/src/parts/abstract/part/mathML.js +0 -2
- package/src/parts/abstract/scroller/onscroll.js +0 -2
- package/src/parts/core/agent/fullscreen-toggle.js +28 -0
- package/src/parts/core/agent/part.json +6 -1
- package/src/parts/core/agent/type.d.ts +4 -0
- package/src/parts/desktop/about/constants.js +1 -0
- package/src/parts/desktop/about/menu-item.html_.js +1 -0
- package/src/parts/desktop/about/part.css +3 -0
- package/src/parts/desktop/about/part.html_.js +7 -8
- package/src/parts/desktop/about/type.d.ts +6 -0
- package/src/parts/desktop/era/modern/part.css +11 -6
- package/src/parts/desktop/era/vintage/part.css_.js +2 -2
- package/src/parts/desktop/era/vintage/static.css +4 -3
- package/src/parts/desktop/task-bar/menu/constants.js +2 -1
- package/src/parts/desktop/task-bar/menu/menu.html_.js +1 -1
- package/src/parts/desktop/task-bar/tray/fullscreen/point.js +1 -17
- package/src/static.css +9 -0
- package/src/type.d.ts +1 -0
package/package.json
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
const { model } = _
|
|
2
2
|
|
|
3
|
-
debug('yes, it is translating ...')
|
|
4
|
-
|
|
5
3
|
if (!("app" in model))
|
|
6
4
|
model.app = {}
|
|
7
5
|
|
|
@@ -20,14 +18,6 @@ if (PATHNAME === "/") {
|
|
|
20
18
|
|
|
21
19
|
const parts = PATHNAME.split("/").slice(1)
|
|
22
20
|
|
|
23
|
-
debug({
|
|
24
|
-
parts,
|
|
25
|
-
badSubpath: parts[0] !== "issues",
|
|
26
|
-
missingCode: !parts[1],
|
|
27
|
-
wrongLength: parts.length !== 2,
|
|
28
|
-
isNaN: isNaN(parts[1]),
|
|
29
|
-
notFound: !(parts[1] in kirejiIssueTracker.sections.issues)
|
|
30
|
-
})
|
|
31
21
|
if (parts[0] !== "issues" || !parts[1] || parts.length !== 2 || isNaN(parts[1]) || !(parts[1] in kirejiIssueTracker.sections.issues))
|
|
32
22
|
throw "Unknown Canonical Path: " + PATHNAME
|
|
33
23
|
|
package/src/build.js
CHANGED
|
@@ -147,7 +147,16 @@ function ƒ(_, compressedSubjectOrigins) {
|
|
|
147
147
|
return this.operate(value1, value2, (a, b) => a * b)
|
|
148
148
|
}
|
|
149
149
|
static dot(vector1, vector2) {
|
|
150
|
-
|
|
150
|
+
let result = 0
|
|
151
|
+
const dimensions = Object.keys(vector1)
|
|
152
|
+
|
|
153
|
+
if (dimensions.some(key => !(key in vector2)) || Object.keys(vector2).some(key => !(key in vector1)))
|
|
154
|
+
throw new Error(`Vector Dot Product Error: the two vectors do not have the same keys.`)
|
|
155
|
+
|
|
156
|
+
for (const dimension of dimensions)
|
|
157
|
+
result += vector1[dimension] * vector2[dimension]
|
|
158
|
+
|
|
159
|
+
return result
|
|
151
160
|
}
|
|
152
161
|
}
|
|
153
162
|
class FenwickTree {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
mesh.define({
|
|
2
2
|
triTable: { value: [] },
|
|
3
3
|
triIndex: { value: -1, writable: true },
|
|
4
|
-
position: { value: { x: null, y: null } },
|
|
4
|
+
position: { value: { x: null, y: null, z: null } },
|
|
5
5
|
data: {
|
|
6
6
|
resolve() {
|
|
7
7
|
return mesh.getData()
|
|
@@ -23,21 +23,21 @@ mesh.define({
|
|
|
23
23
|
// Recover the true points of the tri.
|
|
24
24
|
const points = tri.map(pointID => pointList[pointID])
|
|
25
25
|
|
|
26
|
-
// Get just the
|
|
27
|
-
const
|
|
26
|
+
// Get just the z-coordinate of all the points.
|
|
27
|
+
const zPoints = points.map(point => point[2])
|
|
28
28
|
|
|
29
|
-
// Estimate the
|
|
30
|
-
const
|
|
31
|
-
min: Math.min(...
|
|
32
|
-
max: Math.max(...
|
|
29
|
+
// Estimate the z-range of this tri.
|
|
30
|
+
const zRange = {
|
|
31
|
+
min: Math.min(...zPoints),
|
|
32
|
+
max: Math.max(...zPoints)
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
// Iterate over the range inclusively to populate each row subspace.
|
|
36
36
|
const rows = []
|
|
37
|
-
for (let
|
|
37
|
+
for (let z = zRange.min; z <= zRange.max; z++) {
|
|
38
38
|
|
|
39
39
|
// This irrational offset ensures that all grid points lie vertically in at most one triangular region.
|
|
40
|
-
const offsetRowID =
|
|
40
|
+
const offsetRowID = z + (Math.PI / 3.141 - 0.5)
|
|
41
41
|
|
|
42
42
|
// Iterate over the 3 lines in order to determine where the edges intersect the given row.
|
|
43
43
|
const intersections = []
|
|
@@ -46,35 +46,45 @@ mesh.define({
|
|
|
46
46
|
const pointA = points[edgeID]
|
|
47
47
|
const pointB = points[(edgeID + 1) % 3]
|
|
48
48
|
|
|
49
|
-
if ((pointA[
|
|
50
|
-
|
|
49
|
+
if ((pointA[2] <= offsetRowID && pointB[2] > offsetRowID) || (pointB[2] <= offsetRowID && pointA[2] > offsetRowID)) {
|
|
50
|
+
const t = (offsetRowID - pointA[2]) / (pointB[2] - pointA[2])
|
|
51
|
+
intersections.push({
|
|
52
|
+
x: pointA[0] + t * (pointB[0] - pointA[0]),
|
|
53
|
+
y: pointA[1] + t * (pointB[1] - pointA[1])
|
|
54
|
+
})
|
|
55
|
+
}
|
|
51
56
|
}
|
|
52
57
|
|
|
53
58
|
if (intersections.length < 2) {
|
|
54
|
-
// This row doesn't have a full pixel. Adjust the range.
|
|
55
|
-
if (
|
|
56
|
-
else if (
|
|
59
|
+
// This row doesn't have a full pixel. Adjust the z-range.
|
|
60
|
+
if (z <= zRange.min + 1) zRange.min = z + 1
|
|
61
|
+
else if (z >= zRange.max - 1) zRange.max = z - 1
|
|
57
62
|
else throw new Error("Unexpected tri geometry found in mesh.")
|
|
58
63
|
continue
|
|
59
64
|
}
|
|
60
65
|
|
|
66
|
+
const [min, max] = intersections[0].x <= intersections[1].x
|
|
67
|
+
? [intersections[0], intersections[1]]
|
|
68
|
+
: [intersections[1], intersections[0]]
|
|
69
|
+
|
|
70
|
+
min.x = Math.ceil(min.x)
|
|
71
|
+
max.x = Math.ceil(max.x) - 1
|
|
72
|
+
|
|
61
73
|
/** @type {IMeshTriDataRow} */
|
|
62
74
|
const row = {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
},
|
|
68
|
-
offset: triCardinality
|
|
75
|
+
z,
|
|
76
|
+
xyRange: { min, max },
|
|
77
|
+
offset: triCardinality,
|
|
78
|
+
cardinality: BigInt(max.x - min.x + 1)
|
|
69
79
|
}
|
|
70
80
|
rows.push(row)
|
|
71
|
-
triCardinality +=
|
|
81
|
+
triCardinality += row.cardinality
|
|
72
82
|
}
|
|
73
83
|
|
|
74
84
|
// Store the tri.
|
|
75
85
|
mesh.triTable.push({
|
|
76
86
|
points,
|
|
77
|
-
|
|
87
|
+
zRange,
|
|
78
88
|
rows,
|
|
79
89
|
offset: meshCardinality,
|
|
80
90
|
cardinality: triCardinality
|
|
@@ -2,9 +2,8 @@ const { points, tris } = mesh.manifest
|
|
|
2
2
|
|
|
3
3
|
const data = { collision: [[], []] }
|
|
4
4
|
|
|
5
|
-
// TODO: add a y coordinate use a default 0 for 2D meshes.
|
|
6
5
|
for (let index = 0; index < points.length; index += 2)
|
|
7
|
-
data.collision[0].push([Math.round(points[index]), Math.round(points[index + 1])])
|
|
6
|
+
data.collision[0].push([Math.round(points[index]), 0, Math.round(points[index + 1])])
|
|
8
7
|
|
|
9
8
|
for (let index = 0; index < tris.length; index += 3)
|
|
10
9
|
data.collision[1].push([tris[index], tris[index + 1], tris[index + 2]])
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
const
|
|
1
|
+
const flooredZ = Math.floor(POINT.z)
|
|
2
2
|
const triData = mesh.triTable[TRI_INDEX]
|
|
3
3
|
|
|
4
|
-
if (
|
|
4
|
+
if (flooredZ < triData.zRange.min || flooredZ > triData.zRange.max)
|
|
5
5
|
return false
|
|
6
6
|
|
|
7
|
-
const row = triData.rows[
|
|
7
|
+
const row = triData.rows[flooredZ - triData.zRange.min]
|
|
8
8
|
|
|
9
9
|
if (!row)
|
|
10
10
|
return false
|
|
11
11
|
|
|
12
12
|
const roundedX = Math.floor(POINT.x)
|
|
13
13
|
|
|
14
|
-
return roundedX >= row.
|
|
14
|
+
return roundedX >= row.xyRange.min.x && roundedX <= row.xyRange.max.x
|
|
@@ -1,259 +1,282 @@
|
|
|
1
1
|
// Define a safe result: the current position before casting.
|
|
2
|
+
/** @type {IMeshRayCastResult} */
|
|
2
3
|
const safeIterationResult = {
|
|
3
4
|
hit: false,
|
|
4
5
|
triIndex: mesh.triIndex,
|
|
5
|
-
point: {
|
|
6
|
+
point: {
|
|
7
|
+
x: mesh.position.x,
|
|
8
|
+
y: 0, // Exclude y from ray cast calculations for now.
|
|
9
|
+
z: mesh.position.z
|
|
10
|
+
},
|
|
6
11
|
forceVector: FORCE_VECTOR
|
|
7
12
|
}
|
|
8
13
|
|
|
9
14
|
// Obtain the speed of the force vector, which will be used later if we need to slide along the boundary.
|
|
10
15
|
const speed = Vector.magnitude(FORCE_VECTOR)
|
|
11
16
|
|
|
12
|
-
//
|
|
13
|
-
if (speed
|
|
14
|
-
return safeIterationResult
|
|
17
|
+
// Only cast a ray if there's movement happening.
|
|
18
|
+
if (speed !== 0) {
|
|
15
19
|
|
|
16
|
-
//
|
|
17
|
-
const timeOfNextIntersection = { x: Infinity,
|
|
18
|
-
const timeBetweenIntersections = { ...timeOfNextIntersection }
|
|
20
|
+
// Initialize timing data as though the vector doesn't intersect any grid lines.
|
|
21
|
+
const timeOfNextIntersection = { x: Infinity, z: Infinity }
|
|
22
|
+
const timeBetweenIntersections = { ...timeOfNextIntersection }
|
|
19
23
|
|
|
20
|
-
// Set the clock to zero.
|
|
21
|
-
let time = 0
|
|
24
|
+
// Set the clock to zero.
|
|
25
|
+
let time = 0
|
|
22
26
|
|
|
23
|
-
function initializeRayIntersectionSchedule(alsoComputeIntersectionInterval) {
|
|
27
|
+
function initializeRayIntersectionSchedule(alsoComputeIntersectionInterval) {
|
|
24
28
|
|
|
25
|
-
|
|
26
|
-
|
|
29
|
+
// If the force vector isn't parallel to the x axis...
|
|
30
|
+
if (FORCE_VECTOR.x !== 0) {
|
|
27
31
|
|
|
28
|
-
|
|
29
|
-
|
|
32
|
+
// Determine the x coordinate of the first grid line the ray may intersect.
|
|
33
|
+
const nextGridX = Math.floor(safeIterationResult.point.x) + (FORCE_VECTOR.x > 0)
|
|
30
34
|
|
|
31
|
-
|
|
32
|
-
|
|
35
|
+
// Compute the exact moment that intersection will happen.
|
|
36
|
+
timeOfNextIntersection.x = time + (nextGridX - safeIterationResult.point.x) / FORCE_VECTOR.x
|
|
33
37
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
+
// Compute the constant time between each grid line intersection.
|
|
39
|
+
if (alsoComputeIntersectionInterval)
|
|
40
|
+
timeBetweenIntersections.x = 1 / Math.abs(FORCE_VECTOR.x)
|
|
41
|
+
}
|
|
38
42
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
// Perform the same steps for the z-axis.
|
|
44
|
+
if (FORCE_VECTOR.z !== 0) {
|
|
45
|
+
const nextGridZ = Math.floor(safeIterationResult.point.z) + (FORCE_VECTOR.z > 0)
|
|
46
|
+
timeOfNextIntersection.z = time + (nextGridZ - safeIterationResult.point.z) / FORCE_VECTOR.z
|
|
47
|
+
if (alsoComputeIntersectionInterval)
|
|
48
|
+
timeBetweenIntersections.z = 1 / Math.abs(FORCE_VECTOR.z)
|
|
49
|
+
}
|
|
45
50
|
}
|
|
46
|
-
}
|
|
47
51
|
|
|
48
|
-
initializeRayIntersectionSchedule(true)
|
|
52
|
+
initializeRayIntersectionSchedule(true)
|
|
49
53
|
|
|
50
|
-
const start = _.now
|
|
54
|
+
const start = _.now
|
|
51
55
|
|
|
52
|
-
let iteration = 0
|
|
56
|
+
let iteration = 0
|
|
53
57
|
|
|
54
|
-
// Start iterating on the ray cast.
|
|
55
|
-
while (true) {
|
|
58
|
+
// Start iterating on the ray cast.
|
|
59
|
+
castRay: while (true) {
|
|
56
60
|
|
|
57
|
-
|
|
61
|
+
iteration++
|
|
58
62
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
63
|
+
// Emergency exit the loop.
|
|
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 })
|
|
66
|
+
break castRay
|
|
67
|
+
}
|
|
62
68
|
|
|
63
|
-
|
|
64
|
-
|
|
69
|
+
// Pick the dimension whose grid intersection will happen next.
|
|
70
|
+
const dimension = timeOfNextIntersection.x < timeOfNextIntersection.z ? "x" : "z"
|
|
65
71
|
|
|
66
|
-
|
|
67
|
-
|
|
72
|
+
// Note how much time must elapse to reach that intersection.
|
|
73
|
+
let timeElapsedDuringThisIteration = timeOfNextIntersection[dimension] - time
|
|
68
74
|
|
|
69
|
-
|
|
70
|
-
|
|
75
|
+
// Set the clock to the moment of that intersection.
|
|
76
|
+
time += timeElapsedDuringThisIteration
|
|
71
77
|
|
|
72
|
-
|
|
73
|
-
|
|
78
|
+
// Note if this is a case where the grid intersection is reached after the time limit.
|
|
79
|
+
let ranOutOfTime = time >= DELTA_TIME
|
|
74
80
|
|
|
75
|
-
|
|
76
|
-
|
|
81
|
+
// In that case...
|
|
82
|
+
if (ranOutOfTime) {
|
|
77
83
|
|
|
78
|
-
|
|
79
|
-
|
|
84
|
+
// Measure how far we are past the time limit.
|
|
85
|
+
const overshootTime = time - DELTA_TIME
|
|
80
86
|
|
|
81
|
-
|
|
82
|
-
|
|
87
|
+
// Adjust how much time we say elapsed.
|
|
88
|
+
timeElapsedDuringThisIteration -= overshootTime
|
|
83
89
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
90
|
+
// Set the block back to the last possible moment.
|
|
91
|
+
time = DELTA_TIME
|
|
92
|
+
}
|
|
87
93
|
|
|
88
|
-
|
|
89
|
-
|
|
94
|
+
// Construct the next point along the ray, given the elapsed time.
|
|
95
|
+
const point = Vector.add(safeIterationResult.point, Vector.multiply(FORCE_VECTOR, timeElapsedDuringThisIteration))
|
|
90
96
|
|
|
91
|
-
|
|
92
|
-
|
|
97
|
+
// Check if the point is outside the mesh boundary.
|
|
98
|
+
const triIndex = mesh.triThatContainsPoint(point)
|
|
93
99
|
|
|
94
|
-
|
|
95
|
-
|
|
100
|
+
// If it is...
|
|
101
|
+
if (triIndex === -1) {
|
|
96
102
|
|
|
97
|
-
|
|
98
|
-
|
|
103
|
+
// We are at a boundary pixel. Let's move our position to exactly the center of our current point.
|
|
104
|
+
// safeIterationResult.point = Vector.add(Vector.floor(safeIterationResult.point), 0.5)
|
|
99
105
|
|
|
100
|
-
|
|
101
|
-
|
|
106
|
+
// If we have permission to simulate sliding...
|
|
107
|
+
if (ENABLE_SLIDING) {
|
|
102
108
|
|
|
103
|
-
|
|
104
|
-
|
|
109
|
+
// Walk back the clock to before the ray hit.
|
|
110
|
+
time -= timeElapsedDuringThisIteration
|
|
105
111
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
112
|
+
const neighbor = {
|
|
113
|
+
dot: -Infinity,
|
|
114
|
+
point: null,
|
|
115
|
+
triIndex: null,
|
|
116
|
+
direction: {
|
|
117
|
+
x: null,
|
|
118
|
+
z: null
|
|
119
|
+
}
|
|
113
120
|
}
|
|
114
|
-
}
|
|
115
121
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
122
|
+
let boundaryAppearsFlat = false
|
|
123
|
+
|
|
124
|
+
// Search the local neighborhood of points for one that we can safely move to.
|
|
125
|
+
for (let x = -1; x <= 1; x++) for (let z = -1; z <= 1; z++) {
|
|
126
|
+
|
|
127
|
+
// Exclude the point itself
|
|
128
|
+
if (!x && !z)
|
|
129
|
+
continue
|
|
130
|
+
|
|
131
|
+
const direction = { x, y: 0, z }
|
|
132
|
+
|
|
133
|
+
// Find out how much of the force vector is cancelled out by going to this neighbor.
|
|
134
|
+
const dot = Vector.dot(Vector.normalize(direction), Vector.normalize(FORCE_VECTOR))
|
|
135
|
+
|
|
136
|
+
// If it would require traveling "against" or perpendicular to the force vector, exclude it from consideration.
|
|
137
|
+
if (dot < 0)
|
|
138
|
+
continue
|
|
139
|
+
|
|
140
|
+
// Get the position of the center of the neighbor.
|
|
141
|
+
const point = Vector.add(Vector.floor(Vector.add(safeIterationResult.point, direction)), 0.5)
|
|
142
|
+
const triIndex = mesh.triThatContainsPoint(point)
|
|
143
|
+
|
|
144
|
+
// If it isn't part of the mesh, exclude it from consideration.
|
|
145
|
+
if (triIndex === -1)
|
|
146
|
+
continue
|
|
147
|
+
|
|
148
|
+
// Store the neighbor which most agrees with the force vector.
|
|
149
|
+
if (dot >= neighbor.dot) {
|
|
150
|
+
if (dot < 0.05 && neighbor.dot !== -Infinity && neighbor.dot < 0.05) {
|
|
151
|
+
boundaryAppearsFlat = true
|
|
152
|
+
// Boundary is "flat". Don't allow perpendicular motion.
|
|
153
|
+
neighbor.dot = -Infinity
|
|
154
|
+
neighbor.point = null
|
|
155
|
+
neighbor.triIndex = null
|
|
156
|
+
neighbor.direction.x = null
|
|
157
|
+
neighbor.direction.z = null
|
|
158
|
+
} else {
|
|
159
|
+
boundaryAppearsFlat = false
|
|
160
|
+
neighbor.dot = dot
|
|
161
|
+
neighbor.point = point
|
|
162
|
+
neighbor.triIndex = triIndex
|
|
163
|
+
neighbor.direction = direction
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
133
167
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
168
|
+
if (boundaryAppearsFlat) {
|
|
169
|
+
// Do nothing for now...
|
|
170
|
+
}
|
|
137
171
|
|
|
138
|
-
// If
|
|
139
|
-
if (
|
|
140
|
-
continue
|
|
172
|
+
// If there is no neighboring point, we are "stuck". The ray cast ends here.
|
|
173
|
+
if (!neighbor.point) {
|
|
141
174
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
boundaryAppearsFlat = true
|
|
146
|
-
// Boundary is "flat". Don't allow perpendicular motion.
|
|
147
|
-
neighbor.dot = -Infinity
|
|
148
|
-
neighbor.point = null
|
|
149
|
-
neighbor.triIndex = null
|
|
150
|
-
neighbor.direction.x = null
|
|
151
|
-
neighbor.direction.y = null
|
|
152
|
-
} else {
|
|
153
|
-
boundaryAppearsFlat = false
|
|
154
|
-
neighbor.dot = dot
|
|
155
|
-
neighbor.point = point
|
|
156
|
-
neighbor.triIndex = triIndex
|
|
157
|
-
neighbor.direction = direction
|
|
158
|
-
}
|
|
175
|
+
// Return the safe result data.
|
|
176
|
+
safeIterationResult.hit = true
|
|
177
|
+
break castRay
|
|
159
178
|
}
|
|
160
|
-
}
|
|
161
179
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
180
|
+
// Compute travel distance to the center of the neighbor.
|
|
181
|
+
const vectorToNeighbor = Vector.subtract(neighbor.point, safeIterationResult.point)
|
|
182
|
+
const distance = Vector.magnitude(vectorToNeighbor)
|
|
165
183
|
|
|
166
|
-
|
|
167
|
-
|
|
184
|
+
// Construct a force vector pointing to the chosen neighbor.
|
|
185
|
+
const forceVectorToNeighbor = Vector.multiply(Vector.normalize(vectorToNeighbor), speed)
|
|
168
186
|
|
|
169
|
-
//
|
|
170
|
-
|
|
171
|
-
return safeIterationResult
|
|
172
|
-
}
|
|
187
|
+
// Compute travel time to reach the neighbor.
|
|
188
|
+
timeElapsedDuringThisIteration = distance / speed
|
|
173
189
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
const distance = Vector.magnitude(vectorToNeighbor)
|
|
190
|
+
// Move the clock ahead to our arrival at the neighbor.
|
|
191
|
+
time += timeElapsedDuringThisIteration
|
|
177
192
|
|
|
178
|
-
|
|
179
|
-
|
|
193
|
+
// Check again if we ran out of time.
|
|
194
|
+
ranOutOfTime = time >= DELTA_TIME
|
|
195
|
+
if (ranOutOfTime) {
|
|
196
|
+
const overshootTime = time - DELTA_TIME
|
|
197
|
+
timeElapsedDuringThisIteration -= overshootTime
|
|
198
|
+
time = DELTA_TIME
|
|
180
199
|
|
|
181
|
-
|
|
182
|
-
|
|
200
|
+
// Construct the point along the way to the neighbor.
|
|
201
|
+
const point = Vector.add(safeIterationResult.point, Vector.multiply(forceVectorToNeighbor, timeElapsedDuringThisIteration))
|
|
202
|
+
const triIndex = mesh.triThatContainsPoint(point)
|
|
203
|
+
safeIterationResult.forceVector = forceVectorToNeighbor
|
|
183
204
|
|
|
184
|
-
|
|
185
|
-
|
|
205
|
+
if (triIndex === -1) {
|
|
206
|
+
// We didn't have enough time to overcome the diagonal boundary.
|
|
186
207
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
if (ranOutOfTime) {
|
|
190
|
-
const overshootTime = time - DELTA_TIME
|
|
191
|
-
timeElapsedDuringThisIteration -= overshootTime
|
|
192
|
-
time = DELTA_TIME
|
|
208
|
+
if (speed * DELTA_TIME > Math.SQRT2) {
|
|
209
|
+
// The current speed is enough to overcome diagonal corners.
|
|
193
210
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
safeIterationResult.forceVector = forceVectorToNeighbor
|
|
211
|
+
// Return the previous safe point, chalking the lost time up to friction.
|
|
212
|
+
break castRay
|
|
213
|
+
}
|
|
198
214
|
|
|
199
|
-
|
|
200
|
-
|
|
215
|
+
// There is not enough velocity to overcome the diagonal. Use random chance.
|
|
216
|
+
if (Math.random() < Math.SQRT1_2) {
|
|
217
|
+
safeIterationResult.point = neighbor.point
|
|
218
|
+
safeIterationResult.triIndex = neighbor.triIndex
|
|
219
|
+
}
|
|
201
220
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
// Return the previous safe point, chalking the lost time up to friction.
|
|
206
|
-
return safeIterationResult
|
|
207
|
-
}
|
|
221
|
+
break castRay
|
|
222
|
+
} else {
|
|
208
223
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
safeIterationResult.
|
|
212
|
-
safeIterationResult.triIndex = neighbor.triIndex
|
|
224
|
+
// Go to the partial point.
|
|
225
|
+
safeIterationResult.point = point
|
|
226
|
+
safeIterationResult.triIndex = triIndex
|
|
213
227
|
}
|
|
214
228
|
|
|
215
|
-
|
|
216
|
-
} else {
|
|
217
|
-
|
|
218
|
-
// Go to the partial point.
|
|
219
|
-
safeIterationResult.point = point
|
|
220
|
-
safeIterationResult.triIndex = triIndex
|
|
229
|
+
break castRay
|
|
221
230
|
}
|
|
222
231
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
safeIterationResult.point = neighbor.point
|
|
228
|
-
safeIterationResult.triIndex = neighbor.triIndex
|
|
229
|
-
safeIterationResult.forceVector = FORCE_VECTOR
|
|
232
|
+
// Set the neighbor as the new safe point.
|
|
233
|
+
safeIterationResult.point = neighbor.point
|
|
234
|
+
safeIterationResult.triIndex = neighbor.triIndex
|
|
235
|
+
safeIterationResult.forceVector = FORCE_VECTOR
|
|
230
236
|
|
|
231
|
-
|
|
232
|
-
|
|
237
|
+
// The normal ray intersection schedule has changed.
|
|
238
|
+
initializeRayIntersectionSchedule()
|
|
233
239
|
|
|
234
|
-
|
|
235
|
-
|
|
240
|
+
// Proceed with normal ray casting behavior from this point.
|
|
241
|
+
continue
|
|
236
242
|
|
|
237
|
-
|
|
243
|
+
} else {
|
|
238
244
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
245
|
+
// Discard the unsafe point. Return the safe result data.
|
|
246
|
+
safeIterationResult.hit = true
|
|
247
|
+
break castRay
|
|
248
|
+
}
|
|
242
249
|
}
|
|
243
|
-
}
|
|
244
250
|
|
|
245
251
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
252
|
+
// Otherwise, update the safe result.
|
|
253
|
+
safeIterationResult.point = point
|
|
254
|
+
safeIterationResult.triIndex = triIndex
|
|
249
255
|
|
|
250
|
-
|
|
251
|
-
|
|
256
|
+
// If we ran out of time...
|
|
257
|
+
if (ranOutOfTime) {
|
|
252
258
|
|
|
253
|
-
|
|
254
|
-
|
|
259
|
+
// We're done. Return the safe point.
|
|
260
|
+
break castRay
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Otherwise, Prepare for the next grid line time of this dimension.
|
|
264
|
+
timeOfNextIntersection[dimension] += timeBetweenIntersections[dimension]
|
|
255
265
|
}
|
|
266
|
+
}
|
|
256
267
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
268
|
+
// Interpolate the y position of the collision mesh at the given { x, y } coordinates.
|
|
269
|
+
const triData = mesh.triTable[safeIterationResult.triIndex]
|
|
270
|
+
const flooredZ = Math.floor(safeIterationResult.point.z)
|
|
271
|
+
const row = triData.rows[flooredZ - triData.zRange.min]
|
|
272
|
+
const t = (safeIterationResult.point.x - row.xyRange.min.x) / Number(row.cardinality)
|
|
273
|
+
safeIterationResult.point.y = row.xyRange.min.y + t * (row.xyRange.max.y - row.xyRange.min.y)
|
|
274
|
+
|
|
275
|
+
if (isNaN(safeIterationResult.point.y))
|
|
276
|
+
throw {
|
|
277
|
+
triData,
|
|
278
|
+
flooredZ,
|
|
279
|
+
row,
|
|
280
|
+
t
|
|
281
|
+
}
|
|
282
|
+
return safeIterationResult
|
|
@@ -35,11 +35,11 @@ for (const row of mesh.triTable[mesh.triIndex].rows) {
|
|
|
35
35
|
if (!row)
|
|
36
36
|
continue
|
|
37
37
|
|
|
38
|
-
const rowWidth = BigInt(row.
|
|
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.
|
|
42
|
-
mesh.position.
|
|
41
|
+
mesh.position.x = row.xyRange.min.x + Number(ROUTE_ID - row.offset)
|
|
42
|
+
mesh.position.z = row.z
|
|
43
43
|
break
|
|
44
44
|
}
|
|
45
45
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
const triIndex = mesh.triThatContainsPoint(MODEL)
|
|
2
2
|
const triData = mesh.triTable[triIndex]
|
|
3
|
-
const row = triData.rows[Math.floor(MODEL.
|
|
4
|
-
return triData.offset + row.offset + BigInt(Math.floor(MODEL.x) - row.
|
|
3
|
+
const row = triData.rows[Math.floor(MODEL.z) - triData.zRange.min]
|
|
4
|
+
return triData.offset + row.offset + BigInt(Math.floor(MODEL.x) - row.xyRange.min.x)
|
|
@@ -4,20 +4,11 @@ declare interface IMesh<TOwner>
|
|
|
4
4
|
// Serialized Properties.
|
|
5
5
|
readonly getData(): IMeshData
|
|
6
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:
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
/** 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. */
|
|
11
|
-
readonly triIndex: IMeshTriIndex
|
|
12
|
-
/** The rounded cell position where the cast ray landed. */
|
|
13
|
-
readonly position: IVector2
|
|
14
|
-
/** 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. */
|
|
15
|
-
readonly forceVector: IVector2
|
|
16
|
-
}
|
|
17
|
-
/** Checks if a point (x, y) rounds to a valid pixel within the specified tri's memoized row data. */
|
|
18
|
-
readonly triContainsPoint(TRI_INDEX: IMeshTriIndex, POINT: IVector2): boolean
|
|
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
|
|
19
10
|
/** Returns whether or not the given point is in a tri. @returns the index of the tri that contains the point. -1 otherwise. */
|
|
20
|
-
readonly triThatContainsPoint(POINT:
|
|
11
|
+
readonly triThatContainsPoint(POINT: IVector3): IMeshTriIndex
|
|
21
12
|
|
|
22
13
|
// Runtime Properties.
|
|
23
14
|
/** The memoization data of every tri in the mesh, stored by tri index at build-time. */
|
|
@@ -25,20 +16,31 @@ declare interface IMesh<TOwner>
|
|
|
25
16
|
/** The index of the current tri in the mesh. */
|
|
26
17
|
readonly triIndex?: IMeshTriIndex
|
|
27
18
|
/** The current position of the state in the mesh. */
|
|
28
|
-
readonly position:
|
|
19
|
+
readonly position: IVector3
|
|
29
20
|
readonly manifest: IMeshManifest
|
|
30
21
|
/** A cache of the pre-processed geometry data obtained by running the getData method. */
|
|
31
22
|
readonly data: IMeshData
|
|
32
23
|
}
|
|
33
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
|
+
|
|
34
36
|
declare interface IMeshTriData {
|
|
35
37
|
/** The original point array of the tri as taken from `mesh.getData()`. */
|
|
36
38
|
readonly points: IMeshTriPoints
|
|
37
|
-
/** The
|
|
38
|
-
readonly
|
|
39
|
-
/** The
|
|
39
|
+
/** The z-axis range of the tri. */
|
|
40
|
+
readonly zRange: {
|
|
41
|
+
/** The z position of the top-most row of the tri. */
|
|
40
42
|
readonly min: number
|
|
41
|
-
/** The
|
|
43
|
+
/** The z position of the bottom-most row of the tri. */
|
|
42
44
|
readonly max: number
|
|
43
45
|
}
|
|
44
46
|
/** The rows of pixels in the tri. */
|
|
@@ -50,17 +52,25 @@ declare interface IMeshTriData {
|
|
|
50
52
|
}
|
|
51
53
|
|
|
52
54
|
declare interface IMeshTriDataRow {
|
|
53
|
-
/** The
|
|
54
|
-
readonly
|
|
55
|
-
/** The x-axis range of the row. */
|
|
56
|
-
readonly
|
|
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: {
|
|
57
59
|
/** The smallest x position that is within the tri row. */
|
|
58
|
-
readonly min:
|
|
60
|
+
readonly min: {
|
|
61
|
+
readonly x: number,
|
|
62
|
+
readonly y: number
|
|
63
|
+
}
|
|
59
64
|
/** The largest x position that is within the tri row. */
|
|
60
|
-
readonly max:
|
|
65
|
+
readonly max: {
|
|
66
|
+
readonly x: number,
|
|
67
|
+
readonly y: number
|
|
68
|
+
}
|
|
61
69
|
}
|
|
62
70
|
/** The bigint offset of this row in the overall tri. */
|
|
63
71
|
readonly offset: bigint
|
|
72
|
+
/** The number of points in the given row. */
|
|
73
|
+
readonly cardinality: bigint
|
|
64
74
|
}
|
|
65
75
|
|
|
66
76
|
|
|
@@ -86,7 +96,7 @@ declare type IMeshTriPoints =
|
|
|
86
96
|
[IMeshPoint, IMeshPoint, IMeshPoint]
|
|
87
97
|
|
|
88
98
|
declare type IMeshPoint =
|
|
89
|
-
[x: number, y: number]
|
|
99
|
+
[x: number, y: number, z: number]
|
|
90
100
|
|
|
91
101
|
declare type IMeshTriIndex =
|
|
92
102
|
number
|
|
@@ -9,8 +9,6 @@ const expression = (() => {
|
|
|
9
9
|
|
|
10
10
|
const needsParentheses = PARENTHESIZE && terms.length > 1
|
|
11
11
|
|
|
12
|
-
debug(terms)
|
|
13
|
-
|
|
14
12
|
// Allow "<mrow>" tag nesting for parentheses.
|
|
15
13
|
return (LABELS ? "<munder>" + (needsParentheses ? "" : "<mrow>") : "") + (needsParentheses ? "<mrow class=parenthetic><mo>(</mo>" : "") + terms.join("") + (needsParentheses ? `<mo>)</mo></mrow>` : "") + (LABELS ? (needsParentheses ? "" : "</mrow>") + `<munder><mo stretchy="true">⏟</mo>${recurse(0, "none", false, false)}</munder></munder>` : "")
|
|
16
14
|
})()
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
if (!document.fullscreenElement) {
|
|
2
|
+
|
|
3
|
+
if (FORCE_STATE === false)
|
|
4
|
+
return FORCE_STATE
|
|
5
|
+
|
|
6
|
+
if (document.documentElement.requestFullscreen) {
|
|
7
|
+
document.documentElement.requestFullscreen()
|
|
8
|
+
} else if (document.documentElement.webkitRequestFullscreen) {
|
|
9
|
+
document.documentElement.webkitRequestFullscreen()
|
|
10
|
+
} else if (document.documentElement.msRequestFullscreen) {
|
|
11
|
+
document.documentElement.msRequestFullscreen()
|
|
12
|
+
}
|
|
13
|
+
return true
|
|
14
|
+
} else {
|
|
15
|
+
|
|
16
|
+
if (FORCE_STATE === true)
|
|
17
|
+
return FORCE_STATE
|
|
18
|
+
|
|
19
|
+
if (document.exitFullscreen) {
|
|
20
|
+
document.exitFullscreen()
|
|
21
|
+
} else if (document.webkitExitFullscreen) {
|
|
22
|
+
document.webkitExitFullscreen()
|
|
23
|
+
} else if (document.msExitFullscreen) {
|
|
24
|
+
document.msExitFullscreen()
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return false
|
|
@@ -4,6 +4,10 @@ interface IAgent
|
|
|
4
4
|
// Runtime Properties.
|
|
5
5
|
readonly isMac: boolean
|
|
6
6
|
readonly isSafari: boolean
|
|
7
|
+
|
|
8
|
+
// Serialized Properties.
|
|
9
|
+
/** Toggles the native fullscreen feature (if available) and returns the resulting state. If FORCE_STATE is provided, sets the fullscreen mode to the given state, instead of simply toggling it. */
|
|
10
|
+
readonly toggleFullscreen(FORCE_STATE?: boolean = undefined)
|
|
7
11
|
}
|
|
8
12
|
|
|
9
13
|
declare const agent: IAgent
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const aboutEcosystem = this
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
return `<a ${_.application === aboutEcosystem ? "disabled" : _.pointAttr()} href=https://${aboutEcosystem.host}>About</a>`
|
|
@@ -7,15 +7,14 @@ const longestHost = appNames.reduce((a, b) => (a.length >= b.length ? a : b))
|
|
|
7
7
|
const worstCaseURL = `https://${longestHost}/${_.version}/${encodeSegment(_.cardinality - 1n)}/`
|
|
8
8
|
const maxURLLength = 2000
|
|
9
9
|
const stateSizeInBits = toBits(_.cardinality - 1n, false)
|
|
10
|
+
const stateSizeInCharms = toCharms(_.cardinality - 1n, false)
|
|
10
11
|
|
|
11
12
|
return /* html */`
|
|
12
13
|
<h1>Demo Ecosystem</h1>
|
|
13
14
|
${_.parts.core.update["part.html"]}
|
|
14
|
-
<
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
<li>URL Usage: ${worstCaseURL.length / maxURLLength * 100}%</li>
|
|
21
|
-
</ul>`
|
|
15
|
+
<hr>
|
|
16
|
+
<span>Installed Apps: ${appNames.length}</span>
|
|
17
|
+
<br>
|
|
18
|
+
<span>JS Usage: ${Math.round(sizeInMB / maxSizeInMB * 100)}% (${Math.round(sizeInMB * 100) / 100} MB / ${maxSizeInMB} MB)</span>
|
|
19
|
+
<br>
|
|
20
|
+
<span>URL Usage: ${Math.round(worstCaseURL.length / maxURLLength * 100)}% (${worstCaseURL.length} ch / ${maxURLLength} ch)</span>`
|
|
@@ -33,6 +33,10 @@ title-bar>.part-icon {
|
|
|
33
33
|
position: relative;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
.toggle-control:hover {
|
|
37
|
+
color: var(--accent);
|
|
38
|
+
}
|
|
39
|
+
|
|
36
40
|
.toggle-control .base {
|
|
37
41
|
width: 100%;
|
|
38
42
|
border-radius: var(--spacing);
|
|
@@ -115,10 +119,6 @@ task-menu {
|
|
|
115
119
|
width: auto;
|
|
116
120
|
}
|
|
117
121
|
|
|
118
|
-
task-menu [disabled] {
|
|
119
|
-
display: none !important;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
122
|
task-menu hr {
|
|
123
123
|
display: none;
|
|
124
124
|
}
|
|
@@ -148,6 +148,7 @@ task-menu>* {
|
|
|
148
148
|
}
|
|
149
149
|
|
|
150
150
|
#settings>span,
|
|
151
|
+
#settings>a,
|
|
151
152
|
.toggle-control {
|
|
152
153
|
gap: 1ch;
|
|
153
154
|
height: var(--spacing);
|
|
@@ -172,7 +173,6 @@ task-menu>* {
|
|
|
172
173
|
top: 2px;
|
|
173
174
|
}
|
|
174
175
|
|
|
175
|
-
|
|
176
176
|
.toggle-control[data-state="enabled"] .handle {
|
|
177
177
|
left: calc(var(--spacing) + 2px);
|
|
178
178
|
}
|
|
@@ -199,8 +199,13 @@ task-menu>* {
|
|
|
199
199
|
color: var(--accent);
|
|
200
200
|
}
|
|
201
201
|
|
|
202
|
+
#settings>a[disabled] {
|
|
203
|
+
color: var(--fg-mode-er);
|
|
204
|
+
cursor: default;
|
|
205
|
+
}
|
|
206
|
+
|
|
202
207
|
.task-link:not([data-here]):hover,
|
|
203
|
-
#
|
|
208
|
+
#settings>a:not([disabled]):hover {
|
|
204
209
|
color: var(--accent);
|
|
205
210
|
cursor: pointer;
|
|
206
211
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const menuApplicationsCount = Object.keys(_.menuApplications).length
|
|
2
|
-
const controlLinesCount =
|
|
3
|
-
const separatorCount =
|
|
2
|
+
const controlLinesCount = 3
|
|
3
|
+
const separatorCount = 1
|
|
4
4
|
return part["static.css"] + `
|
|
5
5
|
task-menu::after {
|
|
6
6
|
content: "${_.application.fancyTitle}";
|
|
@@ -112,7 +112,7 @@ scroll-bar>thumb- {
|
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
.task-link>a:hover,
|
|
115
|
-
#
|
|
115
|
+
#settings>a:not([disabled]):hover {
|
|
116
116
|
background: var(--accent);
|
|
117
117
|
color: var(--bg-mode-est);
|
|
118
118
|
}
|
|
@@ -255,13 +255,14 @@ hr {
|
|
|
255
255
|
}
|
|
256
256
|
|
|
257
257
|
[disabled],
|
|
258
|
-
[disabled]
|
|
258
|
+
[disabled] *,
|
|
259
|
+
a[disabled] {
|
|
259
260
|
pointer-events: none;
|
|
260
261
|
color: var(--bg-dark-er);
|
|
261
262
|
text-shadow: 1px 1px var(--bg-light-est);
|
|
262
263
|
}
|
|
263
264
|
|
|
264
|
-
body.dark :is([disabled], [disabled]
|
|
265
|
+
body.dark :is([disabled], [disabled] *, a[disabled]) {
|
|
265
266
|
color: var(--bg-dark-est);
|
|
266
267
|
text-shadow: 1px 1px var(--bg-light-er);
|
|
267
268
|
}
|
|
@@ -3,7 +3,7 @@ const
|
|
|
3
3
|
sections = []
|
|
4
4
|
|
|
5
5
|
// if (_.includeUpdates === "full" || (!production && _.includeUpdates === "local-only"))
|
|
6
|
-
|
|
6
|
+
controls.push(aboutEcosystem["menu-item.html"])
|
|
7
7
|
|
|
8
8
|
if (_.includeColor === "full" || (!production && _.includeColor.startsWith("debug-")))
|
|
9
9
|
controls.push(color["part.html"])
|
|
@@ -1,22 +1,6 @@
|
|
|
1
1
|
pointer.handle({
|
|
2
2
|
click() {
|
|
3
|
-
|
|
4
|
-
if (document.documentElement.requestFullscreen) {
|
|
5
|
-
document.documentElement.requestFullscreen()
|
|
6
|
-
} else if (document.documentElement.webkitRequestFullscreen) {
|
|
7
|
-
document.documentElement.webkitRequestFullscreen()
|
|
8
|
-
} else if (document.documentElement.msRequestFullscreen) {
|
|
9
|
-
document.documentElement.msRequestFullscreen()
|
|
10
|
-
}
|
|
11
|
-
} else {
|
|
12
|
-
if (document.exitFullscreen) {
|
|
13
|
-
document.exitFullscreen()
|
|
14
|
-
} else if (document.webkitExitFullscreen) {
|
|
15
|
-
document.webkitExitFullscreen()
|
|
16
|
-
} else if (document.msExitFullscreen) {
|
|
17
|
-
document.msExitFullscreen()
|
|
18
|
-
}
|
|
19
|
-
}
|
|
3
|
+
_.parts.core.agent.toggleFullScreen()
|
|
20
4
|
},
|
|
21
5
|
POINTER_EVENT,
|
|
22
6
|
TARGET_ELEMENT,
|
package/src/static.css
CHANGED
|
@@ -191,6 +191,7 @@ task-menu {
|
|
|
191
191
|
}
|
|
192
192
|
|
|
193
193
|
#settings>span,
|
|
194
|
+
#settings>a,
|
|
194
195
|
.toggle-control {
|
|
195
196
|
display: flex;
|
|
196
197
|
justify-content: space-between;
|
|
@@ -198,6 +199,14 @@ task-menu {
|
|
|
198
199
|
gap: 5px;
|
|
199
200
|
}
|
|
200
201
|
|
|
202
|
+
#settings>a:not([disabled]) {
|
|
203
|
+
color: inherit;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
#settings>a {
|
|
207
|
+
text-decoration: none;
|
|
208
|
+
}
|
|
209
|
+
|
|
201
210
|
.task-link {
|
|
202
211
|
display: contents;
|
|
203
212
|
}
|
package/src/type.d.ts
CHANGED
|
@@ -415,6 +415,7 @@ declare class Vector {
|
|
|
415
415
|
|
|
416
416
|
declare type IVector = Record<string, number>
|
|
417
417
|
declare type IVector2 = { x: number, y: number }
|
|
418
|
+
declare type IVector3 = { x: number, y: number, z: number }
|
|
418
419
|
|
|
419
420
|
declare type KirejiConfigColor =
|
|
420
421
|
/** The color component will never be included. */
|