@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,258 @@
1
+ import * as THREE from 'three'
2
+
3
+ import { usesMobileRenderingBudget } from './mobile-rendering-budget'
4
+ import { KTX2Loader } from 'three/examples/jsm/loaders/KTX2Loader.js'
5
+
6
+ import type { MaterialRecipe, TrackAppearancePreset, TrackThemeDefinition } from './track-theme'
7
+ import { THEME_MATERIAL_KTX2_URLS } from './theme-material-ktx2-manifest'
8
+
9
+ interface DecodedImageEntry {
10
+ image?: HTMLImageElement
11
+ lastUsed: number
12
+ pins: number
13
+ promise: Promise<HTMLImageElement>
14
+ size: number
15
+ }
16
+
17
+ interface SharedThemeTextureEntry {
18
+ refs: number
19
+ releaseImage: () => void
20
+ texture: THREE.Texture
21
+ }
22
+
23
+ interface CompressedTextureEntry {
24
+ promise: Promise<THREE.CompressedTexture>
25
+ refs: number
26
+ texture?: THREE.CompressedTexture
27
+ }
28
+
29
+ const decodedImages = new Map<string, DecodedImageEntry>()
30
+ const compressedTextures = new Map<string, CompressedTextureEntry>()
31
+ const sharedThemeTextures = new Map<string, SharedThemeTextureEntry>()
32
+ const DESKTOP_DECODED_IMAGE_ALLOWANCE = 96 * 1024 * 1024
33
+ const MOBILE_DECODED_IMAGE_ALLOWANCE = 32 * 1024 * 1024
34
+ let ktx2Loader: KTX2Loader | undefined
35
+
36
+ export function configureThemeMaterialTextureLoader(renderer: THREE.WebGLRenderer): void {
37
+ if (ktx2Loader) return
38
+ ktx2Loader = new KTX2Loader().setTranscoderPath('/basis/').setWorkerLimit(2).detectSupport(renderer)
39
+ }
40
+
41
+ export function runtimeThemeMaterialAssetUrl(authoredUrl: string): string {
42
+ return THEME_MATERIAL_KTX2_URLS[authoredUrl] ?? authoredUrl
43
+ }
44
+
45
+ export function loadThemeKtx2Texture(url: string): Promise<THREE.CompressedTexture> {
46
+ if (!ktx2Loader) throw new Error('KTX2 texture loader has not been configured with a renderer.')
47
+ return ktx2Loader.loadAsync(url)
48
+ }
49
+
50
+ export function themeMaterialRecipeUrls(recipe: MaterialRecipe): string[] {
51
+ return [
52
+ recipe.textureUrl,
53
+ recipe.emissiveTextureUrl,
54
+ recipe.normalTextureUrl,
55
+ recipe.heightTextureUrl,
56
+ recipe.roughnessTextureUrl,
57
+ recipe.aoTextureUrl,
58
+ ].filter((url): url is string => Boolean(url))
59
+ }
60
+
61
+ export function themeMaterialAssetUrls(theme: TrackThemeDefinition): string[] {
62
+ const recipes: MaterialRecipe[] = [
63
+ ...Object.values(theme.materials),
64
+ ...Object.values(theme.detailMaterials ?? {}),
65
+ ...Object.values(theme.appearancePresets ?? {}).flatMap(
66
+ (presets: readonly TrackAppearancePreset[] | undefined) => presets?.map(preset => preset.material) ?? [],
67
+ ),
68
+ ]
69
+ return [...new Set(recipes.flatMap(themeMaterialRecipeUrls))]
70
+ }
71
+
72
+ export async function acquireThemeMaterialAssets(requestedUrls: readonly string[]): Promise<() => void> {
73
+ if (typeof document === 'undefined') return () => undefined
74
+ const leases = [...new Set(requestedUrls)].map(url => acquireThemeMaterialAsset(url, true))
75
+ try {
76
+ await Promise.all(leases.map(lease => lease.promise))
77
+ } catch (error) {
78
+ leases.forEach(lease => lease.release())
79
+ throw error
80
+ }
81
+ let released = false
82
+ return () => {
83
+ if (released) return
84
+ released = true
85
+ leases.forEach(lease => lease.release())
86
+ }
87
+ }
88
+
89
+ /**
90
+ * Creates a recipe-local texture while sharing the already decoded source
91
+ * image. Texture transforms remain independent, but downloads and decode work
92
+ * happen once before the theme is applied.
93
+ */
94
+ export function createThemeMaterialTexture(url: string, variant = 'default'): THREE.Texture {
95
+ const key = `${url}\u0000${variant}`
96
+ const shared = sharedThemeTextures.get(key)
97
+ if (shared) {
98
+ shared.refs += 1
99
+ return shared.texture
100
+ }
101
+ const runtimeUrl = runtimeThemeMaterialAssetUrl(url)
102
+ const lease = acquireThemeMaterialAsset(url, true)
103
+ const texture = runtimeUrl.endsWith('.ktx2')
104
+ ? new THREE.CompressedTexture([], 1, 1)
105
+ : new THREE.Texture(lease.imageEntry?.image)
106
+ texture.userData.themeAssetUrl = url
107
+ texture.userData.themeRuntimeAssetUrl = runtimeUrl
108
+ texture.userData.themeAssetKey = key
109
+ texture.userData.themeAssetReady = lease.promise.then(asset => {
110
+ if (asset instanceof THREE.Texture) hydrateCompressedTexture(texture as THREE.CompressedTexture, asset)
111
+ else texture.image = asset
112
+ texture.needsUpdate = true
113
+ })
114
+ if (lease.imageEntry?.image) texture.needsUpdate = true
115
+ if (lease.compressedEntry?.texture) {
116
+ hydrateCompressedTexture(texture as THREE.CompressedTexture, lease.compressedEntry.texture)
117
+ }
118
+ sharedThemeTextures.set(key, { refs: 1, releaseImage: lease.release, texture })
119
+ return texture
120
+ }
121
+
122
+ function acquireThemeMaterialAsset(
123
+ authoredUrl: string,
124
+ pin: boolean,
125
+ ): {
126
+ compressedEntry?: CompressedTextureEntry
127
+ imageEntry?: DecodedImageEntry
128
+ promise: Promise<HTMLImageElement | THREE.CompressedTexture>
129
+ release: () => void
130
+ } {
131
+ const runtimeUrl = runtimeThemeMaterialAssetUrl(authoredUrl)
132
+ if (!runtimeUrl.endsWith('.ktx2')) {
133
+ const lease = acquireDecodedImage(runtimeUrl, pin)
134
+ return { imageEntry: lease.entry, promise: lease.promise, release: lease.release }
135
+ }
136
+ if (!ktx2Loader) throw new Error('KTX2 material loader has not been configured with a renderer.')
137
+ let entry = compressedTextures.get(runtimeUrl)
138
+ if (!entry) {
139
+ const created: CompressedTextureEntry = { promise: Promise.resolve(undefined as never), refs: 0 }
140
+ created.promise = ktx2Loader
141
+ .loadAsync(runtimeUrl)
142
+ .then(texture => {
143
+ created.texture = texture
144
+ return texture
145
+ })
146
+ .catch(error => {
147
+ if (compressedTextures.get(runtimeUrl) === created) compressedTextures.delete(runtimeUrl)
148
+ throw error
149
+ })
150
+ compressedTextures.set(runtimeUrl, created)
151
+ entry = created
152
+ }
153
+ entry.refs += 1
154
+ let released = false
155
+ return {
156
+ compressedEntry: entry,
157
+ promise: entry.promise,
158
+ release: () => {
159
+ if (released) return
160
+ released = true
161
+ entry!.refs = Math.max(0, entry!.refs - 1)
162
+ releaseCompressedTextureEntry(runtimeUrl, entry!)
163
+ },
164
+ }
165
+ }
166
+
167
+ function releaseCompressedTextureEntry(runtimeUrl: string, entry: CompressedTextureEntry): void {
168
+ if (entry.refs > 0 || compressedTextures.get(runtimeUrl) !== entry) return
169
+ if (entry.texture) {
170
+ compressedTextures.delete(runtimeUrl)
171
+ entry.texture.dispose()
172
+ return
173
+ }
174
+ void entry.promise.then(
175
+ () => releaseCompressedTextureEntry(runtimeUrl, entry),
176
+ () => {
177
+ if (compressedTextures.get(runtimeUrl) === entry) compressedTextures.delete(runtimeUrl)
178
+ },
179
+ )
180
+ }
181
+
182
+ function hydrateCompressedTexture(target: THREE.CompressedTexture, source: THREE.CompressedTexture): void {
183
+ target.image = source.image
184
+ target.mipmaps = source.mipmaps
185
+ target.format = source.format
186
+ target.internalFormat = source.internalFormat
187
+ target.type = source.type
188
+ target.flipY = false
189
+ target.generateMipmaps = false
190
+ }
191
+
192
+ /** Returns true only when the caller owns the final GPU texture reference. */
193
+ export function releaseThemeMaterialTexture(texture: THREE.Texture): boolean {
194
+ const key = texture.userData.themeAssetKey
195
+ if (typeof key !== 'string') return true
196
+ const shared = sharedThemeTextures.get(key)
197
+ if (!shared || shared.texture !== texture) return true
198
+ shared.refs = Math.max(0, shared.refs - 1)
199
+ if (shared.refs > 0) return false
200
+ sharedThemeTextures.delete(key)
201
+ shared.releaseImage()
202
+ delete texture.userData.themeAssetKey
203
+ return true
204
+ }
205
+
206
+ function acquireDecodedImage(
207
+ url: string,
208
+ pin: boolean,
209
+ ): { entry: DecodedImageEntry; promise: Promise<HTMLImageElement>; release: () => void } {
210
+ let entry = decodedImages.get(url)
211
+ if (!entry) {
212
+ entry = { lastUsed: performance.now(), pins: 0, promise: Promise.resolve(undefined as never), size: 0 }
213
+ entry.promise = new THREE.ImageLoader()
214
+ .loadAsync(url)
215
+ .then(image => {
216
+ entry!.image = image
217
+ entry!.size =
218
+ Math.max(1, image.naturalWidth || image.width) * Math.max(1, image.naturalHeight || image.height) * 4
219
+ entry!.lastUsed = performance.now()
220
+ evictDecodedImages()
221
+ return image
222
+ })
223
+ .catch(error => {
224
+ decodedImages.delete(url)
225
+ throw error
226
+ })
227
+ decodedImages.set(url, entry)
228
+ }
229
+ entry.lastUsed = performance.now()
230
+ if (pin) entry.pins += 1
231
+ let released = false
232
+ return {
233
+ entry,
234
+ promise: entry.promise,
235
+ release: () => {
236
+ if (released || !pin) return
237
+ released = true
238
+ entry!.pins = Math.max(0, entry!.pins - 1)
239
+ entry!.lastUsed = performance.now()
240
+ evictDecodedImages()
241
+ },
242
+ }
243
+ }
244
+
245
+ function evictDecodedImages(): void {
246
+ const mobile = usesMobileRenderingBudget()
247
+ const allowance = mobile ? MOBILE_DECODED_IMAGE_ALLOWANCE : DESKTOP_DECODED_IMAGE_ALLOWANCE
248
+ let decodedBytes = [...decodedImages.values()].reduce((total, entry) => total + entry.size, 0)
249
+ if (decodedBytes <= allowance) return
250
+ const candidates = [...decodedImages.entries()]
251
+ .filter(([, entry]) => entry.pins === 0 && entry.image)
252
+ .sort((left, right) => left[1].lastUsed - right[1].lastUsed)
253
+ for (const [url, entry] of candidates) {
254
+ if (decodedBytes <= allowance) break
255
+ decodedImages.delete(url)
256
+ decodedBytes -= entry.size
257
+ }
258
+ }
@@ -0,0 +1,190 @@
1
+ // Generated by scripts/optimize-theme-textures.ts. Do not edit manually.
2
+ export const THEME_MATERIAL_KTX2_URLS: Readonly<Record<string, string>> = {
3
+ "/themes/textures/ancient-egypt-ashlar-v2-ao.webp": "/themes/textures/ancient-egypt-ashlar-v2-ao.ktx2",
4
+ "/themes/textures/ancient-egypt-ashlar-v2-height.webp": "/themes/textures/ancient-egypt-ashlar-v2-height.ktx2",
5
+ "/themes/textures/ancient-egypt-ashlar-v2-normal.webp": "/themes/textures/ancient-egypt-ashlar-v2-normal.ktx2",
6
+ "/themes/textures/ancient-egypt-ashlar-v2-roughness.webp": "/themes/textures/ancient-egypt-ashlar-v2-roughness.ktx2",
7
+ "/themes/textures/ancient-egypt-ashlar-v3-limestone-albedo.webp": "/themes/textures/ancient-egypt-ashlar-v3-limestone-albedo.ktx2",
8
+ "/themes/textures/ancient-egypt-block-limestone-v1-albedo.webp": "/themes/textures/ancient-egypt-block-limestone-v1-albedo.ktx2",
9
+ "/themes/textures/ancient-egypt-block-limestone-v1-ao.webp": "/themes/textures/ancient-egypt-block-limestone-v1-ao.ktx2",
10
+ "/themes/textures/ancient-egypt-block-limestone-v1-height.webp": "/themes/textures/ancient-egypt-block-limestone-v1-height.ktx2",
11
+ "/themes/textures/ancient-egypt-block-limestone-v1-normal.webp": "/themes/textures/ancient-egypt-block-limestone-v1-normal.ktx2",
12
+ "/themes/textures/ancient-egypt-block-limestone-v1-roughness.webp": "/themes/textures/ancient-egypt-block-limestone-v1-roughness.ktx2",
13
+ "/themes/textures/ancient-egypt-paving-v5-approved-albedo.webp": "/themes/textures/ancient-egypt-paving-v5-approved-albedo.ktx2",
14
+ "/themes/textures/ancient-egypt-paving-v5-approved-ao.webp": "/themes/textures/ancient-egypt-paving-v5-approved-ao.ktx2",
15
+ "/themes/textures/ancient-egypt-paving-v5-approved-height.webp": "/themes/textures/ancient-egypt-paving-v5-approved-height.ktx2",
16
+ "/themes/textures/ancient-egypt-paving-v5-approved-normal.webp": "/themes/textures/ancient-egypt-paving-v5-approved-normal.ktx2",
17
+ "/themes/textures/ancient-egypt-paving-v5-approved-roughness.webp": "/themes/textures/ancient-egypt-paving-v5-approved-roughness.ktx2",
18
+ "/themes/textures/ancient-egypt-pyramid-limestone-v1-albedo.webp": "/themes/textures/ancient-egypt-pyramid-limestone-v1-albedo.ktx2",
19
+ "/themes/textures/ancient-egypt-pyramid-limestone-v1-ao.png": "/themes/textures/ancient-egypt-pyramid-limestone-v1-ao.ktx2",
20
+ "/themes/textures/ancient-egypt-pyramid-limestone-v1-height.png": "/themes/textures/ancient-egypt-pyramid-limestone-v1-height.ktx2",
21
+ "/themes/textures/ancient-egypt-pyramid-limestone-v1-normal.png": "/themes/textures/ancient-egypt-pyramid-limestone-v1-normal.ktx2",
22
+ "/themes/textures/ancient-egypt-pyramid-limestone-v1-roughness.png": "/themes/textures/ancient-egypt-pyramid-limestone-v1-roughness.ktx2",
23
+ "/themes/textures/japanese-sakura-castle-ashlar-albedo-v1.png": "/themes/textures/japanese-sakura-castle-ashlar-albedo-v1.ktx2",
24
+ "/themes/textures/japanese-sakura-castle-ashlar-ao-v1.png": "/themes/textures/japanese-sakura-castle-ashlar-ao-v1.ktx2",
25
+ "/themes/textures/japanese-sakura-castle-ashlar-height-v1.png": "/themes/textures/japanese-sakura-castle-ashlar-height-v1.ktx2",
26
+ "/themes/textures/japanese-sakura-castle-ashlar-normal-v1.png": "/themes/textures/japanese-sakura-castle-ashlar-normal-v1.ktx2",
27
+ "/themes/textures/japanese-sakura-castle-ashlar-roughness-v1.png": "/themes/textures/japanese-sakura-castle-ashlar-roughness-v1.ktx2",
28
+ "/themes/textures/japanese-sakura-castle-kawara-v1-albedo.webp": "/themes/textures/japanese-sakura-castle-kawara-v1-albedo.ktx2",
29
+ "/themes/textures/japanese-sakura-castle-kawara-v1-ao.png": "/themes/textures/japanese-sakura-castle-kawara-v1-ao.ktx2",
30
+ "/themes/textures/japanese-sakura-castle-kawara-v1-height.png": "/themes/textures/japanese-sakura-castle-kawara-v1-height.ktx2",
31
+ "/themes/textures/japanese-sakura-castle-kawara-v1-normal.png": "/themes/textures/japanese-sakura-castle-kawara-v1-normal.ktx2",
32
+ "/themes/textures/japanese-sakura-castle-kawara-v1-roughness.png": "/themes/textures/japanese-sakura-castle-kawara-v1-roughness.ktx2",
33
+ "/themes/textures/japanese-sakura-castle-masonry-sill-v1-albedo.webp": "/themes/textures/japanese-sakura-castle-masonry-sill-v1-albedo.ktx2",
34
+ "/themes/textures/japanese-sakura-castle-masonry-sill-v1-ao.png": "/themes/textures/japanese-sakura-castle-masonry-sill-v1-ao.ktx2",
35
+ "/themes/textures/japanese-sakura-castle-masonry-sill-v1-height.png": "/themes/textures/japanese-sakura-castle-masonry-sill-v1-height.ktx2",
36
+ "/themes/textures/japanese-sakura-castle-masonry-sill-v1-normal.png": "/themes/textures/japanese-sakura-castle-masonry-sill-v1-normal.ktx2",
37
+ "/themes/textures/japanese-sakura-castle-masonry-sill-v1-roughness.png": "/themes/textures/japanese-sakura-castle-masonry-sill-v1-roughness.ktx2",
38
+ "/themes/textures/japanese-sakura-castle-pavers-v1-albedo.webp": "/themes/textures/japanese-sakura-castle-pavers-v1-albedo.ktx2",
39
+ "/themes/textures/japanese-sakura-castle-pavers-v1-ao.png": "/themes/textures/japanese-sakura-castle-pavers-v1-ao.ktx2",
40
+ "/themes/textures/japanese-sakura-castle-pavers-v1-height.png": "/themes/textures/japanese-sakura-castle-pavers-v1-height.ktx2",
41
+ "/themes/textures/japanese-sakura-castle-pavers-v1-normal.png": "/themes/textures/japanese-sakura-castle-pavers-v1-normal.ktx2",
42
+ "/themes/textures/japanese-sakura-castle-pavers-v1-roughness.png": "/themes/textures/japanese-sakura-castle-pavers-v1-roughness.ktx2",
43
+ "/themes/textures/japanese-sakura-castle-plaster-v1-albedo.webp": "/themes/textures/japanese-sakura-castle-plaster-v1-albedo.ktx2",
44
+ "/themes/textures/japanese-sakura-castle-plaster-v1-ao.png": "/themes/textures/japanese-sakura-castle-plaster-v1-ao.ktx2",
45
+ "/themes/textures/japanese-sakura-castle-plaster-v1-height.png": "/themes/textures/japanese-sakura-castle-plaster-v1-height.ktx2",
46
+ "/themes/textures/japanese-sakura-castle-plaster-v1-normal.png": "/themes/textures/japanese-sakura-castle-plaster-v1-normal.ktx2",
47
+ "/themes/textures/japanese-sakura-castle-plaster-v1-roughness.png": "/themes/textures/japanese-sakura-castle-plaster-v1-roughness.ktx2",
48
+ "/themes/textures/japanese-sakura-castle-timber-v1-albedo.webp": "/themes/textures/japanese-sakura-castle-timber-v1-albedo.ktx2",
49
+ "/themes/textures/japanese-sakura-castle-timber-v1-ao.png": "/themes/textures/japanese-sakura-castle-timber-v1-ao.ktx2",
50
+ "/themes/textures/japanese-sakura-castle-timber-v1-height.png": "/themes/textures/japanese-sakura-castle-timber-v1-height.ktx2",
51
+ "/themes/textures/japanese-sakura-castle-timber-v1-normal.png": "/themes/textures/japanese-sakura-castle-timber-v1-normal.ktx2",
52
+ "/themes/textures/japanese-sakura-castle-timber-v1-roughness.png": "/themes/textures/japanese-sakura-castle-timber-v1-roughness.ktx2",
53
+ "/themes/textures/japanese-sakura-portal-foundation-stone-v1-albedo.webp": "/themes/textures/japanese-sakura-portal-foundation-stone-v1-albedo.ktx2",
54
+ "/themes/textures/japanese-sakura-portal-foundation-stone-v1-ao.png": "/themes/textures/japanese-sakura-portal-foundation-stone-v1-ao.ktx2",
55
+ "/themes/textures/japanese-sakura-portal-foundation-stone-v1-height.png": "/themes/textures/japanese-sakura-portal-foundation-stone-v1-height.ktx2",
56
+ "/themes/textures/japanese-sakura-portal-foundation-stone-v1-normal.png": "/themes/textures/japanese-sakura-portal-foundation-stone-v1-normal.ktx2",
57
+ "/themes/textures/japanese-sakura-portal-foundation-stone-v1-roughness.png": "/themes/textures/japanese-sakura-portal-foundation-stone-v1-roughness.ktx2",
58
+ "/themes/textures/japanese-sakura-redwood-planks-v1-albedo.webp": "/themes/textures/japanese-sakura-redwood-planks-v1-albedo.ktx2",
59
+ "/themes/textures/japanese-sakura-redwood-planks-v1-ao.png": "/themes/textures/japanese-sakura-redwood-planks-v1-ao.ktx2",
60
+ "/themes/textures/japanese-sakura-redwood-planks-v1-height.png": "/themes/textures/japanese-sakura-redwood-planks-v1-height.ktx2",
61
+ "/themes/textures/japanese-sakura-redwood-planks-v1-normal.png": "/themes/textures/japanese-sakura-redwood-planks-v1-normal.ktx2",
62
+ "/themes/textures/japanese-sakura-redwood-planks-v1-roughness.png": "/themes/textures/japanese-sakura-redwood-planks-v1-roughness.ktx2",
63
+ "/themes/textures/japanese-sakura-vermilion-lacquer-v2-albedo.webp": "/themes/textures/japanese-sakura-vermilion-lacquer-v2-albedo.ktx2",
64
+ "/themes/textures/japanese-sakura-vermilion-lacquer-v2-ao.png": "/themes/textures/japanese-sakura-vermilion-lacquer-v2-ao.ktx2",
65
+ "/themes/textures/japanese-sakura-vermilion-lacquer-v2-height.png": "/themes/textures/japanese-sakura-vermilion-lacquer-v2-height.ktx2",
66
+ "/themes/textures/japanese-sakura-vermilion-lacquer-v2-normal.png": "/themes/textures/japanese-sakura-vermilion-lacquer-v2-normal.ktx2",
67
+ "/themes/textures/japanese-sakura-vermilion-lacquer-v2-roughness.png": "/themes/textures/japanese-sakura-vermilion-lacquer-v2-roughness.ktx2",
68
+ "/themes/textures/jungle-temple-bamboo-platform-ai-v1.webp": "/themes/textures/jungle-temple-bamboo-platform-ai-v1.ktx2",
69
+ "/themes/textures/jungle-temple-bronze-amber-ai-v1.webp": "/themes/textures/jungle-temple-bronze-amber-ai-v1.ktx2",
70
+ "/themes/textures/jungle-temple-elevator-masonry-v3-albedo.webp": "/themes/textures/jungle-temple-elevator-masonry-v3-albedo.ktx2",
71
+ "/themes/textures/jungle-temple-elevator-masonry-v3-ao.png": "/themes/textures/jungle-temple-elevator-masonry-v3-ao.ktx2",
72
+ "/themes/textures/jungle-temple-elevator-masonry-v3-height.png": "/themes/textures/jungle-temple-elevator-masonry-v3-height.ktx2",
73
+ "/themes/textures/jungle-temple-elevator-masonry-v3-normal.png": "/themes/textures/jungle-temple-elevator-masonry-v3-normal.ktx2",
74
+ "/themes/textures/jungle-temple-elevator-masonry-v3-roughness.png": "/themes/textures/jungle-temple-elevator-masonry-v3-roughness.ktx2",
75
+ "/themes/textures/jungle-temple-mossy-block-stone-v3-albedo.webp": "/themes/textures/jungle-temple-mossy-block-stone-v3-albedo.ktx2",
76
+ "/themes/textures/jungle-temple-mossy-block-stone-v3-ao.png": "/themes/textures/jungle-temple-mossy-block-stone-v3-ao.ktx2",
77
+ "/themes/textures/jungle-temple-mossy-block-stone-v3-height.png": "/themes/textures/jungle-temple-mossy-block-stone-v3-height.ktx2",
78
+ "/themes/textures/jungle-temple-mossy-block-stone-v3-normal.png": "/themes/textures/jungle-temple-mossy-block-stone-v3-normal.ktx2",
79
+ "/themes/textures/jungle-temple-mossy-block-stone-v3-roughness.png": "/themes/textures/jungle-temple-mossy-block-stone-v3-roughness.ktx2",
80
+ "/themes/textures/jungle-temple-mossy-flagstone-v3-albedo.webp": "/themes/textures/jungle-temple-mossy-flagstone-v3-albedo.ktx2",
81
+ "/themes/textures/jungle-temple-mossy-flagstone-v3-ao.png": "/themes/textures/jungle-temple-mossy-flagstone-v3-ao.ktx2",
82
+ "/themes/textures/jungle-temple-mossy-flagstone-v3-height.png": "/themes/textures/jungle-temple-mossy-flagstone-v3-height.ktx2",
83
+ "/themes/textures/jungle-temple-mossy-flagstone-v3-normal.png": "/themes/textures/jungle-temple-mossy-flagstone-v3-normal.ktx2",
84
+ "/themes/textures/jungle-temple-mossy-flagstone-v3-roughness.png": "/themes/textures/jungle-temple-mossy-flagstone-v3-roughness.ktx2",
85
+ "/themes/textures/jungle-temple-serpent-facade-v3-albedo.webp": "/themes/textures/jungle-temple-serpent-facade-v3-albedo.ktx2",
86
+ "/themes/textures/jungle-temple-serpent-facade-v3-ao.png": "/themes/textures/jungle-temple-serpent-facade-v3-ao.ktx2",
87
+ "/themes/textures/jungle-temple-serpent-facade-v3-height.png": "/themes/textures/jungle-temple-serpent-facade-v3-height.ktx2",
88
+ "/themes/textures/jungle-temple-serpent-facade-v3-normal.png": "/themes/textures/jungle-temple-serpent-facade-v3-normal.ktx2",
89
+ "/themes/textures/jungle-temple-serpent-facade-v3-roughness.png": "/themes/textures/jungle-temple-serpent-facade-v3-roughness.ktx2",
90
+ "/themes/textures/jungle-temple-timber-ai-v1.webp": "/themes/textures/jungle-temple-timber-ai-v1.ktx2",
91
+ "/themes/textures/old-assets/shared-rope-bridge-end-grain-v2-albedo.webp": "/themes/textures/old-assets/shared-rope-bridge-end-grain-v2-albedo.ktx2",
92
+ "/themes/textures/old-assets/shared-rope-bridge-end-grain-v2-ao.png": "/themes/textures/old-assets/shared-rope-bridge-end-grain-v2-ao.ktx2",
93
+ "/themes/textures/old-assets/shared-rope-bridge-end-grain-v2-normal.png": "/themes/textures/old-assets/shared-rope-bridge-end-grain-v2-normal.ktx2",
94
+ "/themes/textures/old-assets/shared-rope-bridge-end-grain-v2-roughness.png": "/themes/textures/old-assets/shared-rope-bridge-end-grain-v2-roughness.ktx2",
95
+ "/themes/textures/old-assets/shared-rope-bridge-fibre-v2-albedo.webp": "/themes/textures/old-assets/shared-rope-bridge-fibre-v2-albedo.ktx2",
96
+ "/themes/textures/old-assets/shared-rope-bridge-fibre-v2-ao.png": "/themes/textures/old-assets/shared-rope-bridge-fibre-v2-ao.ktx2",
97
+ "/themes/textures/old-assets/shared-rope-bridge-fibre-v2-normal.png": "/themes/textures/old-assets/shared-rope-bridge-fibre-v2-normal.ktx2",
98
+ "/themes/textures/old-assets/shared-rope-bridge-fibre-v2-roughness.png": "/themes/textures/old-assets/shared-rope-bridge-fibre-v2-roughness.ktx2",
99
+ "/themes/textures/old-assets/shared-rope-bridge-mossy-planks-v2-albedo.webp": "/themes/textures/old-assets/shared-rope-bridge-mossy-planks-v2-albedo.ktx2",
100
+ "/themes/textures/old-assets/shared-rope-bridge-mossy-planks-v2-ao.png": "/themes/textures/old-assets/shared-rope-bridge-mossy-planks-v2-ao.ktx2",
101
+ "/themes/textures/old-assets/shared-rope-bridge-mossy-planks-v2-normal.png": "/themes/textures/old-assets/shared-rope-bridge-mossy-planks-v2-normal.ktx2",
102
+ "/themes/textures/old-assets/shared-rope-bridge-mossy-planks-v2-roughness.png": "/themes/textures/old-assets/shared-rope-bridge-mossy-planks-v2-roughness.ktx2",
103
+ "/themes/textures/old-assets/shared-rope-bridge-post-timber-v2-albedo.webp": "/themes/textures/old-assets/shared-rope-bridge-post-timber-v2-albedo.ktx2",
104
+ "/themes/textures/old-assets/shared-rope-bridge-post-timber-v2-ao.png": "/themes/textures/old-assets/shared-rope-bridge-post-timber-v2-ao.ktx2",
105
+ "/themes/textures/old-assets/shared-rope-bridge-post-timber-v2-normal.png": "/themes/textures/old-assets/shared-rope-bridge-post-timber-v2-normal.ktx2",
106
+ "/themes/textures/old-assets/shared-rope-bridge-post-timber-v2-roughness.png": "/themes/textures/old-assets/shared-rope-bridge-post-timber-v2-roughness.ktx2",
107
+ "/themes/textures/old-assets/wild-west-dirt-shoulder-v4.png": "/themes/textures/old-assets/wild-west-dirt-shoulder-v4.ktx2",
108
+ "/themes/textures/old-assets/wild-west-portal-hand-hewn-timber-v2-albedo.webp": "/themes/textures/old-assets/wild-west-portal-hand-hewn-timber-v2-albedo.ktx2",
109
+ "/themes/textures/old-assets/wild-west-portal-hand-hewn-timber-v2-ao.png": "/themes/textures/old-assets/wild-west-portal-hand-hewn-timber-v2-ao.ktx2",
110
+ "/themes/textures/old-assets/wild-west-portal-hand-hewn-timber-v2-height.png": "/themes/textures/old-assets/wild-west-portal-hand-hewn-timber-v2-height.ktx2",
111
+ "/themes/textures/old-assets/wild-west-portal-hand-hewn-timber-v2-normal.png": "/themes/textures/old-assets/wild-west-portal-hand-hewn-timber-v2-normal.ktx2",
112
+ "/themes/textures/old-assets/wild-west-portal-hand-hewn-timber-v2-roughness.png": "/themes/textures/old-assets/wild-west-portal-hand-hewn-timber-v2-roughness.ktx2",
113
+ "/themes/textures/old-assets/wild-west-sand-track-v2.png": "/themes/textures/old-assets/wild-west-sand-track-v2.ktx2",
114
+ "/themes/textures/old-assets/wild-west-stockade-plank-timber-v1-albedo.webp": "/themes/textures/old-assets/wild-west-stockade-plank-timber-v1-albedo.ktx2",
115
+ "/themes/textures/old-assets/wild-west-stockade-plank-timber-v1-ao.png": "/themes/textures/old-assets/wild-west-stockade-plank-timber-v1-ao.ktx2",
116
+ "/themes/textures/old-assets/wild-west-stockade-plank-timber-v1-normal.png": "/themes/textures/old-assets/wild-west-stockade-plank-timber-v1-normal.ktx2",
117
+ "/themes/textures/old-assets/wild-west-stockade-plank-timber-v1-roughness.png": "/themes/textures/old-assets/wild-west-stockade-plank-timber-v1-roughness.ktx2",
118
+ "/themes/textures/painted-valley-wild-west-birch-fence-v1-albedo.webp": "/themes/textures/painted-valley-wild-west-birch-fence-v1-albedo.ktx2",
119
+ "/themes/textures/painted-valley-wild-west-birch-planks-v1-albedo.webp": "/themes/textures/painted-valley-wild-west-birch-planks-v1-albedo.ktx2",
120
+ "/themes/textures/shared-hammered-gold-v1-albedo.webp": "/themes/textures/shared-hammered-gold-v1-albedo.ktx2",
121
+ "/themes/textures/shared-hammered-gold-v1-ao.png": "/themes/textures/shared-hammered-gold-v1-ao.ktx2",
122
+ "/themes/textures/shared-hammered-gold-v1-height.png": "/themes/textures/shared-hammered-gold-v1-height.ktx2",
123
+ "/themes/textures/shared-hammered-gold-v1-normal.png": "/themes/textures/shared-hammered-gold-v1-normal.ktx2",
124
+ "/themes/textures/shared-hammered-gold-v1-roughness.png": "/themes/textures/shared-hammered-gold-v1-roughness.ktx2",
125
+ "/themes/textures/space-station-floor-deck-v2-neutral-albedo.webp": "/themes/textures/space-station-floor-deck-v2-neutral-albedo.ktx2",
126
+ "/themes/textures/space-station-floor-deck-v2-neutral-ao.png": "/themes/textures/space-station-floor-deck-v2-neutral-ao.ktx2",
127
+ "/themes/textures/space-station-floor-deck-v2-neutral-height.png": "/themes/textures/space-station-floor-deck-v2-neutral-height.ktx2",
128
+ "/themes/textures/space-station-floor-deck-v2-neutral-normal.png": "/themes/textures/space-station-floor-deck-v2-neutral-normal.ktx2",
129
+ "/themes/textures/space-station-floor-deck-v2-neutral-roughness.png": "/themes/textures/space-station-floor-deck-v2-neutral-roughness.ktx2",
130
+ "/themes/textures/space-station-wall-chassis-v1-albedo.webp": "/themes/textures/space-station-wall-chassis-v1-albedo.ktx2",
131
+ "/themes/textures/space-station-wall-chassis-v1-ao.png": "/themes/textures/space-station-wall-chassis-v1-ao.ktx2",
132
+ "/themes/textures/space-station-wall-chassis-v1-height.png": "/themes/textures/space-station-wall-chassis-v1-height.ktx2",
133
+ "/themes/textures/space-station-wall-chassis-v1-normal.png": "/themes/textures/space-station-wall-chassis-v1-normal.ktx2",
134
+ "/themes/textures/space-station-wall-chassis-v1-roughness.png": "/themes/textures/space-station-wall-chassis-v1-roughness.ktx2",
135
+ "/themes/textures/space-station-wall-panel-v1-albedo.webp": "/themes/textures/space-station-wall-panel-v1-albedo.ktx2",
136
+ "/themes/textures/space-station-wall-panel-v1-ao.png": "/themes/textures/space-station-wall-panel-v1-ao.ktx2",
137
+ "/themes/textures/space-station-wall-panel-v1-height.png": "/themes/textures/space-station-wall-panel-v1-height.ktx2",
138
+ "/themes/textures/space-station-wall-panel-v1-normal.png": "/themes/textures/space-station-wall-panel-v1-normal.ktx2",
139
+ "/themes/textures/space-station-wall-panel-v1-roughness.png": "/themes/textures/space-station-wall-panel-v1-roughness.ktx2",
140
+ "/themes/textures/space-station-wall-rib-v1-albedo.webp": "/themes/textures/space-station-wall-rib-v1-albedo.ktx2",
141
+ "/themes/textures/space-station-wall-rib-v1-ao.png": "/themes/textures/space-station-wall-rib-v1-ao.ktx2",
142
+ "/themes/textures/space-station-wall-rib-v1-height.png": "/themes/textures/space-station-wall-rib-v1-height.ktx2",
143
+ "/themes/textures/space-station-wall-rib-v1-normal.png": "/themes/textures/space-station-wall-rib-v1-normal.ktx2",
144
+ "/themes/textures/space-station-wall-rib-v1-roughness.png": "/themes/textures/space-station-wall-rib-v1-roughness.ktx2",
145
+ "/themes/textures/vampire-castle-checker-marble-floor-v1-albedo.webp": "/themes/textures/vampire-castle-checker-marble-floor-v1-albedo.ktx2",
146
+ "/themes/textures/vampire-castle-checker-marble-floor-v1-ao.png": "/themes/textures/vampire-castle-checker-marble-floor-v1-ao.ktx2",
147
+ "/themes/textures/vampire-castle-checker-marble-floor-v1-height.png": "/themes/textures/vampire-castle-checker-marble-floor-v1-height.ktx2",
148
+ "/themes/textures/vampire-castle-checker-marble-floor-v1-normal.png": "/themes/textures/vampire-castle-checker-marble-floor-v1-normal.ktx2",
149
+ "/themes/textures/vampire-castle-checker-marble-floor-v1-roughness.png": "/themes/textures/vampire-castle-checker-marble-floor-v1-roughness.ktx2",
150
+ "/themes/textures/vampire-castle-cobblestone-floor-v1-albedo.webp": "/themes/textures/vampire-castle-cobblestone-floor-v1-albedo.ktx2",
151
+ "/themes/textures/vampire-castle-cobblestone-floor-v1-ao.png": "/themes/textures/vampire-castle-cobblestone-floor-v1-ao.ktx2",
152
+ "/themes/textures/vampire-castle-cobblestone-floor-v1-height.png": "/themes/textures/vampire-castle-cobblestone-floor-v1-height.ktx2",
153
+ "/themes/textures/vampire-castle-cobblestone-floor-v1-normal.png": "/themes/textures/vampire-castle-cobblestone-floor-v1-normal.ktx2",
154
+ "/themes/textures/vampire-castle-cobblestone-floor-v1-roughness.png": "/themes/textures/vampire-castle-cobblestone-floor-v1-roughness.ktx2",
155
+ "/themes/textures/vampire-castle-crimson-carpet-v1-albedo.webp": "/themes/textures/vampire-castle-crimson-carpet-v1-albedo.ktx2",
156
+ "/themes/textures/vampire-castle-crimson-carpet-v1-ao.png": "/themes/textures/vampire-castle-crimson-carpet-v1-ao.ktx2",
157
+ "/themes/textures/vampire-castle-crimson-carpet-v1-height.png": "/themes/textures/vampire-castle-crimson-carpet-v1-height.ktx2",
158
+ "/themes/textures/vampire-castle-crimson-carpet-v1-normal.png": "/themes/textures/vampire-castle-crimson-carpet-v1-normal.ktx2",
159
+ "/themes/textures/vampire-castle-crimson-carpet-v1-roughness.png": "/themes/textures/vampire-castle-crimson-carpet-v1-roughness.ktx2",
160
+ "/themes/textures/vampire-castle-dark-oak-floor-v1-albedo.webp": "/themes/textures/vampire-castle-dark-oak-floor-v1-albedo.ktx2",
161
+ "/themes/textures/vampire-castle-dark-oak-floor-v1-ao.png": "/themes/textures/vampire-castle-dark-oak-floor-v1-ao.ktx2",
162
+ "/themes/textures/vampire-castle-dark-oak-floor-v1-height.png": "/themes/textures/vampire-castle-dark-oak-floor-v1-height.ktx2",
163
+ "/themes/textures/vampire-castle-dark-oak-floor-v1-normal.png": "/themes/textures/vampire-castle-dark-oak-floor-v1-normal.ktx2",
164
+ "/themes/textures/vampire-castle-dark-oak-floor-v1-roughness.png": "/themes/textures/vampire-castle-dark-oak-floor-v1-roughness.ktx2",
165
+ "/themes/textures/vampire-castle-dark-stone-wall-v1-albedo.webp": "/themes/textures/vampire-castle-dark-stone-wall-v1-albedo.ktx2",
166
+ "/themes/textures/vampire-castle-dark-stone-wall-v1-ao.png": "/themes/textures/vampire-castle-dark-stone-wall-v1-ao.ktx2",
167
+ "/themes/textures/vampire-castle-dark-stone-wall-v1-height.png": "/themes/textures/vampire-castle-dark-stone-wall-v1-height.ktx2",
168
+ "/themes/textures/vampire-castle-dark-stone-wall-v1-normal.png": "/themes/textures/vampire-castle-dark-stone-wall-v1-normal.ktx2",
169
+ "/themes/textures/vampire-castle-dark-stone-wall-v1-roughness.png": "/themes/textures/vampire-castle-dark-stone-wall-v1-roughness.ktx2",
170
+ "/themes/textures/vampire-castle-plain-oak-wall-v2-albedo.webp": "/themes/textures/vampire-castle-plain-oak-wall-v2-albedo.ktx2",
171
+ "/themes/textures/vampire-castle-plain-oak-wall-v2-ao.png": "/themes/textures/vampire-castle-plain-oak-wall-v2-ao.ktx2",
172
+ "/themes/textures/vampire-castle-plain-oak-wall-v2-height.png": "/themes/textures/vampire-castle-plain-oak-wall-v2-height.ktx2",
173
+ "/themes/textures/vampire-castle-plain-oak-wall-v2-normal.png": "/themes/textures/vampire-castle-plain-oak-wall-v2-normal.ktx2",
174
+ "/themes/textures/vampire-castle-plain-oak-wall-v2-roughness.png": "/themes/textures/vampire-castle-plain-oak-wall-v2-roughness.ktx2",
175
+ "/themes/textures/wild-west-canyon-sandstone-v1-albedo.webp": "/themes/textures/wild-west-canyon-sandstone-v1-albedo.ktx2",
176
+ "/themes/textures/wild-west-canyon-sandstone-v1-ao.webp": "/themes/textures/wild-west-canyon-sandstone-v1-ao.ktx2",
177
+ "/themes/textures/wild-west-canyon-sandstone-v1-height.webp": "/themes/textures/wild-west-canyon-sandstone-v1-height.ktx2",
178
+ "/themes/textures/wild-west-canyon-sandstone-v1-normal.webp": "/themes/textures/wild-west-canyon-sandstone-v1-normal.ktx2",
179
+ "/themes/textures/wild-west-canyon-sandstone-v1-roughness.webp": "/themes/textures/wild-west-canyon-sandstone-v1-roughness.ktx2",
180
+ "/themes/textures/wild-west-covered-mine-iron-v1-albedo.webp": "/themes/textures/wild-west-covered-mine-iron-v1-albedo.ktx2",
181
+ "/themes/textures/wild-west-covered-mine-iron-v1-ao.png": "/themes/textures/wild-west-covered-mine-iron-v1-ao.ktx2",
182
+ "/themes/textures/wild-west-covered-mine-iron-v1-height.png": "/themes/textures/wild-west-covered-mine-iron-v1-height.ktx2",
183
+ "/themes/textures/wild-west-covered-mine-iron-v1-normal.png": "/themes/textures/wild-west-covered-mine-iron-v1-normal.ktx2",
184
+ "/themes/textures/wild-west-covered-mine-iron-v1-roughness.png": "/themes/textures/wild-west-covered-mine-iron-v1-roughness.ktx2",
185
+ "/themes/textures/wild-west-covered-mine-timber-v1-albedo.webp": "/themes/textures/wild-west-covered-mine-timber-v1-albedo.ktx2",
186
+ "/themes/textures/wild-west-covered-mine-timber-v1-ao.png": "/themes/textures/wild-west-covered-mine-timber-v1-ao.ktx2",
187
+ "/themes/textures/wild-west-covered-mine-timber-v1-height.png": "/themes/textures/wild-west-covered-mine-timber-v1-height.ktx2",
188
+ "/themes/textures/wild-west-covered-mine-timber-v1-normal.png": "/themes/textures/wild-west-covered-mine-timber-v1-normal.ktx2",
189
+ "/themes/textures/wild-west-covered-mine-timber-v1-roughness.png": "/themes/textures/wild-west-covered-mine-timber-v1-roughness.ktx2",
190
+ }