@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,1457 @@
1
+ import {
2
+ createThemeMaterialSet,
3
+ MATERIAL_SLOT_DEBUG_THEME,
4
+ NEUTRAL_STUDIO_THEME,
5
+ type MaterialRecipe,
6
+ type MaterialPatternRecipe,
7
+ type ThemeMaterialSlot,
8
+ type ThemeId,
9
+ type TrackThemeDefinition,
10
+ } from './track-theme'
11
+ import { VAMPIRE_CASTLE_THEME } from './vampire-castle-appearance'
12
+ import {
13
+ WILD_WEST_RAIL_MATERIAL_ID,
14
+ WILD_WEST_RAIL_TIE_MATERIAL_ID,
15
+ WILD_WEST_WOODEN_PLANKS_FLOOR_ID,
16
+ } from './railroad-appearance'
17
+ import { WILD_WEST_ANTIQUE_BRASS_MATERIAL_ID, WILD_WEST_GUNMETAL_FLIPPER_MATERIAL_ID } from './rugged-track-appearance'
18
+ import { SHARED_STONE_TRACK_BLOCK_MATERIAL_ID } from './stone-track-shell-appearance'
19
+ import {
20
+ WILD_WEST_CANYON_BUTTRESS_SUPPORT_ID,
21
+ WILD_WEST_TIMBER_TRESTLE_SUPPORT_ID,
22
+ WILD_WEST_TRESTLE_METAL_MATERIAL_ID,
23
+ } from '../pages/play/race/track-appearance-support'
24
+ import { WILD_WEST_SAND_FLOOR_ID, WILD_WEST_SAND_SHOULDER_MATERIAL_ID } from './wild-west-sand-appearance'
25
+ import {
26
+ SHARED_ROPE_WALL_BACKING_MATERIAL,
27
+ SHARED_ROPE_WALL_BACKING_MATERIAL_ID,
28
+ SHARED_ROPE_WALL_END_GRAIN_MATERIAL,
29
+ SHARED_ROPE_WALL_END_GRAIN_MATERIAL_ID,
30
+ SHARED_ROPE_WALL_MATERIAL,
31
+ SHARED_ROPE_WALL_MATERIAL_ID,
32
+ SHARED_ROPE_WALL_TIMBER_MATERIAL,
33
+ SHARED_ROPE_WALL_TIMBER_MATERIAL_ID,
34
+ } from './rope-wall-appearance'
35
+ import {
36
+ JUNGLE_TEMPLE_BRONZE_MATERIAL_ID,
37
+ JUNGLE_TEMPLE_FACADE_MATERIAL_ID,
38
+ JUNGLE_TEMPLE_PLATFORM_MATERIAL_ID,
39
+ JUNGLE_TEMPLE_STONE_MATERIAL_ID,
40
+ JUNGLE_TEMPLE_TIMBER_MATERIAL_ID,
41
+ } from './jungle-temple-appearance'
42
+ import {
43
+ createPaintedValleyMaterials,
44
+ PAINTED_VALLEY_BIRCH_PLANK_MATERIAL,
45
+ PAINTED_VALLEY_BIRCH_RANCH_FENCE_MATERIAL,
46
+ PAINTED_VALLEY_GRASS_ORANGE_DIRT_PATH_FLOOR_ID,
47
+ PAINTED_VALLEY_GRASS_ORANGE_DIRT_PATH_MATERIAL,
48
+ PAINTED_VALLEY_GRASS_SHOULDER_MATERIAL,
49
+ PAINTED_VALLEY_GRASS_SHOULDER_MATERIAL_ID,
50
+ PAINTED_VALLEY_THEME_ID,
51
+ PAINTED_VALLEY_TROPICAL_FLOWER_HEDGE_CORE_MATERIAL,
52
+ PAINTED_VALLEY_TROPICAL_FLOWER_HEDGE_WALL_ID,
53
+ } from './painted-valley-appearance'
54
+ import {
55
+ JAPANESE_SAKURA_BRIDGE_FENCE_ID,
56
+ JAPANESE_SAKURA_BRIDGE_HARDWARE_ID,
57
+ JAPANESE_SAKURA_BRIDGE_HARDWARE_MATERIAL,
58
+ JAPANESE_SAKURA_BRIDGE_TIMBER_ID,
59
+ JAPANESE_SAKURA_BRIDGE_TIMBER_MATERIAL,
60
+ JAPANESE_SAKURA_DRAGON_STONE_MATERIAL,
61
+ JAPANESE_SAKURA_DRAGON_STONE_SUPPORT_ID,
62
+ JAPANESE_SAKURA_CASTLE_KAWARA_ID,
63
+ JAPANESE_SAKURA_CASTLE_KAWARA_MATERIAL,
64
+ JAPANESE_SAKURA_CASTLE_MASONRY_ID,
65
+ JAPANESE_SAKURA_CASTLE_MASONRY_MATERIAL,
66
+ JAPANESE_SAKURA_CASTLE_PAVERS_ID,
67
+ JAPANESE_SAKURA_CASTLE_PAVERS_MATERIAL,
68
+ JAPANESE_SAKURA_REDWOOD_PLANKS_ID,
69
+ JAPANESE_SAKURA_REDWOOD_PLANKS_MATERIAL,
70
+ JAPANESE_SAKURA_VERMILION_UNDERBRIDGE_SUPPORT_ID,
71
+ JAPANESE_SAKURA_PORTAL_FOUNDATION_STONE_ID,
72
+ JAPANESE_SAKURA_PORTAL_FOUNDATION_STONE_MATERIAL,
73
+ JAPANESE_SAKURA_CASTLE_PLASTER_MATERIAL,
74
+ JAPANESE_SAKURA_CASTLE_TIMBER_ID,
75
+ JAPANESE_SAKURA_CASTLE_TIMBER_MATERIAL,
76
+ JAPANESE_SAKURA_CASTLE_WALL_ID,
77
+ } from './japanese-sakura-appearance'
78
+ import {
79
+ SPACE_STATION_ARMORED_WALL_ID,
80
+ SPACE_STATION_CENTER_GUIDE_ID,
81
+ SPACE_STATION_CENTER_GUIDE_MATERIAL,
82
+ SPACE_STATION_FLOOR_DECK_BASE_ID,
83
+ SPACE_STATION_FLOOR_DECK_BASE_MATERIAL,
84
+ SPACE_STATION_FLOOR_DECK_ID,
85
+ SPACE_STATION_FLOOR_DECK_MATERIAL,
86
+ SPACE_STATION_HOVER_GRID_FLOOR_ID,
87
+ SPACE_STATION_HOVER_GRID_FLOOR_MATERIAL,
88
+ SPACE_STATION_WALL_CHASSIS_MATERIAL,
89
+ SPACE_STATION_WALL_LIGHT_ID,
90
+ SPACE_STATION_WALL_LIGHT_MATERIAL,
91
+ SPACE_STATION_WALL_PANEL_ID,
92
+ SPACE_STATION_WALL_PANEL_MATERIAL,
93
+ SPACE_STATION_WALL_RIB_ID,
94
+ SPACE_STATION_WALL_RIB_MATERIAL,
95
+ SPACE_STATION_WALL_TRIM_ID,
96
+ SPACE_STATION_WALL_TRIM_MATERIAL,
97
+ } from './space-station-appearance'
98
+ import { createSharedObstacleMetalMaterials } from './shared-obstacle-metal'
99
+
100
+ const panorama = (id: ThemeId): string => `/themes/panoramas/${id}.ktx2`
101
+ const openGraphPreview = (id: ThemeId): string => `/images/social/og/${id}.webp`
102
+ const uiPreview = (id: ThemeId, role: 'thumbnail' | 'picker' | 'loading'): string =>
103
+ `/themes/previews/${id}-${role}.webp`
104
+
105
+ export const WILD_WEST_COVERED_MINE_IRON_ID = 'wild-west.covered-mine-iron'
106
+ export const WILD_WEST_COVERED_MINE_TIMBER_ID = 'wild-west.covered-mine-timber'
107
+
108
+ const wood: MaterialPatternRecipe = {
109
+ kind: 'wood',
110
+ primary: '#8a4f26',
111
+ secondary: '#3c2114',
112
+ worldSize: [2.4, 2.4],
113
+ }
114
+ const jungleMossBark: MaterialPatternRecipe = {
115
+ kind: 'moss-bark',
116
+ primary: '#574128',
117
+ secondary: '#619646',
118
+ worldSize: [2.5, 2.5],
119
+ }
120
+ const jungleVines: MaterialPatternRecipe = {
121
+ kind: 'jungle-vines',
122
+ primary: '#16371f',
123
+ secondary: '#86c95b',
124
+ worldSize: [2.5, 2.5],
125
+ }
126
+ const jungleLeafCanopy: MaterialPatternRecipe = {
127
+ kind: 'leaf-canopy',
128
+ primary: '#2f7e3a',
129
+ secondary: '#a7da59',
130
+ worldSize: [2.5, 2.5],
131
+ }
132
+ const wildWestWoodenPlanks: MaterialPatternRecipe = {
133
+ kind: 'bridge-planks',
134
+ primary: '#b8743f',
135
+ secondary: '#211711',
136
+ worldSize: [8, 4.8],
137
+ }
138
+
139
+ const wildWestRoughGround: MaterialPatternRecipe = {
140
+ kind: 'rough-wood',
141
+ primary: '#d6ad78',
142
+ secondary: '#321b10',
143
+ worldSize: [2.5, 2.5],
144
+ }
145
+
146
+ const wildWestWoodenPlankMaterial: MaterialRecipe = {
147
+ kind: 'standard',
148
+ color: '#aa7857',
149
+ roughness: 0.76,
150
+ metalness: 0,
151
+ envMapIntensity: 0.18,
152
+ pattern: wildWestWoodenPlanks,
153
+ textureUrl: '/themes/textures/old-assets/shared-rope-bridge-mossy-planks-v2-albedo.webp',
154
+ normalTextureUrl: '/themes/textures/old-assets/shared-rope-bridge-mossy-planks-v2-normal.png',
155
+ roughnessTextureUrl: '/themes/textures/old-assets/shared-rope-bridge-mossy-planks-v2-roughness.png',
156
+ aoTextureUrl: '/themes/textures/old-assets/shared-rope-bridge-mossy-planks-v2-ao.png',
157
+ textureWorldSize: [1.8, 0.72],
158
+ normalScale: [0.86, 0.86],
159
+ aoMapIntensity: 0.64,
160
+ }
161
+
162
+ /** The approved plank timber reoriented for upright stockade grain. */
163
+ const wildWestStockadeTimberMaterial: MaterialRecipe = {
164
+ kind: 'standard',
165
+ color: wildWestWoodenPlankMaterial.color,
166
+ roughness: wildWestWoodenPlankMaterial.roughness,
167
+ metalness: 0,
168
+ envMapIntensity: wildWestWoodenPlankMaterial.envMapIntensity,
169
+ pattern: {
170
+ kind: 'rough-wood',
171
+ primary: '#4b321f',
172
+ secondary: '#17100c',
173
+ worldSize: [0.72, 1.8],
174
+ },
175
+ textureUrl: '/themes/textures/old-assets/wild-west-stockade-plank-timber-v1-albedo.webp',
176
+ normalTextureUrl: '/themes/textures/old-assets/wild-west-stockade-plank-timber-v1-normal.png',
177
+ roughnessTextureUrl: '/themes/textures/old-assets/wild-west-stockade-plank-timber-v1-roughness.png',
178
+ aoTextureUrl: '/themes/textures/old-assets/wild-west-stockade-plank-timber-v1-ao.png',
179
+ textureWorldSize: [0.72, 1.8],
180
+ normalScale: wildWestWoodenPlankMaterial.normalScale,
181
+ aoMapIntensity: wildWestWoodenPlankMaterial.aoMapIntensity,
182
+ }
183
+
184
+ const wildWestRailMaterial: MaterialRecipe = {
185
+ kind: 'physical',
186
+ color: '#464846',
187
+ roughness: 0.42,
188
+ metalness: 0.92,
189
+ clearcoat: 0.08,
190
+ clearcoatRoughness: 0.38,
191
+ envMapIntensity: 1.18,
192
+ }
193
+
194
+ const wildWestRailTieMaterial: MaterialRecipe = {
195
+ kind: 'standard',
196
+ color: '#ffffff',
197
+ roughness: 0.96,
198
+ metalness: 0,
199
+ envMapIntensity: 0.18,
200
+ pattern: {
201
+ kind: 'rough-wood',
202
+ primary: '#3f291a',
203
+ secondary: '#17100c',
204
+ worldSize: [1.6, 0.55],
205
+ },
206
+ bumpScale: 0.035,
207
+ }
208
+
209
+ const wildWestGunmetalMaterial: MaterialRecipe = {
210
+ kind: 'physical',
211
+ color: '#ffffff',
212
+ roughness: 0.12,
213
+ metalness: 0.98,
214
+ clearcoat: 0.92,
215
+ clearcoatRoughness: 0.045,
216
+ envMapIntensity: 2.4,
217
+ pattern: {
218
+ kind: 'gunmetal-silver',
219
+ primary: '#eef2f2',
220
+ secondary: '#91a09d',
221
+ worldSize: [0.72, 0.72],
222
+ },
223
+ bumpScale: 0.018,
224
+ }
225
+
226
+ const wildWestTrestleIronMaterial: MaterialRecipe = {
227
+ kind: 'physical',
228
+ color: '#a4aaa7',
229
+ roughness: 0.28,
230
+ metalness: 0.92,
231
+ clearcoat: 0.24,
232
+ clearcoatRoughness: 0.22,
233
+ envMapIntensity: 1.3,
234
+ pattern: {
235
+ kind: 'gunmetal-silver',
236
+ primary: '#b7bcb8',
237
+ secondary: '#4d5350',
238
+ worldSize: [0.65, 0.65],
239
+ },
240
+ bumpScale: 0.025,
241
+ }
242
+
243
+ const wildWestSand: MaterialPatternRecipe = {
244
+ kind: 'sand',
245
+ primary: '#d2a05f',
246
+ secondary: '#6f3d24',
247
+ // Match the production image cadence so preview/test fallbacks do not
248
+ // visibly rescale when the browser asset finishes loading.
249
+ worldSize: [2.65, 2.65],
250
+ }
251
+
252
+ const wildWestSandyTrackMaterial: MaterialRecipe = {
253
+ kind: 'standard',
254
+ color: '#ffffff',
255
+ roughness: 0.98,
256
+ metalness: 0,
257
+ envMapIntensity: 0.48,
258
+ pattern: wildWestSand,
259
+ textureUrl: '/themes/textures/old-assets/wild-west-sand-track-v2.png',
260
+ textureWorldSize: [2.65, 2.65],
261
+ bumpScale: 0.14,
262
+ surfaceTreatment: {
263
+ kind: 'floor-perimeter-overlay',
264
+ materialId: WILD_WEST_SAND_SHOULDER_MATERIAL_ID,
265
+ bandWidth: 0.34,
266
+ featherWidth: 0.12,
267
+ normalOffset: 0.004,
268
+ },
269
+ }
270
+
271
+ export const JUNGLE_TEMPLE_FLAGSTONE_FLOOR_ID = 'jungle.temple-flagstone'
272
+ export const JUNGLE_TEMPLE_MASONRY_WALL_ID = 'jungle.temple-masonry'
273
+ export const GLOBAL_HAMMERED_GOLD_MATERIAL_ID = 'shared.hammered-gold'
274
+ export const ANCIENT_EGYPT_PAVING_FLOOR_ID = 'ancient-egypt.temple-paving'
275
+ export const ANCIENT_EGYPT_ASHLAR_WALL_ID = 'ancient-egypt.temple-ashlar'
276
+ export const ANCIENT_EGYPT_PORTAL_SANDSTONE_ID = 'ancient-egypt.portal-sandstone'
277
+ export const ANCIENT_EGYPT_PORTAL_CARVED_SANDSTONE_ID = 'ancient-egypt.portal-carved-sandstone'
278
+ export const ANCIENT_EGYPT_PORTAL_AGED_GOLD_ID = 'ancient-egypt.portal-aged-gold'
279
+ export const ANCIENT_EGYPT_PYRAMID_LIMESTONE_ID = 'ancient-egypt.pyramid-limestone'
280
+ export const ANCIENT_EGYPT_PYRAMID_GOLD_ID = GLOBAL_HAMMERED_GOLD_MATERIAL_ID
281
+
282
+ const jungleTempleFlagstoneMaterial: MaterialRecipe = {
283
+ kind: 'standard',
284
+ color: '#ffffff',
285
+ roughness: 0.98,
286
+ metalness: 0,
287
+ envMapIntensity: 0.58,
288
+ textureUrl: '/themes/textures/jungle-temple-mossy-flagstone-v3-albedo.webp',
289
+ normalTextureUrl: '/themes/textures/jungle-temple-mossy-flagstone-v3-normal.png',
290
+ heightTextureUrl: '/themes/textures/jungle-temple-mossy-flagstone-v3-height.png',
291
+ roughnessTextureUrl: '/themes/textures/jungle-temple-mossy-flagstone-v3-roughness.png',
292
+ aoTextureUrl: '/themes/textures/jungle-temple-mossy-flagstone-v3-ao.png',
293
+ textureWorldSize: [4.2, 4.2],
294
+ normalScale: [0.78, 0.78],
295
+ bumpScale: 0.04,
296
+ aoMapIntensity: 0.65,
297
+ }
298
+
299
+ const jungleTempleMasonryMaterial: MaterialRecipe = {
300
+ kind: 'standard',
301
+ color: '#ffffff',
302
+ roughness: 0.99,
303
+ metalness: 0,
304
+ envMapIntensity: 0.54,
305
+ textureUrl: '/themes/textures/jungle-temple-elevator-masonry-v3-albedo.webp',
306
+ normalTextureUrl: '/themes/textures/jungle-temple-elevator-masonry-v3-normal.png',
307
+ heightTextureUrl: '/themes/textures/jungle-temple-elevator-masonry-v3-height.png',
308
+ roughnessTextureUrl: '/themes/textures/jungle-temple-elevator-masonry-v3-roughness.png',
309
+ aoTextureUrl: '/themes/textures/jungle-temple-elevator-masonry-v3-ao.png',
310
+ textureWorldSize: [4.6, 4.6],
311
+ normalScale: [1.08, 1.08],
312
+ bumpScale: 0.085,
313
+ aoMapIntensity: 0.76,
314
+ }
315
+
316
+ const jungleTempleBlockStoneMaterial: MaterialRecipe = {
317
+ kind: 'standard',
318
+ color: '#ffffff',
319
+ roughness: 0.98,
320
+ metalness: 0,
321
+ envMapIntensity: 0.5,
322
+ textureUrl: '/themes/textures/jungle-temple-mossy-block-stone-v3-albedo.webp',
323
+ normalTextureUrl: '/themes/textures/jungle-temple-mossy-block-stone-v3-normal.png',
324
+ heightTextureUrl: '/themes/textures/jungle-temple-mossy-block-stone-v3-height.png',
325
+ roughnessTextureUrl: '/themes/textures/jungle-temple-mossy-block-stone-v3-roughness.png',
326
+ aoTextureUrl: '/themes/textures/jungle-temple-mossy-block-stone-v3-ao.png',
327
+ textureWorldSize: [1.7777777778, 1.7777777778],
328
+ normalScale: [0.62, 0.62],
329
+ bumpScale: 0.025,
330
+ aoMapIntensity: 0.56,
331
+ }
332
+
333
+ const ancientEgyptPavingMaterial: MaterialRecipe = {
334
+ kind: 'standard',
335
+ color: '#ffffff',
336
+ roughness: 0.97,
337
+ metalness: 0,
338
+ envMapIntensity: 1,
339
+ textureUrl: '/themes/textures/ancient-egypt-paving-v5-approved-albedo.webp',
340
+ normalTextureUrl: '/themes/textures/ancient-egypt-paving-v5-approved-normal.webp',
341
+ heightTextureUrl: '/themes/textures/ancient-egypt-paving-v5-approved-height.webp',
342
+ roughnessTextureUrl: '/themes/textures/ancient-egypt-paving-v5-approved-roughness.webp',
343
+ aoTextureUrl: '/themes/textures/ancient-egypt-paving-v5-approved-ao.webp',
344
+ textureWorldSize: [4.4, 4.4],
345
+ normalScale: [0.55, 0.55],
346
+ bumpScale: 0.01,
347
+ aoMapIntensity: 0.48,
348
+ }
349
+
350
+ const ancientEgyptAshlarMaterial: MaterialRecipe = {
351
+ kind: 'standard',
352
+ color: '#ffffff',
353
+ roughness: 0.96,
354
+ metalness: 0,
355
+ envMapIntensity: 0.66,
356
+ textureUrl: '/themes/textures/ancient-egypt-ashlar-v3-limestone-albedo.webp',
357
+ normalTextureUrl: '/themes/textures/ancient-egypt-ashlar-v2-normal.webp',
358
+ heightTextureUrl: '/themes/textures/ancient-egypt-ashlar-v2-height.webp',
359
+ roughnessTextureUrl: '/themes/textures/ancient-egypt-ashlar-v2-roughness.webp',
360
+ aoTextureUrl: '/themes/textures/ancient-egypt-ashlar-v2-ao.webp',
361
+ textureWorldSize: [5.2, 5.2],
362
+ normalScale: [1.08, 1.08],
363
+ bumpScale: 0.08,
364
+ aoMapIntensity: 0.74,
365
+ }
366
+
367
+ const ancientEgyptBlockLimestoneMaterial: MaterialRecipe = {
368
+ kind: 'standard',
369
+ color: '#ffffff',
370
+ roughness: 0.95,
371
+ metalness: 0,
372
+ envMapIntensity: 1,
373
+ textureUrl: '/themes/textures/ancient-egypt-block-limestone-v1-albedo.webp',
374
+ normalTextureUrl: '/themes/textures/ancient-egypt-block-limestone-v1-normal.webp',
375
+ heightTextureUrl: '/themes/textures/ancient-egypt-block-limestone-v1-height.webp',
376
+ roughnessTextureUrl: '/themes/textures/ancient-egypt-block-limestone-v1-roughness.webp',
377
+ aoTextureUrl: '/themes/textures/ancient-egypt-block-limestone-v1-ao.webp',
378
+ textureWorldSize: [1.7777777778, 1.7777777778],
379
+ normalScale: [0.55, 0.55],
380
+ bumpScale: 0.018,
381
+ aoMapIntensity: 0.48,
382
+ }
383
+
384
+ const ancientEgyptPortalCarvedSandstoneMaterial: MaterialRecipe = {
385
+ ...ancientEgyptAshlarMaterial,
386
+ normalScale: [1.2, 1.2],
387
+ bumpScale: 0.095,
388
+ aoMapIntensity: 0.8,
389
+ }
390
+
391
+ const ancientEgyptPyramidLimestoneMaterial: MaterialRecipe = {
392
+ kind: 'standard',
393
+ color: '#ffffff',
394
+ roughness: 1,
395
+ metalness: 0,
396
+ envMapIntensity: 0.82,
397
+ textureUrl: '/themes/textures/ancient-egypt-pyramid-limestone-v1-albedo.webp',
398
+ normalTextureUrl: '/themes/textures/ancient-egypt-pyramid-limestone-v1-normal.png',
399
+ heightTextureUrl: '/themes/textures/ancient-egypt-pyramid-limestone-v1-height.png',
400
+ roughnessTextureUrl: '/themes/textures/ancient-egypt-pyramid-limestone-v1-roughness.png',
401
+ aoTextureUrl: '/themes/textures/ancient-egypt-pyramid-limestone-v1-ao.png',
402
+ textureWorldSize: [2, 2],
403
+ normalScale: [0.42, 0.42],
404
+ bumpScale: 0.02,
405
+ aoMapIntensity: 0.35,
406
+ }
407
+
408
+ const globalHammeredGoldMaterial: MaterialRecipe = {
409
+ kind: 'physical',
410
+ color: '#ffffff',
411
+ roughness: 1,
412
+ metalness: 0.88,
413
+ emissive: '#6b3200',
414
+ emissiveIntensity: 0.18,
415
+ clearcoat: 0.42,
416
+ clearcoatRoughness: 0.16,
417
+ envMapIntensity: 1.9,
418
+ textureUrl: '/themes/textures/shared-hammered-gold-v1-albedo.webp',
419
+ normalTextureUrl: '/themes/textures/shared-hammered-gold-v1-normal.png',
420
+ heightTextureUrl: '/themes/textures/shared-hammered-gold-v1-height.png',
421
+ roughnessTextureUrl: '/themes/textures/shared-hammered-gold-v1-roughness.png',
422
+ aoTextureUrl: '/themes/textures/shared-hammered-gold-v1-ao.png',
423
+ textureWorldSize: [1.2, 1.2],
424
+ normalScale: [0.55, 0.55],
425
+ bumpScale: 0.014,
426
+ aoMapIntensity: 0.25,
427
+ }
428
+
429
+ const ancientEgyptPortalAgedGoldMaterial: MaterialRecipe = {
430
+ kind: 'physical',
431
+ color: '#ffd56a',
432
+ roughness: 0.22,
433
+ metalness: 0.96,
434
+ clearcoat: 0.34,
435
+ clearcoatRoughness: 0.2,
436
+ envMapIntensity: 1.9,
437
+ }
438
+
439
+ function createJungleMaterials(): Record<ThemeMaterialSlot, MaterialRecipe> {
440
+ const materials = createThemeMaterialSet(
441
+ {
442
+ laneSurface: '#d8efd0',
443
+ laneEdge: '#24452b',
444
+ laneGuard: '#4f8f45',
445
+ structure: '#5a4930',
446
+ structureSecondary: '#243521',
447
+ mechanism: '#526743',
448
+ moving: '#ef7d3d',
449
+ route: '#d7ee67',
450
+ hazard: '#ee563c',
451
+ finish: '#ffe27a',
452
+ energy: '#4ee1be',
453
+ portal: '#b06cff',
454
+ glass: '#86dfc8',
455
+ worldGround: '#284b28',
456
+ worldPrimary: '#493824',
457
+ worldSecondary: '#607744',
458
+ foliage: '#39933f',
459
+ accent: '#b5da4b',
460
+ dark: '#142317',
461
+ },
462
+ {
463
+ surfacePattern: jungleVines,
464
+ guardEmissive: '#17391b',
465
+ transparentGuardBacking: true,
466
+ structurePattern: jungleMossBark,
467
+ trackRoughness: 0.9,
468
+ trackMetalness: 0,
469
+ guardMetalness: 0,
470
+ },
471
+ )
472
+
473
+ materials['lane.surface'] = {
474
+ kind: 'physical',
475
+ color: '#ffffff',
476
+ roughness: 0.78,
477
+ metalness: 0,
478
+ clearcoat: 0.08,
479
+ clearcoatRoughness: 0.68,
480
+ transparent: false,
481
+ opacity: 1,
482
+ depthWrite: true,
483
+ envMapIntensity: 0.46,
484
+ pattern: jungleVines,
485
+ }
486
+ materials['world.ground'] = {
487
+ ...materials['world.ground'],
488
+ pattern: jungleVines,
489
+ roughness: 0.94,
490
+ }
491
+ materials['world.foliage'] = {
492
+ ...materials['world.foliage'],
493
+ pattern: jungleLeafCanopy,
494
+ }
495
+ return materials
496
+ }
497
+
498
+ export const ROCKY_MOUNTAIN_WILD_WEST_THEME: TrackThemeDefinition = {
499
+ id: 'rocky-mountain-wild-west',
500
+ version: 1,
501
+ label: 'Rocky Mountain Wild West',
502
+ shortLabel: 'Wild West',
503
+ description: 'Weathered timber, iron straps, desert dust, cactuses, and mountain sun.',
504
+ thumbnailUrl: uiPreview('rocky-mountain-wild-west', 'thumbnail'),
505
+ pickerPreviewUrl: uiPreview('rocky-mountain-wild-west', 'picker'),
506
+ loadingPreviewUrl: uiPreview('rocky-mountain-wild-west', 'loading'),
507
+ previewUrl: openGraphPreview('rocky-mountain-wild-west'),
508
+ panoramaUrl: panorama('rocky-mountain-wild-west'),
509
+ materials: {
510
+ ...createThemeMaterialSet(
511
+ {
512
+ laneSurface: '#c59562',
513
+ laneEdge: '#382b1e',
514
+ laneGuard: '#efc18d',
515
+ structure: '#5b4429',
516
+ structureSecondary: '#27331f',
517
+ mechanism: '#69714d',
518
+ moving: '#ef7d3d',
519
+ route: '#e6f05f',
520
+ hazard: '#ee563c',
521
+ finish: '#ffe27a',
522
+ energy: '#4ee1be',
523
+ portal: '#b06cff',
524
+ glass: '#86dfc8',
525
+ worldGround: '#35512d',
526
+ worldPrimary: '#6a4b2b',
527
+ worldSecondary: '#6b7554',
528
+ foliage: '#3f8f3e',
529
+ accent: '#ff943f',
530
+ dark: '#182318',
531
+ },
532
+ {
533
+ surfacePattern: wildWestRoughGround,
534
+ surfaceBumpScale: 0.16,
535
+ guardPattern: {
536
+ kind: 'stick-fence',
537
+ primary: '#e0a968',
538
+ secondary: '#6a3f25',
539
+ worldSize: [1.6, 1.6],
540
+ },
541
+ guardEmissive: '#4a250f',
542
+ transparentGuardBacking: true,
543
+ structurePattern: {
544
+ kind: 'bark',
545
+ primary: '#76502b',
546
+ secondary: '#273f24',
547
+ worldSize: [2.5, 2.5],
548
+ },
549
+ trackRoughness: 0.94,
550
+ trackMetalness: 0,
551
+ guardMetalness: 0,
552
+ },
553
+ ),
554
+ 'lane.surface': wildWestSandyTrackMaterial,
555
+ 'lane.guard': wildWestStockadeTimberMaterial,
556
+ ...createSharedObstacleMetalMaterials({ light: '#aeb5b0', dark: '#68716c' }),
557
+ },
558
+ detailMaterials: {
559
+ [SHARED_ROPE_WALL_END_GRAIN_MATERIAL_ID]: SHARED_ROPE_WALL_END_GRAIN_MATERIAL,
560
+ [WILD_WEST_GUNMETAL_FLIPPER_MATERIAL_ID]: wildWestGunmetalMaterial,
561
+ [WILD_WEST_RAIL_MATERIAL_ID]: wildWestRailMaterial,
562
+ [WILD_WEST_RAIL_TIE_MATERIAL_ID]: wildWestRailTieMaterial,
563
+ [WILD_WEST_SAND_SHOULDER_MATERIAL_ID]: {
564
+ kind: 'standard',
565
+ color: '#ffffff',
566
+ roughness: 1,
567
+ metalness: 0,
568
+ envMapIntensity: 0.42,
569
+ pattern: {
570
+ kind: 'sand',
571
+ primary: '#c9824f',
572
+ secondary: '#8a5033',
573
+ worldSize: [2.35, 2.35],
574
+ },
575
+ textureUrl: '/themes/textures/old-assets/wild-west-dirt-shoulder-v4.png',
576
+ textureWorldSize: [2.8, 2.8],
577
+ bumpScale: 0.08,
578
+ },
579
+ 'wild-west.mine-timber': {
580
+ kind: 'standard',
581
+ color: '#ffffff',
582
+ roughness: 0.96,
583
+ metalness: 0,
584
+ envMapIntensity: 0.28,
585
+ pattern: {
586
+ kind: 'fence-timber',
587
+ primary: '#563522',
588
+ secondary: '#19100c',
589
+ worldSize: [1.6, 0.55],
590
+ },
591
+ textureUrl: '/themes/textures/old-assets/wild-west-portal-hand-hewn-timber-v2-albedo.webp',
592
+ normalTextureUrl: '/themes/textures/old-assets/wild-west-portal-hand-hewn-timber-v2-normal.png',
593
+ heightTextureUrl: '/themes/textures/old-assets/wild-west-portal-hand-hewn-timber-v2-height.png',
594
+ roughnessTextureUrl: '/themes/textures/old-assets/wild-west-portal-hand-hewn-timber-v2-roughness.png',
595
+ aoTextureUrl: '/themes/textures/old-assets/wild-west-portal-hand-hewn-timber-v2-ao.png',
596
+ textureWorldSize: [1.6, 0.55],
597
+ normalScale: [0.86, 0.86],
598
+ bumpScale: 0.045,
599
+ aoMapIntensity: 0.68,
600
+ },
601
+ [WILD_WEST_COVERED_MINE_TIMBER_ID]: {
602
+ kind: 'standard',
603
+ color: '#ffffff',
604
+ roughness: 0.88,
605
+ metalness: 0,
606
+ envMapIntensity: 0.42,
607
+ pattern: {
608
+ kind: 'fence-timber',
609
+ primary: '#6d3519',
610
+ secondary: '#1f0d06',
611
+ worldSize: [1.8, 0.72],
612
+ },
613
+ textureUrl: '/themes/textures/wild-west-covered-mine-timber-v1-albedo.webp',
614
+ normalTextureUrl: '/themes/textures/wild-west-covered-mine-timber-v1-normal.png',
615
+ heightTextureUrl: '/themes/textures/wild-west-covered-mine-timber-v1-height.png',
616
+ roughnessTextureUrl: '/themes/textures/wild-west-covered-mine-timber-v1-roughness.png',
617
+ aoTextureUrl: '/themes/textures/wild-west-covered-mine-timber-v1-ao.png',
618
+ textureWorldSize: [1.8, 0.72],
619
+ normalScale: [0.58, 0.58],
620
+ bumpScale: 0.026,
621
+ aoMapIntensity: 0.52,
622
+ },
623
+ [WILD_WEST_COVERED_MINE_IRON_ID]: {
624
+ kind: 'physical',
625
+ color: '#ffffff',
626
+ roughness: 0.58,
627
+ metalness: 0.68,
628
+ clearcoat: 0.06,
629
+ clearcoatRoughness: 0.68,
630
+ envMapIntensity: 1.14,
631
+ pattern: {
632
+ kind: 'gunmetal-silver',
633
+ primary: '#555752',
634
+ secondary: '#332017',
635
+ worldSize: [1.45, 1.45],
636
+ },
637
+ textureUrl: '/themes/textures/wild-west-covered-mine-iron-v1-albedo.webp',
638
+ normalTextureUrl: '/themes/textures/wild-west-covered-mine-iron-v1-normal.png',
639
+ heightTextureUrl: '/themes/textures/wild-west-covered-mine-iron-v1-height.png',
640
+ roughnessTextureUrl: '/themes/textures/wild-west-covered-mine-iron-v1-roughness.png',
641
+ aoTextureUrl: '/themes/textures/wild-west-covered-mine-iron-v1-ao.png',
642
+ textureWorldSize: [1.45, 1.45],
643
+ normalScale: [0.46, 0.46],
644
+ bumpScale: 0.018,
645
+ aoMapIntensity: 0.48,
646
+ },
647
+ 'wild-west.warm-ivory-bone': {
648
+ kind: 'standard',
649
+ color: '#d7c49a',
650
+ roughness: 0.82,
651
+ metalness: 0,
652
+ envMapIntensity: 0.72,
653
+ pattern: {
654
+ kind: 'rock',
655
+ primary: '#dfcfaa',
656
+ secondary: '#8d7958',
657
+ worldSize: [0.72, 0.72],
658
+ },
659
+ bumpScale: 0.018,
660
+ },
661
+ [WILD_WEST_ANTIQUE_BRASS_MATERIAL_ID]: {
662
+ kind: 'physical',
663
+ color: '#ffffff',
664
+ roughness: 0.52,
665
+ metalness: 0.76,
666
+ clearcoat: 0.12,
667
+ clearcoatRoughness: 0.62,
668
+ envMapIntensity: 1.05,
669
+ textureUrl: '/themes/textures/jungle-temple-bronze-amber-ai-v1.webp',
670
+ textureWorldSize: [1.2, 1.2],
671
+ bumpScale: 0.025,
672
+ },
673
+ [WILD_WEST_TRESTLE_METAL_MATERIAL_ID]: wildWestTrestleIronMaterial,
674
+ },
675
+ appearancePresets: {
676
+ floor: [
677
+ {
678
+ id: WILD_WEST_WOODEN_PLANKS_FLOOR_ID,
679
+ label: 'Planks',
680
+ material: wildWestWoodenPlankMaterial,
681
+ },
682
+ {
683
+ id: WILD_WEST_SAND_FLOOR_ID,
684
+ label: 'Sand',
685
+ default: true,
686
+ material: wildWestSandyTrackMaterial,
687
+ },
688
+ ],
689
+ rail: [
690
+ {
691
+ id: WILD_WEST_RAIL_MATERIAL_ID,
692
+ label: 'Rails',
693
+ detailStyle: 'wild-west-railroad',
694
+ material: wildWestRailMaterial,
695
+ },
696
+ ],
697
+ support: [
698
+ {
699
+ id: WILD_WEST_TIMBER_TRESTLE_SUPPORT_ID,
700
+ label: 'Timber',
701
+ supportStyle: 'wild-west-timber-trestle',
702
+ material: wildWestWoodenPlankMaterial,
703
+ },
704
+ {
705
+ id: WILD_WEST_CANYON_BUTTRESS_SUPPORT_ID,
706
+ label: 'Canyon',
707
+ supportStyle: 'wild-west-canyon-buttress',
708
+ material: {
709
+ kind: 'standard',
710
+ color: '#ffffff',
711
+ roughness: 0.86,
712
+ metalness: 0,
713
+ envMapIntensity: 0.48,
714
+ textureUrl: '/themes/textures/wild-west-canyon-sandstone-v1-albedo.webp',
715
+ normalTextureUrl: '/themes/textures/wild-west-canyon-sandstone-v1-normal.webp',
716
+ heightTextureUrl: '/themes/textures/wild-west-canyon-sandstone-v1-height.webp',
717
+ roughnessTextureUrl: '/themes/textures/wild-west-canyon-sandstone-v1-roughness.webp',
718
+ aoTextureUrl: '/themes/textures/wild-west-canyon-sandstone-v1-ao.webp',
719
+ textureWorldSize: [3.6, 3.6],
720
+ bumpScale: 0.06,
721
+ normalScale: [0.65, 0.65],
722
+ aoMapIntensity: 0.55,
723
+ },
724
+ },
725
+ {
726
+ id: WILD_WEST_TRESTLE_METAL_MATERIAL_ID,
727
+ label: 'Trestle iron detail',
728
+ supportStyle: 'wild-west-timber-trestle',
729
+ material: wildWestTrestleIronMaterial,
730
+ hidden: true,
731
+ },
732
+ ],
733
+ wall: [
734
+ {
735
+ id: 'wild-west.short-ranch-fence',
736
+ label: 'Fence',
737
+ detailStyle: 'wild-west-short-ranch-fence',
738
+ material: SHARED_ROPE_WALL_TIMBER_MATERIAL,
739
+ },
740
+ {
741
+ id: 'wild-west.tall-stockade',
742
+ label: 'Stockade',
743
+ detailStyle: 'wild-west-tall-stockade',
744
+ default: true,
745
+ material: wildWestStockadeTimberMaterial,
746
+ },
747
+ {
748
+ id: 'wild-west.covered-mine-canopy',
749
+ label: 'Mine Canopy',
750
+ detailStyle: 'wild-west-short-ranch-fence',
751
+ canopyStyle: 'wild-west-covered-mine',
752
+ material: {
753
+ kind: 'standard',
754
+ color: '#f0d0aa',
755
+ roughness: 0.88,
756
+ metalness: 0.02,
757
+ envMapIntensity: 0.86,
758
+ pattern: {
759
+ kind: 'fence-timber',
760
+ primary: '#714022',
761
+ secondary: '#1f130e',
762
+ worldSize: [1.1, 1.1],
763
+ },
764
+ bumpScale: 0.1,
765
+ },
766
+ },
767
+ ],
768
+ },
769
+ environment: {
770
+ background: '#b96d39',
771
+ fog: '#c68b5c',
772
+ fogNear: 90,
773
+ fogFar: 330,
774
+ environmentIntensity: 0.82,
775
+ },
776
+ lighting: {
777
+ skyColor: '#ffe5c2',
778
+ groundColor: '#4a2515',
779
+ ambientIntensity: 1.45,
780
+ keyColor: '#ffd28d',
781
+ keyIntensity: 4.1,
782
+ keyPosition: [-30, 46, 26],
783
+ rimColor: '#8fb9dc',
784
+ rimIntensity: 1.05,
785
+ rimPosition: [30, 20, -32],
786
+ exposure: 1.04,
787
+ },
788
+ world: { kit: 'wild-west', density: 0.9 },
789
+ particles: {
790
+ style: 'dust',
791
+ color: '#ffd1a0',
792
+ secondaryColor: '#b86f3e',
793
+ count: 260,
794
+ size: 0.17,
795
+ speed: 0.72,
796
+ opacity: 0.34,
797
+ },
798
+ ambience: { style: 'desert', volume: 0.055 },
799
+ }
800
+
801
+ export const ANCIENT_EGYPT_THEME: TrackThemeDefinition = {
802
+ id: 'ancient-egypt',
803
+ version: 1,
804
+ label: 'Ancient Egypt',
805
+ shortLabel: 'Ancient Egypt',
806
+ description: 'Sunlit pyramids, sandstone temples, Nile palms, obelisks, and drifting desert gold.',
807
+ thumbnailUrl: uiPreview('ancient-egypt', 'thumbnail'),
808
+ pickerPreviewUrl: uiPreview('ancient-egypt', 'picker'),
809
+ loadingPreviewUrl: uiPreview('ancient-egypt', 'loading'),
810
+ previewUrl: openGraphPreview('ancient-egypt'),
811
+ panoramaUrl: panorama('ancient-egypt'),
812
+ materials: {
813
+ ...createThemeMaterialSet(
814
+ {
815
+ laneSurface: '#c58a4b',
816
+ laneEdge: '#5d3822',
817
+ laneGuard: '#ffffff',
818
+ structure: '#b97738',
819
+ structureSecondary: '#4a3022',
820
+ mechanism: '#806142',
821
+ moving: '#d8a23f',
822
+ route: '#f4cf68',
823
+ hazard: '#b8442d',
824
+ finish: '#f5df8b',
825
+ energy: '#42b9c7',
826
+ portal: '#2d71a8',
827
+ glass: '#bce4df',
828
+ worldGround: '#b9793c',
829
+ worldPrimary: '#d0a05d',
830
+ worldSecondary: '#8b5b35',
831
+ foliage: '#416f4b',
832
+ accent: '#2d6f91',
833
+ dark: '#271910',
834
+ },
835
+ {
836
+ surfacePattern: {
837
+ kind: 'painted-stone',
838
+ primary: '#d1a366',
839
+ secondary: '#8d5c35',
840
+ worldSize: [2, 2],
841
+ },
842
+ trackRoughness: 0.9,
843
+ trackMetalness: 0.01,
844
+ guardMetalness: 0.04,
845
+ },
846
+ ),
847
+ 'lane.surface': ancientEgyptPavingMaterial,
848
+ 'lane.edge': ancientEgyptBlockLimestoneMaterial,
849
+ 'lane.guard': ancientEgyptBlockLimestoneMaterial,
850
+ 'lane.guard.backing': ancientEgyptBlockLimestoneMaterial,
851
+ 'structure.primary': ancientEgyptAshlarMaterial,
852
+ 'structure.secondary': ancientEgyptAshlarMaterial,
853
+ ...createSharedObstacleMetalMaterials({ light: '#d9a83e', dark: '#a27125' }),
854
+ },
855
+ appearancePresets: {
856
+ floor: [
857
+ {
858
+ id: ANCIENT_EGYPT_PAVING_FLOOR_ID,
859
+ label: 'Sandstone Paving',
860
+ default: true,
861
+ material: ancientEgyptPavingMaterial,
862
+ },
863
+ {
864
+ id: WILD_WEST_WOODEN_PLANKS_FLOOR_ID,
865
+ label: 'Planks',
866
+ material: wildWestWoodenPlankMaterial,
867
+ },
868
+ {
869
+ id: WILD_WEST_SAND_FLOOR_ID,
870
+ label: 'Sand',
871
+ material: wildWestSandyTrackMaterial,
872
+ },
873
+ ],
874
+ wall: [
875
+ {
876
+ id: ANCIENT_EGYPT_ASHLAR_WALL_ID,
877
+ label: 'Temple Blocks',
878
+ default: true,
879
+ detailStyle: 'shared-stone-block-shell',
880
+ material: ancientEgyptBlockLimestoneMaterial,
881
+ },
882
+ {
883
+ id: SHARED_ROPE_WALL_MATERIAL_ID,
884
+ label: 'Rope Wall',
885
+ detailStyle: 'shared-rope-wall',
886
+ material: SHARED_ROPE_WALL_MATERIAL,
887
+ },
888
+ ],
889
+ },
890
+ detailMaterials: {
891
+ [SHARED_STONE_TRACK_BLOCK_MATERIAL_ID]: ancientEgyptBlockLimestoneMaterial,
892
+ [SHARED_ROPE_WALL_BACKING_MATERIAL_ID]: SHARED_ROPE_WALL_BACKING_MATERIAL,
893
+ [SHARED_ROPE_WALL_END_GRAIN_MATERIAL_ID]: SHARED_ROPE_WALL_END_GRAIN_MATERIAL,
894
+ [SHARED_ROPE_WALL_TIMBER_MATERIAL_ID]: SHARED_ROPE_WALL_TIMBER_MATERIAL,
895
+ [ANCIENT_EGYPT_PORTAL_SANDSTONE_ID]: ancientEgyptAshlarMaterial,
896
+ [ANCIENT_EGYPT_PORTAL_CARVED_SANDSTONE_ID]: ancientEgyptPortalCarvedSandstoneMaterial,
897
+ [ANCIENT_EGYPT_PORTAL_AGED_GOLD_ID]: ancientEgyptPortalAgedGoldMaterial,
898
+ [ANCIENT_EGYPT_PYRAMID_LIMESTONE_ID]: ancientEgyptPyramidLimestoneMaterial,
899
+ [ANCIENT_EGYPT_PYRAMID_GOLD_ID]: globalHammeredGoldMaterial,
900
+ },
901
+ environment: {
902
+ background: '#c78549',
903
+ fog: '#d6a76d',
904
+ fogNear: 100,
905
+ fogFar: 350,
906
+ environmentIntensity: 0.86,
907
+ },
908
+ lighting: {
909
+ skyColor: '#ffe0ae',
910
+ groundColor: '#59341f',
911
+ ambientIntensity: 1.5,
912
+ keyColor: '#ffd087',
913
+ keyIntensity: 4.3,
914
+ keyPosition: [-34, 43, 22],
915
+ rimColor: '#79a9c9',
916
+ rimIntensity: 0.95,
917
+ rimPosition: [28, 22, -34],
918
+ exposure: 1.05,
919
+ },
920
+ world: { kit: 'ancient-egypt', density: 0.88 },
921
+ particles: {
922
+ style: 'dust',
923
+ color: '#f7d49a',
924
+ secondaryColor: '#b8753e',
925
+ count: 230,
926
+ size: 0.16,
927
+ speed: 0.58,
928
+ opacity: 0.3,
929
+ },
930
+ ambience: { style: 'desert', volume: 0.05 },
931
+ }
932
+
933
+ export const JAPANESE_SAKURA_LAKE_THEME: TrackThemeDefinition = {
934
+ id: 'japanese-sakura-lake',
935
+ version: 1,
936
+ label: 'Japanese Sakura',
937
+ shortLabel: 'Sakura Lake',
938
+ description: 'Cherry blossoms, vermilion gates, lakeside temples, and a brilliant blue spring sky.',
939
+ thumbnailUrl: uiPreview('japanese-sakura-lake', 'thumbnail'),
940
+ pickerPreviewUrl: uiPreview('japanese-sakura-lake', 'picker'),
941
+ loadingPreviewUrl: uiPreview('japanese-sakura-lake', 'loading'),
942
+ previewUrl: openGraphPreview('japanese-sakura-lake'),
943
+ panoramaUrl: panorama('japanese-sakura-lake'),
944
+ materials: {
945
+ ...createThemeMaterialSet(
946
+ {
947
+ laneSurface: '#b98258',
948
+ laneEdge: '#4a2924',
949
+ laneGuard: '#ffffff',
950
+ structure: '#743b2f',
951
+ structureSecondary: '#28262b',
952
+ mechanism: '#65565a',
953
+ moving: '#e45d63',
954
+ route: '#ffd080',
955
+ hazard: '#d72f38',
956
+ finish: '#fff0b0',
957
+ energy: '#68d8dc',
958
+ portal: '#bd86e8',
959
+ glass: '#bdebf2',
960
+ worldGround: '#5f8c55',
961
+ worldPrimary: '#bd3432',
962
+ worldSecondary: '#49332d',
963
+ foliage: '#eaa1bb',
964
+ accent: '#f4c6d8',
965
+ dark: '#211a20',
966
+ },
967
+ {
968
+ surfacePattern: {
969
+ kind: 'painted-wood',
970
+ primary: '#ba855b',
971
+ secondary: '#70412f',
972
+ worldSize: [2.4, 2.4],
973
+ },
974
+ structurePattern: wood,
975
+ trackRoughness: 0.76,
976
+ trackMetalness: 0.03,
977
+ guardMetalness: 0.08,
978
+ clearcoat: 0.2,
979
+ },
980
+ ),
981
+ // The Japanese theme's ordinary wall is the same approved plaster used
982
+ // by the castle-wall preset. The old red procedural timber grid was a
983
+ // legacy default, not a separate architectural material.
984
+ 'lane.guard': JAPANESE_SAKURA_CASTLE_PLASTER_MATERIAL,
985
+ 'lane.guard.backing': JAPANESE_SAKURA_CASTLE_PLASTER_MATERIAL,
986
+ 'lane.surface': JAPANESE_SAKURA_REDWOOD_PLANKS_MATERIAL,
987
+ ...createSharedObstacleMetalMaterials({ light: '#ffffff', dark: '#c4ccd0' }),
988
+ },
989
+ appearancePresets: {
990
+ floor: [
991
+ {
992
+ id: JAPANESE_SAKURA_REDWOOD_PLANKS_ID,
993
+ label: 'Redwood Planks',
994
+ default: true,
995
+ material: JAPANESE_SAKURA_REDWOOD_PLANKS_MATERIAL,
996
+ },
997
+ {
998
+ id: JAPANESE_SAKURA_CASTLE_PAVERS_ID,
999
+ label: 'Castle Pavers',
1000
+ material: JAPANESE_SAKURA_CASTLE_PAVERS_MATERIAL,
1001
+ },
1002
+ ],
1003
+ wall: [
1004
+ {
1005
+ id: JAPANESE_SAKURA_CASTLE_WALL_ID,
1006
+ label: 'Castle Wall',
1007
+ default: true,
1008
+ detailStyle: 'japanese-sakura-castle-wall',
1009
+ material: JAPANESE_SAKURA_CASTLE_PLASTER_MATERIAL,
1010
+ },
1011
+ {
1012
+ id: JAPANESE_SAKURA_BRIDGE_FENCE_ID,
1013
+ label: 'Bridge Fence',
1014
+ detailStyle: 'japanese-sakura-vermilion-bridge-fence',
1015
+ material: JAPANESE_SAKURA_BRIDGE_TIMBER_MATERIAL,
1016
+ },
1017
+ {
1018
+ id: 'japanese-sakura.roofed-gate-canopy',
1019
+ label: 'Roofed Gate',
1020
+ canopyStyle: 'japanese-sakura-roofed-gate',
1021
+ material: JAPANESE_SAKURA_BRIDGE_TIMBER_MATERIAL,
1022
+ },
1023
+ ],
1024
+ support: [
1025
+ {
1026
+ id: JAPANESE_SAKURA_VERMILION_UNDERBRIDGE_SUPPORT_ID,
1027
+ label: 'Timber Underbridge',
1028
+ supportStyle: 'japanese-sakura-vermilion-underbridge',
1029
+ material: JAPANESE_SAKURA_BRIDGE_TIMBER_MATERIAL,
1030
+ },
1031
+ {
1032
+ id: JAPANESE_SAKURA_DRAGON_STONE_SUPPORT_ID,
1033
+ label: 'Stone Piers',
1034
+ supportStyle: 'japanese-sakura-dragon-stone',
1035
+ material: JAPANESE_SAKURA_DRAGON_STONE_MATERIAL,
1036
+ },
1037
+ ],
1038
+ },
1039
+ detailMaterials: {
1040
+ [JAPANESE_SAKURA_BRIDGE_TIMBER_ID]: JAPANESE_SAKURA_BRIDGE_TIMBER_MATERIAL,
1041
+ [JAPANESE_SAKURA_BRIDGE_HARDWARE_ID]: JAPANESE_SAKURA_BRIDGE_HARDWARE_MATERIAL,
1042
+ [JAPANESE_SAKURA_CASTLE_TIMBER_ID]: JAPANESE_SAKURA_CASTLE_TIMBER_MATERIAL,
1043
+ [JAPANESE_SAKURA_CASTLE_MASONRY_ID]: JAPANESE_SAKURA_CASTLE_MASONRY_MATERIAL,
1044
+ [JAPANESE_SAKURA_CASTLE_KAWARA_ID]: JAPANESE_SAKURA_CASTLE_KAWARA_MATERIAL,
1045
+ [JAPANESE_SAKURA_PORTAL_FOUNDATION_STONE_ID]: JAPANESE_SAKURA_PORTAL_FOUNDATION_STONE_MATERIAL,
1046
+ },
1047
+ environment: {
1048
+ background: '#79bde8',
1049
+ fog: '#b9d9e8',
1050
+ fogNear: 96,
1051
+ fogFar: 340,
1052
+ environmentIntensity: 0.92,
1053
+ },
1054
+ lighting: {
1055
+ skyColor: '#d9f2ff',
1056
+ groundColor: '#405a40',
1057
+ ambientIntensity: 1.55,
1058
+ keyColor: '#fff1cf',
1059
+ keyIntensity: 4,
1060
+ keyPosition: [-28, 48, 24],
1061
+ rimColor: '#efb9d0',
1062
+ rimIntensity: 1.1,
1063
+ rimPosition: [32, 22, -30],
1064
+ exposure: 1.06,
1065
+ },
1066
+ world: { kit: 'japanese-sakura-lake', density: 0.9 },
1067
+ particles: {
1068
+ style: 'petals',
1069
+ color: '#ffd8e7',
1070
+ secondaryColor: '#ed8eb1',
1071
+ count: 320,
1072
+ size: 0.16,
1073
+ speed: 0.38,
1074
+ opacity: 0.66,
1075
+ },
1076
+ ambience: { style: 'sakura-lake', volume: 0.045 },
1077
+ }
1078
+
1079
+ export const INTERGALACTIC_SPACE_STATION_THEME: TrackThemeDefinition = {
1080
+ id: 'intergalactic-space-station',
1081
+ version: 1,
1082
+ label: 'Intergalactic Space Station',
1083
+ shortLabel: 'Space Station',
1084
+ description: 'Armored modular decks, cyan energy conduits, planets, and drifting starlight.',
1085
+ thumbnailUrl: uiPreview('intergalactic-space-station', 'thumbnail'),
1086
+ pickerPreviewUrl: uiPreview('intergalactic-space-station', 'picker'),
1087
+ loadingPreviewUrl: uiPreview('intergalactic-space-station', 'loading'),
1088
+ previewUrl: openGraphPreview('intergalactic-space-station'),
1089
+ panoramaUrl: panorama('intergalactic-space-station'),
1090
+ materials: {
1091
+ ...createThemeMaterialSet(
1092
+ {
1093
+ laneSurface: '#35424e',
1094
+ laneEdge: '#111b25',
1095
+ laneGuard: '#7e8c99',
1096
+ structure: '#43515e',
1097
+ structureSecondary: '#111a24',
1098
+ mechanism: '#33424f',
1099
+ moving: '#ff9d3d',
1100
+ route: '#3ceaff',
1101
+ hazard: '#ff5b4f',
1102
+ finish: '#eaffff',
1103
+ energy: '#48bfff',
1104
+ portal: '#ab73ff',
1105
+ glass: '#8edfff',
1106
+ worldGround: '#111a24',
1107
+ worldPrimary: '#7e8c99',
1108
+ worldSecondary: '#263746',
1109
+ foliage: '#526475',
1110
+ accent: '#31dfff',
1111
+ dark: '#060912',
1112
+ },
1113
+ {
1114
+ trackRoughness: 0.5,
1115
+ trackMetalness: 0.68,
1116
+ guardMetalness: 0.72,
1117
+ clearcoat: 0.08,
1118
+ },
1119
+ ),
1120
+ 'lane.surface': SPACE_STATION_FLOOR_DECK_MATERIAL,
1121
+ 'lane.guard': SPACE_STATION_WALL_CHASSIS_MATERIAL,
1122
+ 'lane.guard.backing': SPACE_STATION_WALL_CHASSIS_MATERIAL,
1123
+ ...createSharedObstacleMetalMaterials({ light: '#68b8c7', dark: '#356d79' }),
1124
+ },
1125
+ appearancePresets: {
1126
+ floor: [
1127
+ {
1128
+ id: SPACE_STATION_FLOOR_DECK_ID,
1129
+ label: 'Modular Deck',
1130
+ default: true,
1131
+ material: SPACE_STATION_FLOOR_DECK_MATERIAL,
1132
+ },
1133
+ {
1134
+ id: SPACE_STATION_HOVER_GRID_FLOOR_ID,
1135
+ label: 'Hover Grid',
1136
+ material: SPACE_STATION_HOVER_GRID_FLOOR_MATERIAL,
1137
+ },
1138
+ ],
1139
+ wall: [
1140
+ {
1141
+ id: SPACE_STATION_ARMORED_WALL_ID,
1142
+ label: 'Station Bulkhead',
1143
+ default: true,
1144
+ detailStyle: 'space-station-armored-wall',
1145
+ material: SPACE_STATION_WALL_CHASSIS_MATERIAL,
1146
+ },
1147
+ ],
1148
+ },
1149
+ detailMaterials: {
1150
+ [SPACE_STATION_FLOOR_DECK_BASE_ID]: SPACE_STATION_FLOOR_DECK_BASE_MATERIAL,
1151
+ [SPACE_STATION_WALL_PANEL_ID]: SPACE_STATION_WALL_PANEL_MATERIAL,
1152
+ [SPACE_STATION_WALL_RIB_ID]: SPACE_STATION_WALL_RIB_MATERIAL,
1153
+ [SPACE_STATION_WALL_TRIM_ID]: SPACE_STATION_WALL_TRIM_MATERIAL,
1154
+ [SPACE_STATION_WALL_LIGHT_ID]: SPACE_STATION_WALL_LIGHT_MATERIAL,
1155
+ [SPACE_STATION_CENTER_GUIDE_ID]: SPACE_STATION_CENTER_GUIDE_MATERIAL,
1156
+ },
1157
+ environment: {
1158
+ background: '#070916',
1159
+ fog: '#101626',
1160
+ fogNear: 110,
1161
+ fogFar: 410,
1162
+ environmentIntensity: 1.15,
1163
+ },
1164
+ lighting: {
1165
+ skyColor: '#a8cfff',
1166
+ groundColor: '#070b14',
1167
+ ambientIntensity: 1.42,
1168
+ keyColor: '#dceaff',
1169
+ keyIntensity: 3.7,
1170
+ keyPosition: [-20, 48, 34],
1171
+ rimColor: '#8a5dff',
1172
+ rimIntensity: 2,
1173
+ rimPosition: [38, 28, -42],
1174
+ exposure: 1.152,
1175
+ practical: {
1176
+ color: '#31edff',
1177
+ intensity: 150,
1178
+ distance: 28,
1179
+ decay: 2,
1180
+ count: 4,
1181
+ heightOffset: 2.4,
1182
+ },
1183
+ },
1184
+ world: { kit: 'space-station', density: 0.82 },
1185
+ particles: {
1186
+ style: 'space-drift',
1187
+ color: '#d8f4ff',
1188
+ secondaryColor: '#7b8dff',
1189
+ count: 560,
1190
+ size: 0.15,
1191
+ speed: 2.4,
1192
+ opacity: 0.72,
1193
+ },
1194
+ ambience: { style: 'space', volume: 0.045 },
1195
+ }
1196
+
1197
+ export const LOW_POLY_JUNGLE_THEME: TrackThemeDefinition = {
1198
+ id: 'low-poly-jungle',
1199
+ version: 1,
1200
+ label: 'Low-Poly Jungle',
1201
+ shortLabel: 'Jungle',
1202
+ description: 'Open vine-lattice lanes, climbing plants, broad leaves, mossy roots, and waterfall mist.',
1203
+ thumbnailUrl: uiPreview('low-poly-jungle', 'thumbnail'),
1204
+ pickerPreviewUrl: uiPreview('low-poly-jungle', 'picker'),
1205
+ loadingPreviewUrl: uiPreview('low-poly-jungle', 'loading'),
1206
+ previewUrl: openGraphPreview('low-poly-jungle'),
1207
+ panoramaUrl: panorama('low-poly-jungle'),
1208
+ materials: {
1209
+ ...createJungleMaterials(),
1210
+ 'lane.surface': jungleTempleFlagstoneMaterial,
1211
+ 'lane.edge': jungleTempleBlockStoneMaterial,
1212
+ 'lane.guard': jungleTempleBlockStoneMaterial,
1213
+ 'lane.guard.backing': jungleTempleBlockStoneMaterial,
1214
+ 'structure.primary': jungleTempleMasonryMaterial,
1215
+ 'structure.secondary': jungleTempleMasonryMaterial,
1216
+ ...createSharedObstacleMetalMaterials({ light: '#d3a23f', dark: '#9a7028' }),
1217
+ 'mechanism.flipper.primary': globalHammeredGoldMaterial,
1218
+ 'mechanism.flipper.secondary': globalHammeredGoldMaterial,
1219
+ },
1220
+ appearancePresets: {
1221
+ floor: [
1222
+ {
1223
+ id: WILD_WEST_WOODEN_PLANKS_FLOOR_ID,
1224
+ label: 'Planks',
1225
+ material: wildWestWoodenPlankMaterial,
1226
+ },
1227
+ {
1228
+ id: JUNGLE_TEMPLE_FLAGSTONE_FLOOR_ID,
1229
+ label: 'Temple Flagstones',
1230
+ default: true,
1231
+ material: jungleTempleFlagstoneMaterial,
1232
+ },
1233
+ ],
1234
+ wall: [
1235
+ {
1236
+ id: JUNGLE_TEMPLE_MASONRY_WALL_ID,
1237
+ label: 'Temple Masonry',
1238
+ default: true,
1239
+ detailStyle: 'shared-stone-block-shell',
1240
+ material: jungleTempleBlockStoneMaterial,
1241
+ },
1242
+ {
1243
+ id: SHARED_ROPE_WALL_MATERIAL_ID,
1244
+ label: 'Rope Wall',
1245
+ detailStyle: 'shared-rope-wall',
1246
+ material: SHARED_ROPE_WALL_MATERIAL,
1247
+ },
1248
+ ],
1249
+ },
1250
+ detailMaterials: {
1251
+ [SHARED_STONE_TRACK_BLOCK_MATERIAL_ID]: jungleTempleBlockStoneMaterial,
1252
+ [SHARED_ROPE_WALL_BACKING_MATERIAL_ID]: SHARED_ROPE_WALL_BACKING_MATERIAL,
1253
+ [SHARED_ROPE_WALL_END_GRAIN_MATERIAL_ID]: SHARED_ROPE_WALL_END_GRAIN_MATERIAL,
1254
+ [SHARED_ROPE_WALL_TIMBER_MATERIAL_ID]: SHARED_ROPE_WALL_TIMBER_MATERIAL,
1255
+ [JUNGLE_TEMPLE_STONE_MATERIAL_ID]: jungleTempleMasonryMaterial,
1256
+ [JUNGLE_TEMPLE_FACADE_MATERIAL_ID]: {
1257
+ kind: 'standard',
1258
+ color: '#ffffff',
1259
+ roughness: 0.78,
1260
+ metalness: 0,
1261
+ envMapIntensity: 0.66,
1262
+ textureUrl: '/themes/textures/jungle-temple-serpent-facade-v3-albedo.webp',
1263
+ normalTextureUrl: '/themes/textures/jungle-temple-serpent-facade-v3-normal.png',
1264
+ heightTextureUrl: '/themes/textures/jungle-temple-serpent-facade-v3-height.png',
1265
+ roughnessTextureUrl: '/themes/textures/jungle-temple-serpent-facade-v3-roughness.png',
1266
+ aoTextureUrl: '/themes/textures/jungle-temple-serpent-facade-v3-ao.png',
1267
+ textureWorldSize: [1, 1],
1268
+ normalScale: [0.72, 0.72],
1269
+ bumpScale: 0.035,
1270
+ aoMapIntensity: 0.58,
1271
+ },
1272
+ [JUNGLE_TEMPLE_TIMBER_MATERIAL_ID]: {
1273
+ kind: 'toon',
1274
+ color: '#ffffff',
1275
+ roughness: 0.91,
1276
+ metalness: 0,
1277
+ gradientSteps: 5,
1278
+ inkColor: '#17120c',
1279
+ inkStrength: 0.08,
1280
+ envMapIntensity: 0.7,
1281
+ textureUrl: '/themes/textures/jungle-temple-timber-ai-v1.webp',
1282
+ textureWorldSize: [3.6, 3.6],
1283
+ bumpScale: 0.07,
1284
+ },
1285
+ [JUNGLE_TEMPLE_PLATFORM_MATERIAL_ID]: {
1286
+ kind: 'toon',
1287
+ color: '#ffffff',
1288
+ roughness: 0.94,
1289
+ metalness: 0,
1290
+ gradientSteps: 5,
1291
+ inkColor: '#1b160e',
1292
+ inkStrength: 0.07,
1293
+ envMapIntensity: 0.72,
1294
+ textureUrl: '/themes/textures/jungle-temple-bamboo-platform-ai-v1.webp',
1295
+ textureWorldSize: [4, 4],
1296
+ bumpScale: 0.055,
1297
+ },
1298
+ [JUNGLE_TEMPLE_BRONZE_MATERIAL_ID]: {
1299
+ kind: 'physical',
1300
+ color: '#ffffff',
1301
+ roughness: 0.52,
1302
+ metalness: 0.76,
1303
+ clearcoat: 0.12,
1304
+ clearcoatRoughness: 0.62,
1305
+ envMapIntensity: 1.05,
1306
+ textureUrl: '/themes/textures/jungle-temple-bronze-amber-ai-v1.webp',
1307
+ textureWorldSize: [3.2, 3.2],
1308
+ bumpScale: 0.035,
1309
+ },
1310
+ },
1311
+ environment: {
1312
+ background: '#5e8b4c',
1313
+ fog: '#7aa66b',
1314
+ fogNear: 72,
1315
+ fogFar: 285,
1316
+ environmentIntensity: 0.78,
1317
+ },
1318
+ lighting: {
1319
+ skyColor: '#dff4b4',
1320
+ groundColor: '#132816',
1321
+ ambientIntensity: 1.72,
1322
+ keyColor: '#fff0a5',
1323
+ keyIntensity: 4.05,
1324
+ keyPosition: [-24, 46, 20],
1325
+ rimColor: '#65c3a1',
1326
+ rimIntensity: 1.28,
1327
+ rimPosition: [32, 24, -30],
1328
+ exposure: 1.08,
1329
+ },
1330
+ world: { kit: 'jungle', density: 1 },
1331
+ particles: {
1332
+ style: 'fireflies',
1333
+ color: '#edff83',
1334
+ secondaryColor: '#ff9f5d',
1335
+ count: 260,
1336
+ size: 0.14,
1337
+ speed: 0.42,
1338
+ opacity: 0.62,
1339
+ },
1340
+ ambience: { style: 'jungle', volume: 0.045 },
1341
+ }
1342
+
1343
+ export const PAINTED_VALLEY_THEME: TrackThemeDefinition = {
1344
+ id: PAINTED_VALLEY_THEME_ID,
1345
+ version: 1,
1346
+ label: 'Painted Valley',
1347
+ shortLabel: 'Painted Valley',
1348
+ description: 'Hand-painted grass paths, pale birch boardwalks, ranch fences, tropical flowers, and drifting petals.',
1349
+ thumbnailUrl: uiPreview(PAINTED_VALLEY_THEME_ID, 'thumbnail'),
1350
+ pickerPreviewUrl: uiPreview(PAINTED_VALLEY_THEME_ID, 'picker'),
1351
+ loadingPreviewUrl: uiPreview(PAINTED_VALLEY_THEME_ID, 'loading'),
1352
+ previewUrl: openGraphPreview(PAINTED_VALLEY_THEME_ID),
1353
+ panoramaUrl: panorama(PAINTED_VALLEY_THEME_ID),
1354
+ materials: {
1355
+ ...createPaintedValleyMaterials(),
1356
+ ...createSharedObstacleMetalMaterials({ light: '#d37b65', dark: '#965144' }),
1357
+ },
1358
+ detailMaterials: {
1359
+ [PAINTED_VALLEY_GRASS_SHOULDER_MATERIAL_ID]: PAINTED_VALLEY_GRASS_SHOULDER_MATERIAL,
1360
+ 'wild-west.mine-timber': PAINTED_VALLEY_BIRCH_PLANK_MATERIAL,
1361
+ },
1362
+ appearancePresets: {
1363
+ floor: [
1364
+ {
1365
+ id: PAINTED_VALLEY_GRASS_ORANGE_DIRT_PATH_FLOOR_ID,
1366
+ label: 'Grass Path',
1367
+ default: true,
1368
+ material: PAINTED_VALLEY_GRASS_ORANGE_DIRT_PATH_MATERIAL,
1369
+ },
1370
+ {
1371
+ id: WILD_WEST_WOODEN_PLANKS_FLOOR_ID,
1372
+ label: 'Planks',
1373
+ material: PAINTED_VALLEY_BIRCH_PLANK_MATERIAL,
1374
+ },
1375
+ ],
1376
+ wall: [
1377
+ {
1378
+ id: 'wild-west.short-ranch-fence',
1379
+ label: 'Birch Fence',
1380
+ default: true,
1381
+ detailStyle: 'wild-west-short-ranch-fence',
1382
+ material: PAINTED_VALLEY_BIRCH_RANCH_FENCE_MATERIAL,
1383
+ },
1384
+ {
1385
+ id: PAINTED_VALLEY_TROPICAL_FLOWER_HEDGE_WALL_ID,
1386
+ label: 'Flower Hedge',
1387
+ detailStyle: 'jungle-flower-hedge',
1388
+ material: PAINTED_VALLEY_TROPICAL_FLOWER_HEDGE_CORE_MATERIAL,
1389
+ },
1390
+ ],
1391
+ },
1392
+ environment: {
1393
+ background: '#93c6df',
1394
+ fog: '#b7d1b7',
1395
+ fogNear: 92,
1396
+ fogFar: 360,
1397
+ environmentIntensity: 0.66,
1398
+ },
1399
+ lighting: {
1400
+ skyColor: '#d9eddd',
1401
+ groundColor: '#405641',
1402
+ ambientIntensity: 1.38,
1403
+ keyColor: '#fff1bf',
1404
+ keyIntensity: 2.85,
1405
+ keyPosition: [-34, 48, 28],
1406
+ rimColor: '#8eb8c4',
1407
+ rimIntensity: 0.9,
1408
+ rimPosition: [32, 22, -36],
1409
+ exposure: 0.9,
1410
+ },
1411
+ world: { kit: 'studio', density: 0 },
1412
+ particles: {
1413
+ style: 'petals',
1414
+ color: '#fff4e1',
1415
+ secondaryColor: '#e9a9a3',
1416
+ count: 230,
1417
+ size: 0.18,
1418
+ speed: 0.58,
1419
+ opacity: 0.72,
1420
+ },
1421
+ ambience: { style: 'meadow', volume: 0.045 },
1422
+ }
1423
+
1424
+ export const PRODUCTION_TRACK_THEMES = [
1425
+ ROCKY_MOUNTAIN_WILD_WEST_THEME,
1426
+ ANCIENT_EGYPT_THEME,
1427
+ JAPANESE_SAKURA_LAKE_THEME,
1428
+ INTERGALACTIC_SPACE_STATION_THEME,
1429
+ PAINTED_VALLEY_THEME,
1430
+ LOW_POLY_JUNGLE_THEME,
1431
+ ] as const
1432
+
1433
+ export const TRACK_THEMES = [
1434
+ ...PRODUCTION_TRACK_THEMES,
1435
+ VAMPIRE_CASTLE_THEME,
1436
+ NEUTRAL_STUDIO_THEME,
1437
+ MATERIAL_SLOT_DEBUG_THEME,
1438
+ ] as const
1439
+
1440
+ const themesById = new Map(TRACK_THEMES.map(theme => [theme.id, theme]))
1441
+
1442
+ export interface ThemeResolution {
1443
+ theme: TrackThemeDefinition
1444
+ requestedId: string
1445
+ usedFallback: boolean
1446
+ }
1447
+
1448
+ export function resolveTrackTheme(themeId: string): ThemeResolution {
1449
+ const theme = themesById.get(themeId)
1450
+ return theme
1451
+ ? { theme, requestedId: themeId, usedFallback: false }
1452
+ : { theme: NEUTRAL_STUDIO_THEME, requestedId: themeId, usedFallback: true }
1453
+ }
1454
+
1455
+ export function getTrackTheme(themeId: string): TrackThemeDefinition {
1456
+ return resolveTrackTheme(themeId).theme
1457
+ }