@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.
Files changed (129) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +15 -0
  3. package/assets.json +346 -0
  4. package/package.json +32 -0
  5. package/release.json +135 -0
  6. package/src/audio/game-audio-preference.ts +9 -0
  7. package/src/authoritative.ts +6 -0
  8. package/src/catalog.ts +1 -0
  9. package/src/index.ts +14 -0
  10. package/src/legacy-stock-catalog.ts +130 -0
  11. package/src/pages/lobby/lobby-types.ts +140 -0
  12. package/src/pages/lobby/marble-factory.ts +931 -0
  13. package/src/pages/play/race/egypt-elevator-blender.ts +159 -0
  14. package/src/pages/play/race/egypt-portal-frame.ts +382 -0
  15. package/src/pages/play/race/finish-detection.ts +1 -0
  16. package/src/pages/play/race/japanese-sakura-castle-support-blender.ts +510 -0
  17. package/src/pages/play/race/japanese-sakura-kawara-roof.ts +201 -0
  18. package/src/pages/play/race/japanese-sakura-portal-frame.ts +325 -0
  19. package/src/pages/play/race/jungle-portal-frame.ts +308 -0
  20. package/src/pages/play/race/jungle-temple-lift.ts +366 -0
  21. package/src/pages/play/race/marble-entity.ts +257 -0
  22. package/src/pages/play/race/marble-material.ts +20 -0
  23. package/src/pages/play/race/marble-race-engine.ts +2652 -0
  24. package/src/pages/play/race/path-pattern-layout.ts +142 -0
  25. package/src/pages/play/race/peg-obstacle-visual.ts +171 -0
  26. package/src/pages/play/race/physics-debug.ts +1 -0
  27. package/src/pages/play/race/physics-dry-run.ts +90 -0
  28. package/src/pages/play/race/portal-derived-elevator-skins.ts +729 -0
  29. package/src/pages/play/race/portal-pair-color.ts +20 -0
  30. package/src/pages/play/race/portal-proportions.ts +25 -0
  31. package/src/pages/play/race/portal-visual.ts +1108 -0
  32. package/src/pages/play/race/race-camera-director.ts +586 -0
  33. package/src/pages/play/race/race-camera-obstruction.ts +37 -0
  34. package/src/pages/play/race/race-camera-tour-planner.ts +274 -0
  35. package/src/pages/play/race/race-camera.ts +206 -0
  36. package/src/pages/play/race/race-completion.ts +5 -0
  37. package/src/pages/play/race/race-configuration.ts +57 -0
  38. package/src/pages/play/race/race-marble-focus-renderer.ts +134 -0
  39. package/src/pages/play/race/race-physics-profile.ts +7 -0
  40. package/src/pages/play/race/race-physics.ts +16 -0
  41. package/src/pages/play/race/race-playback.ts +41 -0
  42. package/src/pages/play/race/race-rolling-audio.ts +616 -0
  43. package/src/pages/play/race/race-simulation-renderer.ts +221 -0
  44. package/src/pages/play/race/race-terminal-checker-strip.ts +226 -0
  45. package/src/pages/play/race/race-transform-interpolation.ts +50 -0
  46. package/src/pages/play/race/race-types.ts +12 -0
  47. package/src/pages/play/race/rebound-visual.ts +70 -0
  48. package/src/pages/play/race/seeded-random.ts +23 -0
  49. package/src/pages/play/race/space-station-portal-frame.ts +275 -0
  50. package/src/pages/play/race/track-appearance-canopy.ts +946 -0
  51. package/src/pages/play/race/track-appearance-floor-runner.ts +206 -0
  52. package/src/pages/play/race/track-appearance-jungle-flower-hedge.ts +483 -0
  53. package/src/pages/play/race/track-appearance-rope-wall.ts +443 -0
  54. package/src/pages/play/race/track-appearance-sakura-bridge-fence.ts +305 -0
  55. package/src/pages/play/race/track-appearance-sakura-castle-wall.ts +1031 -0
  56. package/src/pages/play/race/track-appearance-space-station-wall.ts +497 -0
  57. package/src/pages/play/race/track-appearance-stone-block-shell.ts +517 -0
  58. package/src/pages/play/race/track-appearance-support.ts +983 -0
  59. package/src/pages/play/race/track-appearance-vampire-carved-wall.ts +545 -0
  60. package/src/pages/play/race/track-appearance-wall-terminal.ts +167 -0
  61. package/src/pages/play/race/track-course.ts +271 -0
  62. package/src/pages/play/race/track-definition.ts +443 -0
  63. package/src/pages/play/race/track-fence-architecture.ts +33 -0
  64. package/src/pages/play/race/track-floor-material-rules.ts +51 -0
  65. package/src/pages/play/race/track-mechanisms.ts +1350 -0
  66. package/src/pages/play/race/track-physics-surface.ts +6 -0
  67. package/src/pages/play/race/track-route-network.ts +9 -0
  68. package/src/pages/play/race/track-shadow-batching.ts +760 -0
  69. package/src/pages/play/race/track-surface-basis.ts +1 -0
  70. package/src/pages/play/race/track-surface-topology.ts +326 -0
  71. package/src/pages/play/race/track-world.ts +10181 -0
  72. package/src/pages/play/race/under-track-support-architecture.ts +122 -0
  73. package/src/pages/play/race/vortex-profile.ts +5 -0
  74. package/src/pages/play/race/vortex-water-effect.ts +863 -0
  75. package/src/pages/play/race/wild-west-mine-lift.ts +281 -0
  76. package/src/pages/play/race/wild-west-vortex-housing.ts +572 -0
  77. package/src/pages/track-lab/atlas-vortex-layout.ts +1 -0
  78. package/src/pages/track-lab/cone-field-layout.ts +1 -0
  79. package/src/pages/track-lab/conveyor-layout.ts +1 -0
  80. package/src/pages/track-lab/engine/canonical-track-assembly.ts +64 -0
  81. package/src/pages/track-lab/engine/editor-object-geometry.ts +170 -0
  82. package/src/pages/track-lab/engine/track-lab-connection-state.ts +123 -0
  83. package/src/pages/track-lab/engine/track-piece-visual.ts +1420 -0
  84. package/src/pages/track-lab/flipper-bank-layout.ts +1 -0
  85. package/src/pages/track-lab/flipper-component.ts +127 -0
  86. package/src/pages/track-lab/rising-wall-layout.ts +1 -0
  87. package/src/pages/track-lab/simple-obstacle-layout.ts +1 -0
  88. package/src/pages/track-lab/track-piece-layout.ts +28 -0
  89. package/src/pages/track-lab/track-runtime-adapter.ts +1152 -0
  90. package/src/three/geometry-attribute-aliases.ts +24 -0
  91. package/src/three/geometry-detail.ts +36 -0
  92. package/src/three/homepage-marble-geometry.ts +15 -0
  93. package/src/three/japanese-sakura-appearance.ts +252 -0
  94. package/src/three/jungle-flower-hedge-appearance.ts +7 -0
  95. package/src/three/jungle-temple-appearance.ts +5 -0
  96. package/src/three/low-quality-scene-renderer.ts +132 -0
  97. package/src/three/marble-sphere-geometry.ts +13 -0
  98. package/src/three/mobile-rendering-budget.ts +11 -0
  99. package/src/three/painted-valley-appearance.ts +270 -0
  100. package/src/three/railroad-appearance.ts +71 -0
  101. package/src/three/renderer-resize.ts +32 -0
  102. package/src/three/rope-wall-appearance.ts +91 -0
  103. package/src/three/rugged-track-appearance.ts +2 -0
  104. package/src/three/scene-lighting.ts +183 -0
  105. package/src/three/scene-shader-preparation.ts +64 -0
  106. package/src/three/scene-theme-controller.ts +461 -0
  107. package/src/three/shadow-shader-preparation.ts +162 -0
  108. package/src/three/shared-obstacle-metal.ts +44 -0
  109. package/src/three/soft-additive-particles.ts +57 -0
  110. package/src/three/space-station-appearance.ts +213 -0
  111. package/src/three/static-track-batched-mesh.ts +132 -0
  112. package/src/three/stone-track-shell-appearance.ts +12 -0
  113. package/src/three/theme-ambience-controller.ts +226 -0
  114. package/src/three/theme-asset-cache.ts +120 -0
  115. package/src/three/theme-audio-preference.ts +43 -0
  116. package/src/three/theme-catalog.ts +1457 -0
  117. package/src/three/theme-material-assets.ts +258 -0
  118. package/src/three/theme-material-ktx2-manifest.ts +190 -0
  119. package/src/three/theme-material-registry.ts +1952 -0
  120. package/src/three/theme-world-factory.ts +590 -0
  121. package/src/three/track-connector-batch.ts +125 -0
  122. package/src/three/track-material-continuity.ts +442 -0
  123. package/src/three/track-theme.ts +535 -0
  124. package/src/three/vampire-castle-appearance.ts +258 -0
  125. package/src/three/visual-frame-pacing.ts +19 -0
  126. package/src/three/visual-geometry.ts +120 -0
  127. package/src/three/visual-quality.ts +83 -0
  128. package/src/three/water-appearance.ts +29 -0
  129. 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
+ }