@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,305 @@
1
+ import { geometryDetailProfile } from '../../../three/geometry-detail'
2
+ import * as THREE from 'three'
3
+
4
+ import { VisualLatheGeometry, VisualExtrudeGeometry, VisualBoxGeometry } from '../../../three/visual-geometry'
5
+
6
+ import {
7
+ canonicalWallFrameAt,
8
+ resampleCanonicalWallRun,
9
+ type CanonicalWallRun,
10
+ type RawWallFrame,
11
+ } from './track-surface-topology'
12
+ import { woodenFenceHeight, woodenFencePostCount, WOODEN_FENCE_HEIGHT_RATIO } from './track-fence-architecture'
13
+
14
+ export type SakuraBridgeFencePathFrame = RawWallFrame
15
+ export type SakuraBridgeFencePathRun = CanonicalWallRun
16
+
17
+ export interface SakuraBridgeFenceMaterials {
18
+ timber: THREE.Material
19
+ hardware: THREE.Material
20
+ }
21
+
22
+ const RAIL_SAMPLE_SPACING = 1.2 * geometryDetailProfile.ribbonTolerance
23
+ const POST_WIDTH_RATIO = 0.15
24
+ const POST_DEPTH_RATIO = 0.17
25
+ const BALUSTER_WIDTH_RATIO = 0.08
26
+ const BALUSTER_DEPTH_RATIO = 0.065
27
+ const FINIAL_REFERENCE_POST_HEIGHT = 1.28
28
+ const FINIAL_HEIGHT = 0.325
29
+
30
+ /**
31
+ * Adds an open vermilion Japanese bridge fence over the unchanged wall
32
+ * collider: lacquered timber posts and rails with gunmetal giboshi finials.
33
+ */
34
+ export function addSakuraBridgeFenceVisual(
35
+ root: THREE.Group,
36
+ id: string,
37
+ runs: readonly SakuraBridgeFencePathRun[],
38
+ wallHeight: number,
39
+ materials: SakuraBridgeFenceMaterials,
40
+ ): THREE.Group | undefined {
41
+ if (wallHeight <= 0.3) return undefined
42
+
43
+ const group = new THREE.Group()
44
+ group.name = `${id}-sakura-vermilion-bridge-fence`
45
+ group.userData.themeOnly = 'japanese-sakura-lake'
46
+ group.userData.decorative = true
47
+ group.userData.visualOnly = true
48
+ group.userData.appearance = 'japanese-sakura-vermilion-bridge-fence'
49
+ group.userData.constructionContract = 'japanese-sakura-vermilion-bridge-fence-v5'
50
+ group.userData.wallHeightRatio = WOODEN_FENCE_HEIGHT_RATIO
51
+ group.userData.balustersPerPanel = 3
52
+ group.userData.balusterWidthRatio = BALUSTER_WIDTH_RATIO
53
+ group.userData.balusterDepthRatio = BALUSTER_DEPTH_RATIO
54
+
55
+ const postMatrices: THREE.Matrix4[] = []
56
+ const railMatrices: THREE.Matrix4[] = []
57
+ const balusterMatrices: THREE.Matrix4[] = []
58
+ const knobMatrices: THREE.Matrix4[] = []
59
+ const ownedPostPositions: THREE.Vector3[] = []
60
+ let suppressedConnectedPostCount = 0
61
+ let runCount = 0
62
+
63
+ for (const run of runs) {
64
+ if (run.frames.length < 2) continue
65
+ const canonicalRun = run
66
+ const frames = resampleCanonicalWallRun(canonicalRun, RAIL_SAMPLE_SPACING).frames
67
+ const totalLength = canonicalRun.length
68
+ if (totalLength <= 0.001) continue
69
+ runCount += 1
70
+
71
+ const overallFenceHeight = woodenFenceHeight(wallHeight)
72
+ // The finial is part of the silhouette, so reserve its scaled height
73
+ // inside the shared fence-height envelope rather than adding it on top.
74
+ const postHeight = overallFenceHeight / (1 + FINIAL_HEIGHT / FINIAL_REFERENCE_POST_HEIGHT)
75
+ const postCount = woodenFencePostCount(totalLength, overallFenceHeight)
76
+ for (let postIndex = 0; postIndex < postCount; postIndex += 1) {
77
+ const distance = (postIndex / (postCount - 1)) * totalLength
78
+ const frame = canonicalWallFrameAt(canonicalRun, distance)
79
+ // A connected run never owns its start post. At an ordinary connector
80
+ // the incoming neighbour owns it; at a T-junction the straight receiver
81
+ // owns the single corner post while the circular branch rails terminate
82
+ // against it. This prevents doubled posts and paired finials.
83
+ if (postIndex === 0 && run.startOwnership === 'connected') {
84
+ suppressedConnectedPostCount += 1
85
+ continue
86
+ }
87
+ if (ownedPostPositions.some(position => position.distanceToSquared(frame.base) <= 0.025 * 0.025)) {
88
+ suppressedConnectedPostCount += 1
89
+ continue
90
+ }
91
+ ownedPostPositions.push(frame.base.clone())
92
+ const worldUp = new THREE.Vector3(0, 1, 0)
93
+ const rotation = verticalFrameQuaternion(frame)
94
+ postMatrices.push(
95
+ new THREE.Matrix4().compose(
96
+ frame.base.clone().addScaledVector(worldUp, postHeight / 2 - 0.03),
97
+ rotation,
98
+ new THREE.Vector3(postHeight * POST_WIDTH_RATIO, postHeight, postHeight * POST_DEPTH_RATIO),
99
+ ),
100
+ )
101
+ knobMatrices.push(
102
+ new THREE.Matrix4().compose(
103
+ frame.base.clone().addScaledVector(worldUp, postHeight - 0.03),
104
+ rotation,
105
+ new THREE.Vector3(1, 1, 1).multiplyScalar(postHeight / FINIAL_REFERENCE_POST_HEIGHT),
106
+ ),
107
+ )
108
+ }
109
+
110
+ for (let panelIndex = 0; panelIndex < postCount - 1; panelIndex += 1) {
111
+ const panelStart = (panelIndex / (postCount - 1)) * totalLength
112
+ const panelEnd = ((panelIndex + 1) / (postCount - 1)) * totalLength
113
+ const balusterCount = 3
114
+ for (let balusterIndex = 0; balusterIndex < balusterCount; balusterIndex += 1) {
115
+ const distance = THREE.MathUtils.lerp(panelStart, panelEnd, (balusterIndex + 1) / 4)
116
+ const frame = canonicalWallFrameAt(canonicalRun, distance)
117
+ const bottomRailTop = postHeight * (0.16 + 0.13 / 2)
118
+ const middleRailBottom = postHeight * (0.55 - 0.13 / 2)
119
+ const balusterHeight = Math.max(0.16, middleRailBottom - bottomRailTop)
120
+ balusterMatrices.push(
121
+ new THREE.Matrix4().compose(
122
+ frame.base.clone().add(new THREE.Vector3(0, (bottomRailTop + middleRailBottom) / 2 - 0.03, 0)),
123
+ verticalFrameQuaternion(frame),
124
+ new THREE.Vector3(
125
+ postHeight * BALUSTER_WIDTH_RATIO,
126
+ balusterHeight,
127
+ postHeight * BALUSTER_DEPTH_RATIO,
128
+ ),
129
+ ),
130
+ )
131
+ }
132
+ }
133
+
134
+ for (let index = 0; index < frames.length - 1; index += 1) {
135
+ const start = frames[index]!
136
+ const end = frames[index + 1]!
137
+ const outward = start.outward.clone().add(end.outward).normalize()
138
+ for (const [heightFraction, heightRatio, depthRatio] of [
139
+ [0.16, 0.13, 0.11],
140
+ [0.55, 0.13, 0.11],
141
+ [0.84, 0.12, 0.11],
142
+ ] as const) {
143
+ const startPoint = start.base.clone().add(new THREE.Vector3(0, postHeight * heightFraction - 0.03, 0))
144
+ const endPoint = end.base.clone().add(new THREE.Vector3(0, postHeight * heightFraction - 0.03, 0))
145
+ appendRailMatrix(
146
+ railMatrices,
147
+ startPoint,
148
+ endPoint,
149
+ outward,
150
+ postHeight * heightRatio,
151
+ postHeight * depthRatio,
152
+ )
153
+ }
154
+ }
155
+ }
156
+
157
+ if (runCount === 0) return undefined
158
+ if (postMatrices.length > 0) {
159
+ const geometry = useAuthoredUv(new VisualBoxGeometry(1, 1, 1, 3, 0.12))
160
+ geometry.name = 'sakura-bridge-chunky-post-geometry'
161
+ group.add(instancedBatch(`${id}-sakura-bridge-posts`, geometry, materials.timber, postMatrices))
162
+ }
163
+ if (railMatrices.length > 0) {
164
+ const geometry = useAuthoredUv(createProfiledRailGeometry())
165
+ geometry.name = 'sakura-bridge-profiled-longitudinal-rail-geometry'
166
+ group.add(instancedBatch(`${id}-sakura-bridge-rails`, geometry, materials.timber, railMatrices))
167
+ }
168
+ if (balusterMatrices.length > 0) {
169
+ const geometry = useAuthoredUv(new VisualBoxGeometry(1, 1, 1, 3, 0.12))
170
+ geometry.name = 'sakura-bridge-lower-panel-baluster-geometry'
171
+ group.add(instancedBatch(`${id}-sakura-bridge-balusters`, geometry, materials.timber, balusterMatrices))
172
+ }
173
+ if (knobMatrices.length > 0) {
174
+ group.add(instancedBatch(`${id}-sakura-bridge-gunmetal-knobs`, createGiboshiGeometry(), materials.hardware, knobMatrices))
175
+ }
176
+
177
+ group.userData.runCount = runCount
178
+ group.userData.postCount = postMatrices.length
179
+ group.userData.railCount = railMatrices.length
180
+ group.userData.balusterCount = balusterMatrices.length
181
+ group.userData.knobCount = knobMatrices.length
182
+ group.userData.suppressedConnectedPostCount = suppressedConnectedPostCount
183
+ group.userData.connectedPostOwnership = 'incoming-or-t-receiver'
184
+ root.add(group)
185
+ return group
186
+ }
187
+
188
+ function appendRailMatrix(
189
+ target: THREE.Matrix4[],
190
+ start: THREE.Vector3,
191
+ end: THREE.Vector3,
192
+ outward: THREE.Vector3,
193
+ height: number,
194
+ depth: number,
195
+ ): void {
196
+ const direction = end.clone().sub(start)
197
+ const length = direction.length()
198
+ if (length <= 0.001) return
199
+ const xAxis = direction.normalize()
200
+ const zAxis = outward.clone().addScaledVector(xAxis, -outward.dot(xAxis))
201
+ if (zAxis.lengthSq() < 0.000_001) return
202
+ zAxis.normalize()
203
+ const yAxis = new THREE.Vector3().crossVectors(zAxis, xAxis).normalize()
204
+ const rotation = new THREE.Quaternion().setFromRotationMatrix(new THREE.Matrix4().makeBasis(xAxis, yAxis, zAxis))
205
+ target.push(
206
+ new THREE.Matrix4().compose(
207
+ start.clone().lerp(end, 0.5),
208
+ rotation,
209
+ new THREE.Vector3(length + 0.035, height, depth),
210
+ ),
211
+ )
212
+ }
213
+
214
+ function verticalFrameQuaternion(frame: SakuraBridgeFencePathFrame): THREE.Quaternion {
215
+ const yAxis = new THREE.Vector3(0, 1, 0)
216
+ const xAxis = frame.tangent.clone().addScaledVector(yAxis, -frame.tangent.dot(yAxis))
217
+ if (xAxis.lengthSq() < 0.000_001) xAxis.set(1, 0, 0)
218
+ xAxis.normalize()
219
+ const zAxis = new THREE.Vector3().crossVectors(xAxis, yAxis).normalize()
220
+ xAxis.crossVectors(yAxis, zAxis).normalize()
221
+ return new THREE.Quaternion().setFromRotationMatrix(new THREE.Matrix4().makeBasis(xAxis, yAxis, zAxis))
222
+ }
223
+
224
+ function createGiboshiGeometry(): THREE.LatheGeometry {
225
+ const profile = [
226
+ new THREE.Vector2(0, 0),
227
+ new THREE.Vector2(0.11, 0),
228
+ new THREE.Vector2(0.125, 0.012),
229
+ new THREE.Vector2(0.125, 0.03),
230
+ new THREE.Vector2(0.108, 0.042),
231
+ new THREE.Vector2(0.124, 0.052),
232
+ new THREE.Vector2(0.124, 0.07),
233
+ new THREE.Vector2(0.1, 0.083),
234
+ new THREE.Vector2(0.094, 0.098),
235
+ new THREE.Vector2(0.122, 0.132),
236
+ new THREE.Vector2(0.137, 0.17),
237
+ new THREE.Vector2(0.126, 0.195),
238
+ new THREE.Vector2(0.105, 0.222),
239
+ new THREE.Vector2(0.075, 0.255),
240
+ new THREE.Vector2(0.045, 0.282),
241
+ new THREE.Vector2(0.018, 0.307),
242
+ new THREE.Vector2(0.005, 0.319),
243
+ new THREE.Vector2(0, 0.325),
244
+ ]
245
+ const geometry = new VisualLatheGeometry([0, 1, 3, 8, 10, 12, 15, 17].map(index => profile[index]!), 32)
246
+ geometry.name = 'sakura-bridge-gunmetal-giboshi-geometry-v3'
247
+ geometry.userData.profile = 'compact-two-ring-long-taper-giboshi'
248
+ return geometry
249
+ }
250
+
251
+ function createProfiledRailGeometry(): THREE.ExtrudeGeometry {
252
+ const profile = new THREE.Shape()
253
+ profile.moveTo(-0.5, -0.32)
254
+ profile.quadraticCurveTo(-0.5, -0.5, -0.32, -0.5)
255
+ profile.lineTo(0.16, -0.5)
256
+ profile.quadraticCurveTo(0.43, -0.5, 0.53, -0.29)
257
+ profile.quadraticCurveTo(0.64, 0, 0.53, 0.29)
258
+ profile.quadraticCurveTo(0.43, 0.5, 0.16, 0.5)
259
+ profile.lineTo(-0.32, 0.5)
260
+ profile.quadraticCurveTo(-0.5, 0.5, -0.5, 0.32)
261
+ profile.closePath()
262
+ const geometry = new VisualExtrudeGeometry(profile, {
263
+ depth: 1,
264
+ steps: 1,
265
+ curveSegments: 5,
266
+ bevelEnabled: false,
267
+ })
268
+ geometry.rotateY(-Math.PI / 2)
269
+ geometry.translate(0.5, 0, 0)
270
+ geometry.computeVertexNormals()
271
+ geometry.userData.profile = 'flat-rear-crowned-fascia-bullnose'
272
+ geometry.userData.grainDirection = 'longitudinal'
273
+ return geometry
274
+ }
275
+
276
+ function useAuthoredUv<T extends THREE.BufferGeometry>(geometry: T): T {
277
+ const uv = geometry.getAttribute('uv')
278
+ const authored = new Float32Array(uv.count * 4)
279
+ for (let index = 0; index < uv.count; index += 1) authored[index * 4 + 2] = 1
280
+ geometry.setAttribute('themeNetUv', new THREE.BufferAttribute(authored, 4))
281
+ geometry.setAttribute('uv1', uv.clone())
282
+ geometry.userData.textureMapping = 'authored-aligned-pbr'
283
+ return geometry
284
+ }
285
+
286
+
287
+ function instancedBatch(
288
+ name: string,
289
+ geometry: THREE.BufferGeometry,
290
+ material: THREE.Material,
291
+ matrices: readonly THREE.Matrix4[],
292
+ ): THREE.InstancedMesh {
293
+ const mesh = new THREE.InstancedMesh(geometry, material, matrices.length)
294
+ mesh.name = name
295
+ mesh.userData.themeOnly = 'japanese-sakura-lake'
296
+ mesh.userData.decorative = true
297
+ mesh.userData.visualOnly = true
298
+ mesh.castShadow = true
299
+ mesh.receiveShadow = true
300
+ matrices.forEach((matrix, index) => mesh.setMatrixAt(index, matrix))
301
+ mesh.instanceMatrix.needsUpdate = true
302
+ mesh.computeBoundingBox()
303
+ mesh.computeBoundingSphere()
304
+ return mesh
305
+ }