@marble.fun/track-catalog 3.0.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/LICENSE +21 -0
- package/README.md +15 -0
- package/assets.json +346 -0
- package/package.json +32 -0
- package/release.json +135 -0
- package/src/audio/game-audio-preference.ts +9 -0
- package/src/authoritative.ts +6 -0
- package/src/catalog.ts +1 -0
- package/src/index.ts +14 -0
- package/src/legacy-stock-catalog.ts +130 -0
- package/src/pages/lobby/lobby-types.ts +140 -0
- package/src/pages/lobby/marble-factory.ts +931 -0
- package/src/pages/play/race/egypt-elevator-blender.ts +159 -0
- package/src/pages/play/race/egypt-portal-frame.ts +382 -0
- package/src/pages/play/race/finish-detection.ts +1 -0
- package/src/pages/play/race/japanese-sakura-castle-support-blender.ts +510 -0
- package/src/pages/play/race/japanese-sakura-kawara-roof.ts +201 -0
- package/src/pages/play/race/japanese-sakura-portal-frame.ts +325 -0
- package/src/pages/play/race/jungle-portal-frame.ts +308 -0
- package/src/pages/play/race/jungle-temple-lift.ts +366 -0
- package/src/pages/play/race/marble-entity.ts +257 -0
- package/src/pages/play/race/marble-material.ts +20 -0
- package/src/pages/play/race/marble-race-engine.ts +2652 -0
- package/src/pages/play/race/path-pattern-layout.ts +142 -0
- package/src/pages/play/race/peg-obstacle-visual.ts +171 -0
- package/src/pages/play/race/physics-debug.ts +1 -0
- package/src/pages/play/race/physics-dry-run.ts +90 -0
- package/src/pages/play/race/portal-derived-elevator-skins.ts +729 -0
- package/src/pages/play/race/portal-pair-color.ts +20 -0
- package/src/pages/play/race/portal-proportions.ts +25 -0
- package/src/pages/play/race/portal-visual.ts +1108 -0
- package/src/pages/play/race/race-camera-director.ts +586 -0
- package/src/pages/play/race/race-camera-obstruction.ts +37 -0
- package/src/pages/play/race/race-camera-tour-planner.ts +274 -0
- package/src/pages/play/race/race-camera.ts +206 -0
- package/src/pages/play/race/race-completion.ts +5 -0
- package/src/pages/play/race/race-configuration.ts +57 -0
- package/src/pages/play/race/race-marble-focus-renderer.ts +134 -0
- package/src/pages/play/race/race-physics-profile.ts +7 -0
- package/src/pages/play/race/race-physics.ts +16 -0
- package/src/pages/play/race/race-playback.ts +41 -0
- package/src/pages/play/race/race-rolling-audio.ts +616 -0
- package/src/pages/play/race/race-simulation-renderer.ts +221 -0
- package/src/pages/play/race/race-terminal-checker-strip.ts +226 -0
- package/src/pages/play/race/race-transform-interpolation.ts +50 -0
- package/src/pages/play/race/race-types.ts +12 -0
- package/src/pages/play/race/rebound-visual.ts +70 -0
- package/src/pages/play/race/seeded-random.ts +23 -0
- package/src/pages/play/race/space-station-portal-frame.ts +275 -0
- package/src/pages/play/race/track-appearance-canopy.ts +946 -0
- package/src/pages/play/race/track-appearance-floor-runner.ts +206 -0
- package/src/pages/play/race/track-appearance-jungle-flower-hedge.ts +483 -0
- package/src/pages/play/race/track-appearance-rope-wall.ts +443 -0
- package/src/pages/play/race/track-appearance-sakura-bridge-fence.ts +305 -0
- package/src/pages/play/race/track-appearance-sakura-castle-wall.ts +1031 -0
- package/src/pages/play/race/track-appearance-space-station-wall.ts +497 -0
- package/src/pages/play/race/track-appearance-stone-block-shell.ts +517 -0
- package/src/pages/play/race/track-appearance-support.ts +983 -0
- package/src/pages/play/race/track-appearance-vampire-carved-wall.ts +545 -0
- package/src/pages/play/race/track-appearance-wall-terminal.ts +167 -0
- package/src/pages/play/race/track-course.ts +271 -0
- package/src/pages/play/race/track-definition.ts +443 -0
- package/src/pages/play/race/track-fence-architecture.ts +33 -0
- package/src/pages/play/race/track-floor-material-rules.ts +51 -0
- package/src/pages/play/race/track-mechanisms.ts +1350 -0
- package/src/pages/play/race/track-physics-surface.ts +6 -0
- package/src/pages/play/race/track-route-network.ts +9 -0
- package/src/pages/play/race/track-shadow-batching.ts +760 -0
- package/src/pages/play/race/track-surface-basis.ts +1 -0
- package/src/pages/play/race/track-surface-topology.ts +326 -0
- package/src/pages/play/race/track-world.ts +10181 -0
- package/src/pages/play/race/under-track-support-architecture.ts +122 -0
- package/src/pages/play/race/vortex-profile.ts +5 -0
- package/src/pages/play/race/vortex-water-effect.ts +863 -0
- package/src/pages/play/race/wild-west-mine-lift.ts +281 -0
- package/src/pages/play/race/wild-west-vortex-housing.ts +572 -0
- package/src/pages/track-lab/atlas-vortex-layout.ts +1 -0
- package/src/pages/track-lab/cone-field-layout.ts +1 -0
- package/src/pages/track-lab/conveyor-layout.ts +1 -0
- package/src/pages/track-lab/engine/canonical-track-assembly.ts +64 -0
- package/src/pages/track-lab/engine/editor-object-geometry.ts +170 -0
- package/src/pages/track-lab/engine/track-lab-connection-state.ts +123 -0
- package/src/pages/track-lab/engine/track-piece-visual.ts +1420 -0
- package/src/pages/track-lab/flipper-bank-layout.ts +1 -0
- package/src/pages/track-lab/flipper-component.ts +127 -0
- package/src/pages/track-lab/rising-wall-layout.ts +1 -0
- package/src/pages/track-lab/simple-obstacle-layout.ts +1 -0
- package/src/pages/track-lab/track-piece-layout.ts +28 -0
- package/src/pages/track-lab/track-runtime-adapter.ts +1152 -0
- package/src/three/geometry-attribute-aliases.ts +24 -0
- package/src/three/geometry-detail.ts +36 -0
- package/src/three/homepage-marble-geometry.ts +15 -0
- package/src/three/japanese-sakura-appearance.ts +252 -0
- package/src/three/jungle-flower-hedge-appearance.ts +7 -0
- package/src/three/jungle-temple-appearance.ts +5 -0
- package/src/three/low-quality-scene-renderer.ts +132 -0
- package/src/three/marble-sphere-geometry.ts +13 -0
- package/src/three/mobile-rendering-budget.ts +11 -0
- package/src/three/painted-valley-appearance.ts +270 -0
- package/src/three/railroad-appearance.ts +71 -0
- package/src/three/renderer-resize.ts +32 -0
- package/src/three/rope-wall-appearance.ts +91 -0
- package/src/three/rugged-track-appearance.ts +2 -0
- package/src/three/scene-lighting.ts +183 -0
- package/src/three/scene-shader-preparation.ts +64 -0
- package/src/three/scene-theme-controller.ts +461 -0
- package/src/three/shadow-shader-preparation.ts +162 -0
- package/src/three/shared-obstacle-metal.ts +44 -0
- package/src/three/soft-additive-particles.ts +57 -0
- package/src/three/space-station-appearance.ts +213 -0
- package/src/three/static-track-batched-mesh.ts +132 -0
- package/src/three/stone-track-shell-appearance.ts +12 -0
- package/src/three/theme-ambience-controller.ts +226 -0
- package/src/three/theme-asset-cache.ts +120 -0
- package/src/three/theme-audio-preference.ts +43 -0
- package/src/three/theme-catalog.ts +1457 -0
- package/src/three/theme-material-assets.ts +258 -0
- package/src/three/theme-material-ktx2-manifest.ts +190 -0
- package/src/three/theme-material-registry.ts +1952 -0
- package/src/three/theme-world-factory.ts +590 -0
- package/src/three/track-connector-batch.ts +125 -0
- package/src/three/track-material-continuity.ts +442 -0
- package/src/three/track-theme.ts +535 -0
- package/src/three/vampire-castle-appearance.ts +258 -0
- package/src/three/visual-frame-pacing.ts +19 -0
- package/src/three/visual-geometry.ts +120 -0
- package/src/three/visual-quality.ts +83 -0
- package/src/three/water-appearance.ts +29 -0
- package/src/three/wild-west-sand-appearance.ts +2 -0
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import * as THREE from 'three'
|
|
2
|
+
|
|
3
|
+
import { STANDARD_RAILROAD_HALF_GAUGE } from '../../../three/railroad-appearance'
|
|
4
|
+
import type { RouteNetworkFrame, SurfaceRouteRun } from './track-route-network'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A standard runner occupies the same visual envelope as the established
|
|
8
|
+
* railway gauge. The floor remains visible on both sides, while narrow lanes
|
|
9
|
+
* clamp the runner inward instead of widening their authored surface.
|
|
10
|
+
*/
|
|
11
|
+
export const STANDARD_FLOOR_RUNNER_WIDTH = STANDARD_RAILROAD_HALF_GAUGE * 2
|
|
12
|
+
export const FLOOR_RUNNER_EDGE_CLEARANCE = 0.34
|
|
13
|
+
export const FLOOR_RUNNER_BASE_LIFT = 0.008
|
|
14
|
+
export const FLOOR_RUNNER_THICKNESS = 0.024
|
|
15
|
+
export const FLOOR_RUNNER_LATERAL_SEGMENTS = 12
|
|
16
|
+
|
|
17
|
+
export interface FloorRunnerFrame extends RouteNetworkFrame {
|
|
18
|
+
point: THREE.Vector3
|
|
19
|
+
right: THREE.Vector3
|
|
20
|
+
up: THREE.Vector3
|
|
21
|
+
tangent: THREE.Vector3
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface FloorRunnerOptions<Frame extends FloorRunnerFrame> {
|
|
25
|
+
themeId: string
|
|
26
|
+
appearanceMaterialId: string
|
|
27
|
+
surfacePoint(frame: Frame, normalizedLateral: number): THREE.Vector3
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface RunnerRoute<Frame extends FloorRunnerFrame> {
|
|
31
|
+
route: SurfaceRouteRun<Frame>
|
|
32
|
+
centers: THREE.Vector3[]
|
|
33
|
+
distances: number[]
|
|
34
|
+
totalLength: number
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Adds one visual-only carpet/runner batch over canonical routed floor paths.
|
|
39
|
+
* It never creates colliders and therefore composes with every base floor.
|
|
40
|
+
*/
|
|
41
|
+
export function addCenteredFloorRunnerVisual<Frame extends FloorRunnerFrame>(
|
|
42
|
+
host: THREE.Group,
|
|
43
|
+
id: string,
|
|
44
|
+
routes: readonly SurfaceRouteRun<Frame>[],
|
|
45
|
+
material: THREE.Material,
|
|
46
|
+
options: FloorRunnerOptions<Frame>,
|
|
47
|
+
): THREE.Group | undefined {
|
|
48
|
+
const validRoutes: RunnerRoute<Frame>[] = routes
|
|
49
|
+
.filter(route => route.frames.length >= 2)
|
|
50
|
+
.map(route => {
|
|
51
|
+
const centers = route.frames.map((frame, index) => {
|
|
52
|
+
const centerOffset = route.centerOffsets[index] ?? 0
|
|
53
|
+
return options.surfacePoint(frame, (centerOffset * 2) / Math.max(0.001, frame.width))
|
|
54
|
+
})
|
|
55
|
+
const distances = [0]
|
|
56
|
+
for (let index = 1; index < centers.length; index += 1) {
|
|
57
|
+
distances.push(distances.at(-1)! + centers[index]!.distanceTo(centers[index - 1]!))
|
|
58
|
+
}
|
|
59
|
+
return { route, centers, distances, totalLength: distances.at(-1) ?? 0 }
|
|
60
|
+
})
|
|
61
|
+
.filter(route => route.totalLength > 0.000_001)
|
|
62
|
+
if (validRoutes.length === 0) return undefined
|
|
63
|
+
|
|
64
|
+
const positions: number[] = []
|
|
65
|
+
const uvs: number[] = []
|
|
66
|
+
const netUvs: number[] = []
|
|
67
|
+
const indices: number[] = []
|
|
68
|
+
const appendVertex = (point: THREE.Vector3, transverse: number, longitudinal: number, totalLength: number) => {
|
|
69
|
+
positions.push(point.x, point.y, point.z)
|
|
70
|
+
uvs.push(transverse, longitudinal)
|
|
71
|
+
netUvs.push(transverse, longitudinal, 1, totalLength)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
for (const { route, distances, totalLength } of validRoutes) {
|
|
75
|
+
const routeOffset = positions.length / 3
|
|
76
|
+
for (const [index, frame] of route.frames.entries()) {
|
|
77
|
+
const laneWidth = Math.max(0.001, route.laneWidths[index] ?? frame.width)
|
|
78
|
+
const width = Math.min(STANDARD_FLOOR_RUNNER_WIDTH, Math.max(0.6, laneWidth - FLOOR_RUNNER_EDGE_CLEARANCE * 2))
|
|
79
|
+
const halfWidth = width / 2
|
|
80
|
+
const centerOffset = route.centerOffsets[index] ?? 0
|
|
81
|
+
const distance = distances[index]!
|
|
82
|
+
const surfacePoints = Array.from({ length: FLOOR_RUNNER_LATERAL_SEGMENTS + 1 }, (_unused, lateralIndex) => {
|
|
83
|
+
const transverse = THREE.MathUtils.lerp(-halfWidth, halfWidth, lateralIndex / FLOOR_RUNNER_LATERAL_SEGMENTS)
|
|
84
|
+
const lateral = ((centerOffset + transverse) * 2) / Math.max(0.001, frame.width)
|
|
85
|
+
return options.surfacePoint(frame, lateral)
|
|
86
|
+
})
|
|
87
|
+
surfacePoints.forEach((surface, lateralIndex) => {
|
|
88
|
+
const previous = surfacePoints[Math.max(0, lateralIndex - 1)]!
|
|
89
|
+
const next = surfacePoints[Math.min(surfacePoints.length - 1, lateralIndex + 1)]!
|
|
90
|
+
const across = next.clone().sub(previous).normalize()
|
|
91
|
+
const surfaceUp = new THREE.Vector3().crossVectors(frame.tangent, across).normalize()
|
|
92
|
+
if (surfaceUp.dot(frame.up) < 0) surfaceUp.negate()
|
|
93
|
+
const transverse = THREE.MathUtils.lerp(-halfWidth, halfWidth, lateralIndex / FLOOR_RUNNER_LATERAL_SEGMENTS)
|
|
94
|
+
const bottom = surface.clone().addScaledVector(surfaceUp, FLOOR_RUNNER_BASE_LIFT)
|
|
95
|
+
const top = bottom.clone().addScaledVector(surfaceUp, FLOOR_RUNNER_THICKNESS)
|
|
96
|
+
appendVertex(top, transverse, distance, totalLength)
|
|
97
|
+
appendVertex(bottom, transverse, distance, totalLength)
|
|
98
|
+
})
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const rowStride = (FLOOR_RUNNER_LATERAL_SEGMENTS + 1) * 2
|
|
102
|
+
for (let index = 0; index < route.frames.length - 1; index += 1) {
|
|
103
|
+
const currentRow = routeOffset + index * rowStride
|
|
104
|
+
const nextRow = currentRow + rowStride
|
|
105
|
+
for (let lateralIndex = 0; lateralIndex < FLOOR_RUNNER_LATERAL_SEGMENTS; lateralIndex += 1) {
|
|
106
|
+
const currentTop = currentRow + lateralIndex * 2
|
|
107
|
+
const currentBottom = currentTop + 1
|
|
108
|
+
const currentRightTop = currentTop + 2
|
|
109
|
+
const currentRightBottom = currentBottom + 2
|
|
110
|
+
const nextTop = nextRow + lateralIndex * 2
|
|
111
|
+
const nextBottom = nextTop + 1
|
|
112
|
+
const nextRightTop = nextTop + 2
|
|
113
|
+
const nextRightBottom = nextBottom + 2
|
|
114
|
+
indices.push(
|
|
115
|
+
currentTop,
|
|
116
|
+
nextTop,
|
|
117
|
+
currentRightTop,
|
|
118
|
+
currentRightTop,
|
|
119
|
+
nextTop,
|
|
120
|
+
nextRightTop,
|
|
121
|
+
currentBottom,
|
|
122
|
+
currentRightBottom,
|
|
123
|
+
nextBottom,
|
|
124
|
+
currentRightBottom,
|
|
125
|
+
nextRightBottom,
|
|
126
|
+
nextBottom,
|
|
127
|
+
)
|
|
128
|
+
}
|
|
129
|
+
const currentLeftTop = currentRow
|
|
130
|
+
const currentLeftBottom = currentLeftTop + 1
|
|
131
|
+
const nextLeftTop = nextRow
|
|
132
|
+
const nextLeftBottom = nextLeftTop + 1
|
|
133
|
+
const currentRightTop = currentRow + FLOOR_RUNNER_LATERAL_SEGMENTS * 2
|
|
134
|
+
const currentRightBottom = currentRightTop + 1
|
|
135
|
+
const nextRightTop = nextRow + FLOOR_RUNNER_LATERAL_SEGMENTS * 2
|
|
136
|
+
const nextRightBottom = nextRightTop + 1
|
|
137
|
+
indices.push(
|
|
138
|
+
currentLeftTop,
|
|
139
|
+
currentLeftBottom,
|
|
140
|
+
nextLeftTop,
|
|
141
|
+
currentLeftBottom,
|
|
142
|
+
nextLeftBottom,
|
|
143
|
+
nextLeftTop,
|
|
144
|
+
currentRightTop,
|
|
145
|
+
nextRightTop,
|
|
146
|
+
currentRightBottom,
|
|
147
|
+
currentRightBottom,
|
|
148
|
+
nextRightTop,
|
|
149
|
+
nextRightBottom,
|
|
150
|
+
)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const start = routeOffset
|
|
154
|
+
const end = routeOffset + (route.frames.length - 1) * rowStride
|
|
155
|
+
for (let lateralIndex = 0; lateralIndex < FLOOR_RUNNER_LATERAL_SEGMENTS; lateralIndex += 1) {
|
|
156
|
+
const startTop = start + lateralIndex * 2
|
|
157
|
+
const startBottom = startTop + 1
|
|
158
|
+
const startRightTop = startTop + 2
|
|
159
|
+
const startRightBottom = startBottom + 2
|
|
160
|
+
indices.push(startTop, startRightTop, startBottom, startRightTop, startRightBottom, startBottom)
|
|
161
|
+
const endTop = end + lateralIndex * 2
|
|
162
|
+
const endBottom = endTop + 1
|
|
163
|
+
const endRightTop = endTop + 2
|
|
164
|
+
const endRightBottom = endBottom + 2
|
|
165
|
+
indices.push(endTop, endBottom, endRightTop, endRightTop, endBottom, endRightBottom)
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const geometry = new THREE.BufferGeometry()
|
|
170
|
+
geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3))
|
|
171
|
+
geometry.setAttribute('uv', new THREE.Float32BufferAttribute(uvs, 2))
|
|
172
|
+
geometry.setAttribute('themeNetUv', new THREE.Float32BufferAttribute(netUvs, 4))
|
|
173
|
+
geometry.setIndex(indices)
|
|
174
|
+
geometry.computeVertexNormals()
|
|
175
|
+
geometry.computeBoundingBox()
|
|
176
|
+
geometry.computeBoundingSphere()
|
|
177
|
+
geometry.userData.floorOverlay = 'centered-runner'
|
|
178
|
+
geometry.userData.visualOnly = true
|
|
179
|
+
geometry.userData.runnerWidth = STANDARD_FLOOR_RUNNER_WIDTH
|
|
180
|
+
geometry.userData.runnerThickness = FLOOR_RUNNER_THICKNESS
|
|
181
|
+
geometry.userData.lateralSegments = FLOOR_RUNNER_LATERAL_SEGMENTS
|
|
182
|
+
geometry.userData.themeMaterialLongitudinalAxis = 'y'
|
|
183
|
+
|
|
184
|
+
const mesh = new THREE.Mesh(geometry, material)
|
|
185
|
+
mesh.name = `${id}-centered-floor-runner-overlay`
|
|
186
|
+
mesh.userData.themeOnly = options.themeId
|
|
187
|
+
mesh.userData.themeRole = 'lane-centered-floor-runner'
|
|
188
|
+
mesh.userData.appearanceMaterialId = options.appearanceMaterialId
|
|
189
|
+
mesh.userData.decorative = true
|
|
190
|
+
mesh.userData.visualOnly = true
|
|
191
|
+
mesh.castShadow = false
|
|
192
|
+
mesh.receiveShadow = true
|
|
193
|
+
|
|
194
|
+
const group = new THREE.Group()
|
|
195
|
+
group.name = `${id}-centered-floor-runner`
|
|
196
|
+
group.userData.themeOnly = options.themeId
|
|
197
|
+
group.userData.appearance = 'centered-floor-runner'
|
|
198
|
+
group.userData.representation = 'procedural-routed-surface-overlay'
|
|
199
|
+
group.userData.visualOnly = true
|
|
200
|
+
group.userData.drawCallBudget = 1
|
|
201
|
+
group.userData.routeCount = validRoutes.length
|
|
202
|
+
group.userData.runMetricLengths = validRoutes.map(route => route.totalLength)
|
|
203
|
+
group.add(mesh)
|
|
204
|
+
host.add(group)
|
|
205
|
+
return group
|
|
206
|
+
}
|