procedural-terrains 2.0.0 → 2.0.1

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 (43) hide show
  1. package/dist/{FiniteTerrain-B34WMz5S.js → FiniteTerrain-B5_3y6xX.js} +3 -3
  2. package/dist/{FiniteTerrain-B34WMz5S.js.map → FiniteTerrain-B5_3y6xX.js.map} +1 -1
  3. package/dist/{InfiniteTerrain-SgoJz3qJ.js → InfiniteTerrain-jeCy6RED.js} +5 -5
  4. package/dist/{InfiniteTerrain-SgoJz3qJ.js.map → InfiniteTerrain-jeCy6RED.js.map} +1 -1
  5. package/dist/{MiniTerrain-Blt0H1S0.js → MiniTerrain-Bb5VYkZU.js} +8 -8
  6. package/dist/MiniTerrain-Bb5VYkZU.js.map +1 -0
  7. package/dist/{PlanetMaterial-B1_ZPlx5.js → PlanetMaterial-Cs-_x6vr.js} +4 -4
  8. package/dist/{PlanetMaterial-B1_ZPlx5.js.map → PlanetMaterial-Cs-_x6vr.js.map} +1 -1
  9. package/dist/{PlanetTerrain-DCvxS1Q8.js → PlanetTerrain-Bsfx7YA6.js} +5 -5
  10. package/dist/{PlanetTerrain-DCvxS1Q8.js.map → PlanetTerrain-Bsfx7YA6.js.map} +1 -1
  11. package/dist/{RevisionScope-J__6V9I_.js → RevisionScope-Dl4yjj-0.js} +2 -2
  12. package/dist/{RevisionScope-J__6V9I_.js.map → RevisionScope-Dl4yjj-0.js.map} +1 -1
  13. package/dist/{TerrainClouds-BuKvwnWw.js → TerrainClouds-DV6ny7P1.js} +31 -19
  14. package/dist/TerrainClouds-DV6ny7P1.js.map +1 -0
  15. package/dist/{TerrainHeightCache-Dsde6EDL.js → TerrainHeightCache-DIZxi9jz.js} +2 -2
  16. package/dist/{TerrainHeightCache-Dsde6EDL.js.map → TerrainHeightCache-DIZxi9jz.js.map} +1 -1
  17. package/dist/{TerrainParameters-A3fcNJTR.js → TerrainParameters-DMCjnnxz.js} +10 -8
  18. package/dist/TerrainParameters-DMCjnnxz.js.map +1 -0
  19. package/dist/{TerrainWater-Cil7waG3.js → TerrainWater-CX4XdwA0.js} +17 -11
  20. package/dist/TerrainWater-CX4XdwA0.js.map +1 -0
  21. package/dist/{WaterMaterial-BUsAp0SS.js → WaterMaterial-C9h1xm9E.js} +7 -5
  22. package/dist/WaterMaterial-C9h1xm9E.js.map +1 -0
  23. package/dist/{biomeGLSL-CIkhxIlH.js → biomeGLSL-DWGDDBqT.js} +6 -3
  24. package/dist/{biomeGLSL-CIkhxIlH.js.map → biomeGLSL-DWGDDBqT.js.map} +1 -1
  25. package/dist/clouds.js +1 -1
  26. package/dist/documents.js +6 -6
  27. package/dist/export.js +2 -2
  28. package/dist/index.js +1 -1
  29. package/dist/infinite.js +1 -1
  30. package/dist/mini.js +1 -1
  31. package/dist/planet.js +1 -1
  32. package/dist/{planetGLSL-2xas0f3o.js → planetGLSL-D9Zy2IAw.js} +2 -2
  33. package/dist/{planetGLSL-2xas0f3o.js.map → planetGLSL-D9Zy2IAw.js.map} +1 -1
  34. package/dist/real-world.js +1 -1
  35. package/dist/render.js +1 -1
  36. package/dist/viewer.js +1 -1
  37. package/dist/water.js +1 -1
  38. package/package.json +1 -1
  39. package/dist/MiniTerrain-Blt0H1S0.js.map +0 -1
  40. package/dist/TerrainClouds-BuKvwnWw.js.map +0 -1
  41. package/dist/TerrainParameters-A3fcNJTR.js.map +0 -1
  42. package/dist/TerrainWater-Cil7waG3.js.map +0 -1
  43. package/dist/WaterMaterial-BUsAp0SS.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MiniTerrain-Bb5VYkZU.js","sources":["../../../src/engine/mini/MiniTerrainSettings.js","../../../src/engine/mini/MiniStudioStage.js","../../../src/engine/mini/MiniWaterCut.js","../../../src/engine/mini/MiniLightMap.js","../../../src/engine/mini/MiniTerrainController.js","../../../src/runtime/worlds/MiniTerrain.js"],"sourcesContent":["// ============================================================================\n// Mini Terrain — document model, normalization and derived configuration.\n//\n// Mini Terrain is a PRESENTATION of the finite (Tile/studio) world: one\n// footprint, one main seed, one high-resolution surface, a cut-away base and\n// water that stops at the footprint. It is not a terrain source: the relief is\n// still the procedural noise stack (plus Paint layers), on top of which a\n// deterministic composition recipe lays down the dominant silhouette.\n//\n// Everything here is pure (no THREE, no engine state) so it can be unit tested\n// and shared by the engine, the worker snapshot and the React panel.\n//\n// Units: every artistic proportion is expressed against the reference width W\n// (world units of the square footprint) and converted explicitly to the units\n// the existing systems use (heights, cloud altitudes, prop distances...). The\n// miniature look comes from framing and proportions, never from scaling the\n// scene down.\n// ============================================================================\n\nimport { MINI_VISUAL_PARAMS } from './MiniLook.js';\nimport { DEFAULT_PARAMS, PRESETS } from '../presets.js';\n\n// v2: relief/height split, props through the shared prop system. Older\n// documents get their derived params re-applied on load.\n// v3: diorama noise shaping (band-limited octaves, rounded relief) and the\n// props size control; v2 documents get the 'shape' scope re-applied.\nexport const MINI_TERRAIN_VERSION = 3;\n\n// Reference footprint width in engine units. Large enough that the existing\n// absolute thresholds (water foam/shallow distances, caustic depth fade, wave\n// spectrum) stay in their tuned range; small enough that one chunk at 256\n// segments gives ~4 units per quad.\nexport const MINI_REFERENCE_WIDTH = 1024;\nexport const MINI_WIDTH_LIMITS = Object.freeze({ min: 512, max: 2048 });\n\n// Recipes are authored in RELIEF units: 1 = W * MINI_RELIEF_RATIO world\n// units. The engine height scale is deliberately larger (MINI_HEIGHT_RATIO)\n// because the terrain palette reads h01 = height / heightScale as altitude\n// (snow, bare high rock): the cliffs of a diorama are a temperate coast, not\n// an alpine summit. Composition heights are converted relief -> h01 with\n// k = RELIEF / HEIGHT.\nexport const MINI_RELIEF_RATIO = 0.32;\nexport const MINI_HEIGHT_RATIO = 0.6;\n// Frozen formation sea level (relief units). The composition is authored\n// around it, so the live water-level control moves only the water.\nexport const MINI_FORMATION_SEA01 = 0.22;\n// Water level slider (0..1) -> sea level offset around the formation level,\n// in relief units: 0 = almost dry basins, 1 = mostly submerged lowlands.\nexport const MINI_WATER_SWING01 = 0.16;\n\n// Requested terrain resolution profiles (segments per side of the single\n// surface mesh). Effective render quality may degrade passes, never this.\nexport const MINI_QUALITY_PROFILES = Object.freeze({\n balanced: Object.freeze({ id: 'balanced', label: 'Balanced', segments: 128, waterMode: 'volumetric' }),\n high: Object.freeze({ id: 'high', label: 'High', segments: 256, waterMode: 'volumetric' }),\n capture: Object.freeze({ id: 'capture', label: 'Capture', segments: 512, waterMode: 'volumetric' }),\n});\nexport const MINI_QUALITY_IDS = Object.freeze(Object.keys(MINI_QUALITY_PROFILES));\n\n// Cut-away (section) palettes for the opaque terrain walls. Colours are sRGB\n// 0..1 triplets: topsoil just under the surface, then alternating strata,\n// then the deep base.\nexport const MINI_CUT_STYLES = Object.freeze({\n strata: Object.freeze({\n id: 'strata', label: 'Layered rock',\n topsoil: [0.30, 0.22, 0.15], bandA: [0.60, 0.52, 0.42], bandB: [0.48, 0.40, 0.32],\n deep: [0.30, 0.27, 0.24], sediment: [0.74, 0.66, 0.50], bands: 9,\n }),\n soil: Object.freeze({\n id: 'soil', label: 'Soil & sand',\n topsoil: [0.26, 0.19, 0.12], bandA: [0.66, 0.55, 0.40], bandB: [0.56, 0.45, 0.32],\n deep: [0.42, 0.34, 0.26], sediment: [0.80, 0.72, 0.55], bands: 6,\n }),\n dark: Object.freeze({\n id: 'dark', label: 'Dark earth',\n topsoil: [0.16, 0.12, 0.09], bandA: [0.30, 0.25, 0.21], bandB: [0.24, 0.20, 0.17],\n deep: [0.13, 0.11, 0.10], sediment: [0.42, 0.37, 0.30], bands: 7,\n }),\n});\nexport const MINI_CUT_STYLE_IDS = Object.freeze(Object.keys(MINI_CUT_STYLES));\n\n// Footprint outline. A circle is a rounded bevel whose radius is the\n// half-width, so terrain, walls, water, props, light map and export all share\n// the existing bevel path; only the socle and its ground shadow change shape.\n// Hexagons use six regular sides, with half-width as the circumradius.\nexport const MINI_SHAPES = Object.freeze(['square', 'circle', 'hexagon']);\n\n// Composition recipes. `shape` is the shader discriminant (uMiniShape).\n// Geometry is in normalized footprint coordinates (half-width = 1); heights in\n// h01 units relative to the formation sea level. `jitter` bounds the seeded\n// variation so every seed keeps the recipe's readable silhouette.\nexport const MINI_RECIPES = Object.freeze({\n // Fully procedural diorama: no imposed composition, the relief comes from\n // a regular procedural preset (+ noise stack), only scaled to the footprint.\n procedural: Object.freeze({\n id: 'procedural',\n label: 'Procédural',\n labelEn: 'Procedural',\n shape: 0,\n geometry: [0, 0, 0, 0],\n heights: [0, 0, 0, 0],\n detail: [0, 0, 0, 0],\n wobble: 0,\n jitter: { center: 0, angle: 0, radius: 0 },\n palette: 'coast',\n cutStyle: 'strata',\n water: 'tropical',\n vegetation: 0.7,\n clouds: 0.75,\n climate: null,\n }),\n cove: Object.freeze({\n id: 'cove',\n label: 'Crique aux falaises',\n labelEn: 'Cliff cove',\n shape: 1,\n // radius of the sheltered bowl, ring width, opening half-angle, cliff width\n geometry: [0.44, 0.42, 0.80, 0.035],\n // land height, sea-floor depth, beach height, secondary peak (relief units)\n heights: [0.50, 0.26, 0.035, 0.12],\n // detail on land / under water, terrace steps, terrace strength\n detail: [0.30, 0.08, 11, 0.5],\n wobble: 0.2,\n jitter: { center: 0.08, angle: 0.30, radius: 0.08 },\n palette: 'tropical',\n cutStyle: 'strata',\n water: 'tropical',\n vegetation: 0.75,\n clouds: 0.75,\n climate: { tempBias: 0.42, moistBias: 0.3 },\n }),\n islet: Object.freeze({\n id: 'islet',\n label: 'Îlot boisé',\n labelEn: 'Wooded islet',\n shape: 2,\n // island radius, shelf width, peak offset distance, shoreline width\n geometry: [0.64, 0.85, 0.34, 0.06],\n heights: [0.40, 0.24, 0.03, 0.16],\n detail: [0.30, 0.07, 0, 0],\n wobble: 0.22,\n jitter: { center: 0.12, angle: 3.14159, radius: 0.10 },\n palette: 'tropical',\n cutStyle: 'soil',\n water: 'tropical',\n vegetation: 0.9,\n clouds: 0.75,\n climate: { tempBias: 0.45, moistBias: 0.38 },\n }),\n lake: Object.freeze({\n id: 'lake',\n label: 'Lac de montagne',\n labelEn: 'Mountain lake',\n shape: 3,\n // lake radius, shore width, back-range spread, shoreline width\n geometry: [0.54, 0.30, 0.85, 0.07],\n heights: [0.30, 0.14, 0.03, 0.46],\n detail: [0.42, 0.06, 0, 0],\n wobble: 0.3,\n jitter: { center: 0.10, angle: 0.45, radius: 0.08 },\n palette: 'earth',\n cutStyle: 'dark',\n water: 'lake',\n vegetation: 0.6,\n clouds: 0.75,\n climate: { tempBias: 0.32, moistBias: 0.25 },\n }),\n});\nexport const MINI_RECIPE_IDS = Object.freeze(Object.keys(MINI_RECIPES));\nexport const MINI_COMPOSITION_IDS = Object.freeze(MINI_RECIPE_IDS.filter((id) => id !== 'procedural'));\nexport const DEFAULT_MINI_RECIPE = 'procedural';\nexport const DEFAULT_MINI_PRESET = 'archipelago';\n// Procedural base presets offered for a fully procedural diorama.\nexport const MINI_PROCEDURAL_PRESETS = Object.freeze(\n Object.entries(PRESETS).map(([id, preset]) => Object.freeze({ id, label: preset.label })),\n);\n// Height of a procedural diorama relative to the same preset on a 2048-unit\n// open board (proportionally, before the Relief slider). Below 1: a diorama\n// reads as a landscape model, not as a cluster of needles.\nexport const MINI_PROCEDURAL_RELIEF = 0.9;\n// Props size slider range (multiplier of the diorama's base prop scales).\nexport const MINI_PROP_SCALE_LIMITS = Object.freeze({ min: 0.25, max: 3 });\n// Base prop scales of a diorama at Props size 1.\nconst MINI_TREE_SCALE = 2.2;\nconst MINI_ROCK_SCALE = 2.5;\n\nconst clamp = (v, lo, hi) => (v < lo ? lo : v > hi ? hi : v);\nconst finite = (v, fallback) => (Number.isFinite(Number(v)) ? Number(v) : fallback);\n\n// ---------------------------------------------------------------------------\n// Seeds\n// ---------------------------------------------------------------------------\n\n// 32-bit avalanche hash (lowbias32). Pure integer maths → identical everywhere.\nfunction hash32(x) {\n let h = x >>> 0;\n h ^= h >>> 16;\n h = Math.imul(h, 0x7feb352d) >>> 0;\n h ^= h >>> 15;\n h = Math.imul(h, 0x846ca68b) >>> 0;\n h ^= h >>> 16;\n return h >>> 0;\n}\n\n/**\n * Independent sub-seeds derived from the single main seed. Changing the\n * vegetation density re-draws nothing in the relief, and vice versa.\n */\nexport function deriveMiniSeeds(seed) {\n const s = (Number(seed) >>> 0);\n return {\n relief: hash32(s ^ 0x52454c46), // 'RELF'\n props: hash32(s ^ 0x50524f50), // 'PROP'\n clouds: hash32(s ^ 0x434c4f55), // 'CLOU'\n noise: hash32(s ^ 0x4e4f4953), // 'NOIS'\n };\n}\n\n// Deterministic uniform stream in [0,1) from a 32-bit seed.\nfunction makeRandom(seed) {\n let a = seed >>> 0;\n return () => {\n a = (a + 0x6d2b79f5) >>> 0;\n let t = a;\n t = Math.imul(t ^ (t >>> 15), t | 1);\n t ^= t + Math.imul(t ^ (t >>> 7), t | 61);\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n };\n}\n\n// ---------------------------------------------------------------------------\n// Document\n// ---------------------------------------------------------------------------\n\nexport function createMiniTerrainState({ recipe = DEFAULT_MINI_RECIPE, seed = 1337, preset = null } = {}) {\n const r = MINI_RECIPES[recipe] ?? MINI_RECIPES[DEFAULT_MINI_RECIPE];\n return normalizeMiniTerrainState({\n version: MINI_TERRAIN_VERSION,\n recipe: r.id,\n preset,\n seed,\n width: MINI_REFERENCE_WIDTH,\n quality: 'high',\n relief: 1,\n waterLevel: 0.5,\n vegetation: r.vegetation,\n propScale: 1,\n clouds: r.clouds,\n cloudSpread: 100,\n cutStyle: r.cutStyle,\n shape: 'square',\n socle: true,\n backdrop: [0.91, 0.89, 0.86],\n camera: null,\n });\n}\n\n/**\n * Normalize/migrate a stored Mini section. Returns null for anything that is\n * not a Mini document so old projects (no section) keep their exact behaviour.\n */\nexport function normalizeMiniTerrainState(input) {\n if (!input || typeof input !== 'object') return null;\n const version = finite(input.version, 1);\n if (version > MINI_TERRAIN_VERSION) {\n // A newer document: keep the fields we understand, never discard it.\n }\n const recipe = MINI_RECIPES[input.recipe] ? input.recipe : DEFAULT_MINI_RECIPE;\n const r = MINI_RECIPES[recipe];\n const quality = MINI_QUALITY_PROFILES[input.quality] ? input.quality : 'high';\n const cutStyle = MINI_CUT_STYLES[input.cutStyle] ? input.cutStyle : r.cutStyle;\n const backdrop = Array.isArray(input.backdrop) && input.backdrop.length === 3\n ? input.backdrop.map((c) => clamp(finite(c, 0.9), 0, 1))\n : [0.91, 0.89, 0.86];\n const camera = normalizeMiniCamera(input.camera);\n return {\n version: MINI_TERRAIN_VERSION,\n recipe,\n // procedural base preset (null for composed recipes)\n preset: recipe === 'procedural'\n ? (PRESETS[input.preset] ? input.preset : DEFAULT_MINI_PRESET)\n : null,\n seed: finite(input.seed, 1337) >>> 0,\n width: clamp(Math.round(finite(input.width, MINI_REFERENCE_WIDTH)), MINI_WIDTH_LIMITS.min, MINI_WIDTH_LIMITS.max),\n quality,\n relief: clamp(finite(input.relief, 1), 0.4, 1.6),\n waterLevel: clamp(finite(input.waterLevel, 0.5), 0, 1),\n vegetation: clamp(finite(input.vegetation, r.vegetation), 0, 1),\n propScale: clamp(finite(input.propScale, 1), MINI_PROP_SCALE_LIMITS.min, MINI_PROP_SCALE_LIMITS.max),\n clouds: clamp(finite(input.clouds, r.clouds), 0, 1),\n // Older projects used a radius of width * 1.15 * 0.62.\n cloudSpread: clamp(finite(input.cloudSpread, 142.6), 10, 200),\n cutStyle,\n waterEdges: clamp(finite(input.waterEdges, 1), 0, 2),\n waterBevel: clamp(finite(input.waterBevel, 0), 0, 10),\n terrainBevel: clamp(finite(input.bevelSync === true ? input.waterBevel : input.terrainBevel, 0), 0, 10),\n bevelSync: input.bevelSync === true,\n bevelStyle: input.bevelStyle === 'rounded' ? 'rounded' : 'chamfer',\n shape: MINI_SHAPES.includes(input.shape) ? input.shape : 'square',\n socle: input.socle !== false,\n backdrop,\n camera,\n };\n}\n\nfunction normalizeMiniCamera(camera) {\n if (!camera || typeof camera !== 'object') return null;\n const views = Array.isArray(camera.views)\n ? camera.views.slice(0, 8).map(normalizeMiniView).filter(Boolean)\n : [];\n return { views };\n}\n\nexport function normalizeMiniView(view) {\n if (!view || typeof view !== 'object') return null;\n const theta = finite(view.theta, NaN);\n const phi = finite(view.phi, NaN);\n const radius = finite(view.radius, NaN);\n if (![theta, phi, radius].every(Number.isFinite)) return null;\n const target = Array.isArray(view.target) && view.target.length === 3\n ? view.target.map((v) => finite(v, 0))\n : [0, 0, 0];\n return {\n name: String(view.name ?? 'View').slice(0, 40),\n theta, phi, radius, target,\n };\n}\n\nexport function isMiniTerrainState(state) {\n return !!state && typeof state === 'object' && !!MINI_RECIPES[state.recipe];\n}\n\n// ---------------------------------------------------------------------------\n// Derived layout\n// ---------------------------------------------------------------------------\n\n/**\n * Engine-unit layout derived from the footprint width. Every absolute size\n * the Mini presentation needs comes from here.\n */\nexport function resolveMiniLayout(state) {\n const s = normalizeMiniTerrainState(state) ?? createMiniTerrainState();\n const W = s.width;\n let heightScale;\n let reliefHeight;\n let formationSea;\n if (s.recipe === 'procedural') {\n // a regular preset, scaled to the footprint (and slightly exaggerated)\n const pp = PRESETS[s.preset]?.params ?? {};\n const factor = (W / 2048) * MINI_PROCEDURAL_RELIEF * s.relief;\n heightScale = Math.round((pp.heightScale ?? DEFAULT_PARAMS.heightScale) * factor);\n reliefHeight = heightScale * 0.5;\n formationSea = Math.round((pp.seaLevel ?? DEFAULT_PARAMS.seaLevel) * factor * 100) / 100;\n } else {\n heightScale = Math.round(W * MINI_HEIGHT_RATIO);\n reliefHeight = W * MINI_RELIEF_RATIO;\n formationSea = Math.round(MINI_FORMATION_SEA01 * reliefHeight * 100) / 100;\n }\n const seaLevel = Math.max(\n 1,\n Math.round((formationSea + (s.waterLevel - 0.5) * 2 * MINI_WATER_SWING01 * reliefHeight) * 100) / 100,\n );\n const segments = MINI_QUALITY_PROFILES[s.quality].segments;\n // The section wall drops to this depth below y = 0; the socle sits under it.\n const baseDepth = Math.round(W * 0.07);\n const circle = s.shape === 'circle';\n return {\n width: W,\n half: W / 2,\n heightScale,\n reliefHeight,\n // relief units -> h01 of the engine height scale\n reliefToH01: reliefHeight / heightScale,\n formationSea,\n seaLevel,\n segments,\n baseDepth,\n shape: s.shape,\n hexagon: s.shape === 'hexagon',\n waterBevel: circle ? W / 2 : s.shape === 'hexagon' ? 0 : W * s.waterBevel / 100,\n terrainBevel: circle ? W / 2 : s.shape === 'hexagon' ? 0 : W * s.terrainBevel / 100,\n rounded: circle || (s.shape === 'square' && s.bevelStyle === 'rounded'),\n socleHeight: Math.round(W * 0.045),\n socleMargin: Math.round(W * 0.018),\n quadSize: W / segments,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Composition (shader uniforms)\n// ---------------------------------------------------------------------------\n\n/**\n * Seeded composition parameters for the analytic macro silhouette. The same\n * values feed the GLSL (uMini* uniforms) and its CPU twin, so rendering,\n * picking, shoreline and prop placement share one terrain.\n */\nexport function resolveMiniComposition(state) {\n const s = normalizeMiniTerrainState(state) ?? createMiniTerrainState();\n const r = MINI_RECIPES[s.recipe];\n const rand = makeRandom(deriveMiniSeeds(s.seed).relief);\n // Front direction: the opening faces the initial three-quarter camera\n // (azimuth ≈ 20° around +Z), with a bounded seeded swing.\n const baseAngle = 0.35;\n const angle = baseAngle + (rand() * 2 - 1) * r.jitter.angle;\n const dirX = Math.sin(angle);\n const dirZ = Math.cos(angle);\n const cx = (rand() * 2 - 1) * r.jitter.center;\n const cz = (rand() * 2 - 1) * r.jitter.center;\n const radiusScale = 1 + (rand() * 2 - 1) * r.jitter.radius;\n const phases = [rand() * Math.PI * 2, rand() * Math.PI * 2, rand() * Math.PI * 2];\n const relief = s.relief;\n const k = resolveMiniLayout(s).reliefToH01;\n\n const [g0, g1, g2, g3] = r.geometry;\n const [hLand, hDepth, hBeach, hPeak] = r.heights;\n const [dLand, dSea, steps, terraceStrength] = r.detail;\n\n return {\n shape: r.shape,\n // (front dir x, front dir z, center x, center z) — centre in [-1,1] units,\n // pushed slightly AWAY from the front so the focal area stays framed.\n frame: [dirX, dirZ, cx - dirX * 0.12, cz - dirZ * 0.12],\n geometry: [g0 * radiusScale, g1, g2, g3],\n heights: [hLand * relief * k, hDepth * Math.sqrt(relief) * k, hBeach * k, hPeak * relief * k],\n wobble: [phases[0], phases[1], phases[2], r.wobble],\n detail: [dLand * relief * k, dSea * k, steps > 0 ? steps / k : 0, terraceStrength],\n cameraAzimuth: angle + 0.42,\n };\n}\n\n/** Uniform values for the composition (shape 0 = disabled). */\nexport function miniCompositionUniformValues(state) {\n if (!isMiniTerrainState(state)) {\n return { shape: 0, frame: [0, 1, 0, 0], geometry: [0, 0, 0, 0], heights: [0, 0, 0, 0], wobble: [0, 0, 0, 0], detail: [0, 0, 0, 0] };\n }\n const c = resolveMiniComposition(state);\n return { shape: c.shape, frame: c.frame, geometry: c.geometry, heights: c.heights, wobble: c.wobble, detail: c.detail };\n}\n\n// ---------------------------------------------------------------------------\n// Params patch\n// ---------------------------------------------------------------------------\n\n// Water look shared by all recipes: clear, coloured, readable depth ramp,\n// short moderate waves and thin foam. Backend (realistic/volumetric/cinematic)\n// is chosen by the quality profile, never by the palette.\nconst MINI_WATER_LOOKS = Object.freeze({\n tropical: {\n waterOpacity: 0.5,\n waterRoughness: 0.22,\n waterSpecularStrength: 0.8,\n waterDepthColorStrength: 0.9,\n waterDepthOpacityStrength: 0.75,\n waterMaxVisibleDepth: 70,\n waterShallowDistance: 6,\n waterDeepDistance: 38,\n waterAbsorptionStrength: 0.7,\n waterNaturalColor: 0.85,\n waterBiomeColorStrength: 0.2,\n waterWaveScale: 1.6,\n waterWaveStrength: 0.55,\n waterSmallWaveStrength: 0.45,\n waterLargeWaveStrength: 0.4,\n waterNormalIntensity: 0.7,\n waterFoamStrength: 0.5,\n waterFoamWidth: 2.2,\n waterFresnelStrength: 1.0,\n waterRefractionStrength: 0.5,\n waterUnderwaterCaustics: 0.32,\n },\n lake: {\n waterOpacity: 0.62,\n waterRoughness: 0.32,\n waterSpecularStrength: 0.7,\n waterDepthColorStrength: 0.95,\n waterDepthOpacityStrength: 0.85,\n waterMaxVisibleDepth: 60,\n waterShallowDistance: 6,\n waterDeepDistance: 34,\n waterAbsorptionStrength: 0.85,\n waterNaturalColor: 0.75,\n waterBiomeColorStrength: 0.3,\n waterWaveScale: 1.8,\n waterWaveStrength: 0.4,\n waterSmallWaveStrength: 0.35,\n waterLargeWaveStrength: 0.3,\n waterNormalIntensity: 0.6,\n waterFoamStrength: 0.35,\n waterFoamWidth: 1.8,\n waterFresnelStrength: 1.0,\n waterRefractionStrength: 0.45,\n waterUnderwaterCaustics: 0.25,\n },\n});\n\n/**\n * Octave count that keeps the noise band-limited to the Mini surface mesh.\n * The legacy recipe's finest detail is its ridged layer (1.7× the base\n * frequency, × lacunarity per octave); octaves whose lattice cells are\n * narrower than ~3 surface quads cannot be represented by the vertices and\n * alias into needle spikes and wrinkled shading. Lower noise scales leave\n * room for more octaves.\n */\nexport function miniOctaveCap({ noiseScale, lacunarity }, segments) {\n const baseCells = Math.max(0.5, Number(noiseScale) || DEFAULT_PARAMS.noiseScale) * 0.1 * 1.7;\n const lac = Math.max(1.2, Number(lacunarity) || DEFAULT_PARAMS.lacunarity);\n const maxCells = Math.max(1, segments) / 3;\n return clamp(Math.floor(Math.log(maxCells / baseCells) / Math.log(lac)) + 1, 3, 8);\n}\n\n/**\n * Terrain shape of a diorama. A composed recipe tunes the detail noise; a\n * procedural diorama takes the complete preset (reset to defaults first, like\n * applyPreset), softened into a landscape model: rounded peaks, gentler\n * ridges, smoother falloff of detail and octaves band-limited to the mesh.\n */\nfunction miniShapeParams(s, segments) {\n const r = MINI_RECIPES[s.recipe];\n let shape;\n if (s.recipe === 'procedural') {\n shape = {};\n for (const key of [\n 'noiseScale', 'noiseStrength', 'terrainSmoothing', 'octaves', 'persistence', 'lacunarity',\n 'ridge', 'warp', 'falloff', 'moistScale', 'moistBias', 'biomeScale', 'tempBias', 'snowLine',\n 'normalStrength', 'aoStrength', 'aoRidge', 'rockSlopeLo', 'rockSlopeHi', 'snowSlopeMin', 'snowSlopeMax',\n ]) shape[key] = DEFAULT_PARAMS[key];\n const pp = { ...(PRESETS[s.preset]?.params ?? {}) };\n delete pp.heightScale;\n delete pp.seaLevel;\n Object.assign(shape, pp, { preset: s.preset, edgeFalloffMode: 'island' });\n shape.ridge = Math.round(shape.ridge * 0.62 * 1000) / 1000;\n shape.terrainSmoothing = Math.max(shape.terrainSmoothing, 0.6);\n shape.persistence = Math.min(shape.persistence, 0.46);\n } else {\n shape = {\n // detail noise: few large features across the footprint, moderate ridges\n noiseScale: 26,\n noiseStrength: 1.0,\n persistence: 0.46,\n lacunarity: 2.05,\n ridge: 0.4,\n warp: 0.7,\n terrainSmoothing: 0.3,\n falloff: 0,\n edgeFalloffMode: 'island',\n tempBias: r.climate.tempBias,\n moistBias: r.climate.moistBias,\n biomeScale: 0.6,\n snowLine: s.recipe === 'lake' ? 0.82 : 0.95,\n };\n }\n shape.octaves = Math.min(shape.octaves ?? 8, miniOctaveCap(shape, segments));\n return shape;\n}\n\n/**\n * Engine params that realise a Mini document. Applied when a Mini scene is\n * created, regenerated or its recipe changes. `scope` limits the patch:\n * 'all' — new scene / recipe change (relief, water, clouds, props, look)\n * 'water' — water level only (never touches the relief)\n * 'clouds' — cloud amount only\n * 'props' — vegetation only\n * 'propScale' — props size only\n * 'quality' — terrain resolution profile + water backend\n * 'structure' — layout defaults (load enforces the footprint, fills missing params)\n * 'shape' — terrain noise shaping (v2 → v3 migration)\n */\nexport function miniParamsPatch(state, scope = 'all') {\n const s = normalizeMiniTerrainState(state) ?? createMiniTerrainState();\n const r = MINI_RECIPES[s.recipe];\n const L = resolveMiniLayout(s);\n const seeds = deriveMiniSeeds(s.seed);\n const profile = MINI_QUALITY_PROFILES[s.quality];\n const W = L.width;\n\n const water = {\n seaLevel: L.seaLevel,\n waterEnabled: true,\n };\n const quality = {\n waterMode: profile.waterMode,\n waterQualityPreset: 'custom',\n };\n const landTop = s.recipe === 'procedural'\n ? L.heightScale * 0.75\n : L.formationSea + (r.heights[0] + r.heights[3]) * s.relief * L.reliefHeight;\n const clouds = {\n cloudsEnabled: s.clouds > 0.04,\n cloudCoverage: Math.round((0.18 + s.clouds * 0.42) * 1000) / 1000,\n };\n // Vegetation and rocks are regular props (Props panel, asset library),\n // densified for a diorama read: a wooded slope needs far more and larger\n // trees than an open-world meadow seen at walking height.\n const props = {\n propsEnabled: s.vegetation > 0.02,\n propsDensity: Math.round((0.6 + s.vegetation * 0.4) * 1000) / 1000,\n propsTreeDensity: Math.round((0.4 + s.vegetation * 1.6) * 1000) / 1000,\n propsGrassDensity: Math.round((0.3 + s.vegetation * 0.7) * 1000) / 1000,\n propsForest: Math.round(Math.min(1, s.vegetation * 1.1) * 1000) / 1000,\n };\n const propScale = {\n propsTreeScale: Math.round(MINI_TREE_SCALE * s.propScale * 1000) / 1000,\n propsRockScale: Math.round(MINI_ROCK_SCALE * s.propScale * 1000) / 1000,\n propsGrass: Math.round(s.propScale * 1000) / 1000,\n };\n // Defaults derived from the document. Load enforces the footprint but\n // preserves saved height and water edits from the shared settings panels.\n const structure = {\n chunkCount: 1,\n chunkSize: W,\n heightScale: L.heightScale,\n terrainFormationSeaLevel: L.formationSea,\n ...quality,\n };\n if (scope === 'water') return water;\n if (scope === 'clouds') return clouds;\n if (scope === 'props') return props;\n if (scope === 'propScale') return propScale;\n if (scope === 'quality') return quality;\n if (scope === 'structure') return structure;\n const shape = miniShapeParams(s, L.segments);\n if (scope === 'shape') return shape;\n\n return {\n seed: seeds.noise,\n propsSeed: seeds.props,\n ...structure,\n ...water,\n ...(MINI_WATER_LOOKS[r.water] ?? MINI_WATER_LOOKS.tropical),\n waterAnim: true,\n ...shape,\n // Studio presentation; sky and time of day remain editable after creation.\n ...MINI_VISUAL_PARAMS,\n skyboxEnabled: true,\n skyboxDayNightCycle: true,\n sunAzimuth: 128,\n sunElevation: 46,\n fogDensity: 0.02,\n aoStrength: 0.8,\n normalStrength: 1.15,\n // clouds sized from W: a few small formations above the composition\n ...clouds,\n cloudAltitude: Math.round(landTop + W * 0.12),\n cloudThickness: Math.round(W * 0.11),\n cloudScale: 3.4,\n cloudDetailScale: 9,\n cloudSoftness: 0.22,\n cloudMaxDistance: 2.5,\n cloudWindSpeed: 0.35,\n cloudEvolveSpeed: 0.6,\n cloudShadowsEnabled: true,\n cloudShadowOpacity: 0.3,\n // vegetation: distances from W so the whole diorama stays populated\n ...props,\n ...propScale,\n propsCullDistance: Math.round(W * 3.2),\n propsLodDistance: Math.round(W * 1.4),\n };\n}\n\n/**\n * Cloud slab placement centred on the diorama. Spread is the cloud diameter\n * as a percentage of terrain width; 100% fits inside the circular footprint.\n * Coverage extent stays fixed so narrowing clouds does not change cull distance.\n */\nexport function resolveMiniCloudLayout(state) {\n const s = normalizeMiniTerrainState(state) ?? createMiniTerrainState();\n const L = resolveMiniLayout(s);\n return {\n extent: L.width * 1.15,\n radius: L.width * s.cloudSpread / 200,\n center: { x: 0, z: 0 },\n };\n}\n\n/** Terrain LOD segments for the single Mini surface (all four LOD slots). */\nexport function miniLodSegments(state) {\n const { segments } = resolveMiniLayout(state);\n return [segments, segments, segments, segments];\n}\n\n// ---------------------------------------------------------------------------\n// Camera\n// ---------------------------------------------------------------------------\n\n/**\n * Initial three-quarter framing: the whole diorama in view, low-distortion\n * perspective, pivot at the composition centre around sea level.\n */\nexport function resolveMiniFraming(state, { fov = 45, aspect = 16 / 9 } = {}) {\n const s = normalizeMiniTerrainState(state) ?? createMiniTerrainState();\n const L = resolveMiniLayout(s);\n const c = resolveMiniComposition(s);\n const phi = 58 * Math.PI / 180; // from +Y → ~32° above horizon\n // Fit the footprint diagonal (+ socle) in the narrower FOV axis.\n const vFov = fov * Math.PI / 180;\n const hFov = 2 * Math.atan(Math.tan(vFov / 2) * Math.max(0.5, aspect));\n const fitFov = Math.min(vFov, hFov);\n const extent = L.width * (s.shape === 'square' ? 0.76 : 0.6);\n const radius = Math.round((extent / Math.tan(fitFov / 2)) * 100) / 100;\n return {\n theta: c.cameraAzimuth,\n phi,\n radius,\n target: [0, L.seaLevel * 0.5, 0],\n minRadius: Math.round(L.width * 0.22),\n maxRadius: Math.round(L.width * 3.2),\n minPhi: 6 * Math.PI / 180,\n maxPhi: 86 * Math.PI / 180,\n panLimit: L.width * 0.45,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Presentation summary (diagnostics / UI)\n// ---------------------------------------------------------------------------\n\nexport function describeMiniTerrain(state) {\n const s = normalizeMiniTerrainState(state);\n if (!s) return null;\n const L = resolveMiniLayout(s);\n const r = MINI_RECIPES[s.recipe];\n return {\n recipe: s.recipe,\n label: r.label,\n width: L.width,\n segments: L.segments,\n triangles: 2 * L.segments * L.segments,\n quality: s.quality,\n };\n}\n","import * as THREE from 'three';\nimport { MINI_LIGHTING_GLSL, miniLightingUniforms } from './MiniLighting.js';\n\n// ============================================================================\n// MiniStudioStage — presentation objects around a Mini Terrain diorama:\n//\n// * backdrop : a large inside-out sphere with a soft vertical gradient (the\n// neutral studio background; never part of an export);\n// * shadow : a ground plane under the socle that only darkens — an\n// analytic soft drop shadow offset along the sun direction plus\n// a tight contact occlusion. No shadow map, no extra pass;\n// * socle : a simple, slightly chamfered pedestal under the section base.\n//\n// All three write display colour with the same manual gamma as the terrain so\n// they stay consistent on the canvas and in every intermediate render target.\n// They are owned here and disposed together; the engine hides them during\n// exports/heightmap captures through its plinth-visibility switch.\n// ============================================================================\n\nconst BACKDROP_VERTEX = /* glsl */ `\nvarying vec3 vDir;\nvoid main() {\n vDir = normalize(position);\n vec4 wp = modelMatrix * vec4(position, 1.0);\n gl_Position = projectionMatrix * viewMatrix * wp;\n}\n`;\n\nconst BACKDROP_FRAGMENT = /* glsl */ `\nuniform vec3 uColor; // display (sRGB) colour at the horizon\nvarying vec3 vDir;\nvoid main() {\n float y = normalize(vDir).y;\n vec3 top = uColor * 1.035;\n vec3 low = uColor * 0.90;\n vec3 col = mix(low, uColor, smoothstep(-0.55, 0.0, y));\n col = mix(col, top, smoothstep(0.05, 0.85, y));\n gl_FragColor = vec4(col, 1.0);\n}\n`;\n\nconst SHADOW_VERTEX = /* glsl */ `\nvarying vec3 vWorldPos;\nvoid main() {\n vec4 wp = modelMatrix * vec4(position, 1.0);\n vWorldPos = wp.xyz;\n gl_Position = projectionMatrix * viewMatrix * wp;\n}\n`;\n\nconst SHADOW_FRAGMENT = /* glsl */ `\nuniform vec3 uSunDir;\nuniform float uHalf; // socle half-width\nuniform float uLift; // height of the diorama mass above the ground\nuniform float uStrength;\nuniform vec3 uShadowColor; // display colour of full shadow\nuniform float uHexagon;\nuniform float uCircle; // 1 = round footprint\nvarying vec3 vWorldPos;\n\nfloat sdBox(vec2 p, vec2 b) {\n if (uHexagon > 0.5) {\n vec2 q = abs(p);\n return max(q.x, dot(q, vec2(0.5, 0.866025404))) - b.x * 0.866025404;\n }\n if (uCircle > 0.5) return length(p) - b.x;\n vec2 d = abs(p) - b;\n return length(max(d, 0.0)) + min(max(d.x, d.y), 0.0);\n}\n\nvoid main() {\n vec3 sun = normalize(uSunDir);\n float elev = max(sun.y, 0.18);\n vec2 offset = -sun.xz / elev * uLift * 0.45;\n float soft = uHalf * 0.55 + uLift * 0.25;\n float drop = 1.0 - smoothstep(-soft * 0.35, soft, sdBox(vWorldPos.xz - offset, vec2(uHalf * 0.92)));\n float contact = 1.0 - smoothstep(0.0, uHalf * 0.12, sdBox(vWorldPos.xz, vec2(uHalf)));\n float shade = clamp(drop * 0.55 + contact * 0.45, 0.0, 1.0) * uStrength;\n gl_FragColor = vec4(uShadowColor * shade, shade);\n}\n`;\n\nconst SOCLE_VERTEX = /* glsl */ `\nvarying vec3 vNormalW;\nvarying vec3 vWorldPos;\nvoid main() {\n vec4 wp = modelMatrix * vec4(position, 1.0);\n vWorldPos = wp.xyz;\n vNormalW = normalize(mat3(modelMatrix) * normal);\n gl_Position = projectionMatrix * viewMatrix * wp;\n}\n`;\n\nconst SOCLE_FRAGMENT = /* glsl */ `\n${MINI_LIGHTING_GLSL}\nuniform vec3 uSunDir;\nuniform vec3 uColor; // linear albedo\nuniform float uTopY;\nuniform float uBottomY;\nvarying vec3 vNormalW;\nvarying vec3 vWorldPos;\nvoid main() {\n vec3 n = normalize(vNormalW);\n float ndl = max(dot(n, normalize(uSunDir)), 0.0);\n float t = clamp((vWorldPos.y - uBottomY) / max(uTopY - uBottomY, 1.0), 0.0, 1.0);\n vec3 albedo = uColor * mix(0.78, 1.0, smoothstep(0.0, 0.35, t));\n // thin darker groove just under the section base\n albedo *= 1.0 - 0.18 * smoothstep(0.86, 1.0, t);\n vec3 lit = albedo * miniLighting(ndl, 1.0, 1.0);\n gl_FragColor = vec4(pow(max(lit, vec3(0.0)), vec3(1.0 / 2.2)), 1.0);\n}\n`;\n\nconst srgbToLinear = (c) => (c <= 0.04045 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4);\n\nfunction chamferedBoxGeometry(width, height, depth, chamfer) {\n // A box whose top edges are bevelled: built from an extruded rounded rect\n // would cost more triangles than this deserves; a two-tier box reads the same.\n const c = Math.min(chamfer, height * 0.45, width * 0.1);\n const lower = new THREE.BoxGeometry(width, height - c, depth);\n lower.translate(0, -c / 2, 0);\n const upper = new THREE.BoxGeometry(width - c * 2, c, depth - c * 2);\n upper.translate(0, height / 2 - c / 2, 0);\n const merged = mergeGeometries([lower, upper]);\n lower.dispose();\n upper.dispose();\n return merged;\n}\n\n// Round pedestal: the same two-tier read as the box, as two cylinders.\nfunction chamferedDiscGeometry(radius, height, chamfer, segments = 128) {\n const c = Math.min(chamfer, height * 0.45, radius * 0.2);\n const lower = new THREE.CylinderGeometry(radius, radius, height - c, segments, 1);\n lower.translate(0, -c / 2, 0);\n const upper = new THREE.CylinderGeometry(radius - c, radius - c, c, segments, 1);\n upper.translate(0, height / 2 - c / 2, 0);\n const merged = mergeGeometries([lower, upper]);\n lower.dispose();\n upper.dispose();\n return merged;\n}\n\nfunction mergeGeometries(geometries) {\n const positions = [];\n const normals = [];\n const indices = [];\n let offset = 0;\n for (const geo of geometries) {\n const pos = geo.getAttribute('position');\n const nor = geo.getAttribute('normal');\n for (let i = 0; i < pos.count; i++) {\n positions.push(pos.getX(i), pos.getY(i), pos.getZ(i));\n normals.push(nor.getX(i), nor.getY(i), nor.getZ(i));\n }\n const idx = geo.index;\n for (let i = 0; i < idx.count; i++) indices.push(idx.getX(i) + offset);\n offset += pos.count;\n }\n const out = new THREE.BufferGeometry();\n out.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));\n out.setAttribute('normal', new THREE.Float32BufferAttribute(normals, 3));\n out.setIndex(indices);\n out.computeBoundingSphere();\n return out;\n}\n\nexport class MiniStudioStage {\n constructor(sharedUniforms) {\n this.group = new THREE.Group();\n this.group.name = 'mini-studio-stage';\n\n this.backdropMaterial = new THREE.ShaderMaterial({\n name: 'MiniBackdrop',\n uniforms: { uColor: { value: new THREE.Vector3(0.91, 0.89, 0.86) } },\n vertexShader: BACKDROP_VERTEX,\n fragmentShader: BACKDROP_FRAGMENT,\n side: THREE.BackSide,\n depthWrite: false,\n });\n this.backdrop = new THREE.Mesh(new THREE.SphereGeometry(1, 48, 24), this.backdropMaterial);\n this.backdrop.name = 'mini-backdrop';\n this.backdrop.frustumCulled = false;\n this.backdrop.renderOrder = -100;\n this.backdrop.scale.setScalar(24000);\n\n this.shadowMaterial = new THREE.ShaderMaterial({\n name: 'MiniShadowCatcher',\n uniforms: {\n uSunDir: sharedUniforms.uSunDir,\n uHalf: { value: 512 },\n uLift: { value: 300 },\n uStrength: { value: 0.42 },\n uShadowColor: { value: new THREE.Vector3(0.36, 0.33, 0.30) },\n uCircle: { value: 0 },\n uHexagon: { value: 0 },\n },\n vertexShader: SHADOW_VERTEX,\n fragmentShader: SHADOW_FRAGMENT,\n transparent: true,\n premultipliedAlpha: true,\n depthWrite: false,\n });\n const plane = new THREE.PlaneGeometry(1, 1);\n plane.rotateX(-Math.PI / 2);\n this.shadow = new THREE.Mesh(plane, this.shadowMaterial);\n this.shadow.name = 'mini-shadow-catcher';\n this.shadow.renderOrder = -50;\n\n this.socleMaterial = new THREE.ShaderMaterial({\n name: 'MiniSocle',\n uniforms: {\n ...miniLightingUniforms(sharedUniforms),\n uSunDir: sharedUniforms.uSunDir,\n uColor: { value: new THREE.Vector3(0.6, 0.52, 0.4) },\n uTopY: { value: -70 },\n uBottomY: { value: -115 },\n },\n vertexShader: SOCLE_VERTEX,\n fragmentShader: SOCLE_FRAGMENT,\n });\n this.socle = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), this.socleMaterial);\n this.socle.name = 'mini-socle';\n\n // Soft studio fill for the lit props (trees, rocks): sky above, warm\n // bounce below. The terrain and water shaders do their own lighting.\n // (physically based light units: Lambert divides by pi, hence the value)\n this.fill = new THREE.HemisphereLight(0xdbe7f5, 0x8a7d66, 3.2);\n this.fill.name = 'mini-studio-fill';\n\n this.group.add(this.backdrop, this.shadow, this.socle, this.fill);\n this._layoutKey = '';\n this.group.visible = false;\n }\n\n /**\n * @param {object} layout { half, baseY, socleHeight, socleMargin, maxHeight, socle, circle, hexagon }\n */\n setLayout({ half, baseY, socleHeight, socleMargin, maxHeight, socle = true, circle = false, hexagon = false }) {\n const key = `${half}:${baseY}:${socleHeight}:${socleMargin}:${socle}:${circle}:${hexagon}`;\n this.shadowMaterial.uniforms.uCircle.value = circle ? 1 : 0;\n this.shadowMaterial.uniforms.uHexagon.value = hexagon ? 1 : 0;\n const bottom = socle ? baseY - socleHeight : baseY;\n this.shadow.position.set(0, bottom - 0.5, 0);\n this.shadow.scale.set(half * 9, 1, half * 9);\n this.shadowMaterial.uniforms.uHalf.value = half + (socle ? socleMargin : 0);\n this.shadowMaterial.uniforms.uLift.value = Math.max(1, maxHeight - bottom);\n this.socle.visible = !!socle;\n this.socleMaterial.uniforms.uTopY.value = baseY;\n this.socleMaterial.uniforms.uBottomY.value = bottom;\n if (key === this._layoutKey) return;\n this._layoutKey = key;\n if (socle) {\n const width = (half + socleMargin) * 2;\n this.socle.geometry.dispose();\n this.socle.geometry = circle || hexagon\n ? chamferedDiscGeometry(width / 2, socleHeight, socleMargin * 0.9, hexagon ? 6 : 128)\n : chamferedBoxGeometry(width, socleHeight, width, socleMargin * 0.9);\n this.socle.position.set(0, baseY - socleHeight / 2, 0);\n }\n }\n\n /** Backdrop + shadow tint from a display-space [r,g,b] colour. */\n setBackdrop(rgb) {\n const [r, g, b] = rgb;\n this.backdropMaterial.uniforms.uColor.value.set(r, g, b);\n this.shadowMaterial.uniforms.uShadowColor.value.set(r * 0.38, g * 0.36, b * 0.35);\n }\n\n /** Socle albedo from a display-space colour. */\n setSocleColor(rgb) {\n const lin = rgb.map(srgbToLinear);\n this.socleMaterial.uniforms.uColor.value.set(lin[0], lin[1], lin[2]);\n }\n\n setLighting(state, skyActive) {\n this.backdrop.visible = !skyActive;\n if (!state) return;\n this.fill.color.setRGB(...state.ambientTopColor);\n this.fill.groundColor.setRGB(...state.groundBounceColor);\n this.shadowMaterial.uniforms.uStrength.value = Math.min(0.6, Math.max(...state.directLightColor, 0) * 0.6);\n }\n\n setVisible(visible) {\n this.group.visible = !!visible;\n }\n\n get materials() {\n return [this.backdropMaterial, this.shadowMaterial, this.socleMaterial];\n }\n\n dispose() {\n this.group.removeFromParent();\n this.backdrop.geometry.dispose();\n this.shadow.geometry.dispose();\n this.socle.geometry.dispose();\n for (const m of this.materials) m.dispose();\n }\n}\n","import * as THREE from 'three';\nimport { createMiniWaterCutMaterial } from './MiniWaterMaterial.js';\nimport { miniFootprint } from './MiniBevel.js';\n\n// ============================================================================\n// MiniWaterCut — the four vertical faces that make the diorama's water read as\n// a cleanly cut volume.\n//\n// Geometry: four quads just inside the footprint (inset by `inset`), from the\n// section base up to the water level, facing outward (FrontSide). Below the\n// local terrain edge the opaque section wall is in front of them (the wall is\n// the terrain's own perimeter skirt at exactly ±half), so they only show where\n// the terrain edge sits under the water line — the vertical domain starts at\n// the visible sediment and ends at the water level. Dry edges stay opaque.\n//\n// Shading (MiniWaterMaterial, single pass, same colour model as the surface):\n// * the optical path L is the distance from the entry point on the face to\n// the first of: the volume's exit (top / far side / base) or the terrain\n// behind (scene depth). Side views therefore never reuse the top view's\n// vertical-depth opacity.\n// * with the Volumetric/Cinematic water-free scene capture bound, the face\n// composes the background itself (bg·T + inscatter·(1−T)) and is written\n// opaque — no double alpha blending with the surface behind it;\n// * without a capture (Realistic/Legacy), it outputs premultiplied\n// inscatter with alpha 1−T over the already-drawn terrain, using the box\n// exit as the path (the section base caps it).\n//\n// Pass order (documented contract):\n// opaque terrain/props/backdrop → [capture: scene colour+depth without any\n// water] → water surface (transparent, renderOrder 10) → cut faces\n// (transparent, renderOrder 11). From any outside camera the convex volume is\n// entered exactly once, so the cut face is always the nearest water layer of\n// its pixel; drawing it after the surface is therefore correct by\n// construction, not by a global renderOrder tweak. depthTest on, depthWrite\n// off; the opaque section wall depth-occludes the faces below the terrain.\n// ============================================================================\n\nexport function buildMiniWaterCutGeometry(half, bottom, top, inset = 0.5, bevel = 0, rounded = false, hexagon = false) {\n const h = Math.max(1, half - inset);\n const y0 = bottom;\n const y1 = Math.max(top, bottom + 0.01);\n // Each face: 4 vertices, CCW when seen from outside (outward normal).\n const ring = miniFootprint(h, bevel, rounded, hexagon);\n const faces = ring.map(([x, z], i) => {\n const [nx, nz] = ring[(i + 1) % ring.length];\n const normal = new THREE.Vector3(z - nz, 0, nx - x).normalize().toArray();\n return { n: normal, v: [[x, y0, z], [nx, y0, nz], [nx, y1, nz], [x, y1, z]] };\n });\n const positions = [];\n const normals = [];\n const indices = [];\n faces.forEach((face, i) => {\n for (const v of face.v) {\n positions.push(...v);\n normals.push(...face.n);\n }\n const o = i * 4;\n indices.push(o, o + 1, o + 2, o, o + 2, o + 3);\n });\n const geo = new THREE.BufferGeometry();\n geo.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));\n geo.setAttribute('normal', new THREE.Float32BufferAttribute(normals, 3));\n geo.setIndex(indices);\n geo.computeBoundingSphere();\n return geo;\n}\n\nexport class MiniWaterCut {\n constructor(sharedUniforms) {\n this.material = createMiniWaterCutMaterial(sharedUniforms);\n this.mesh = new THREE.Mesh(buildMiniWaterCutGeometry(512, -70, 70), this.material);\n this.mesh.name = 'mini-water-cut';\n this.mesh.renderOrder = 11; // after the water surface (renderOrder 10)\n this.mesh.frustumCulled = true;\n this.mesh.visible = false;\n this._key = '';\n }\n\n /** Update the box (half-width, section base, water level). */\n setBounds({ half, bottom, top, inset, bevel = 0, rounded = false, hexagon = false }) {\n // a round footprint's bevel is the whole half-width: keep it on the inset box\n bevel = Math.min(bevel, half - inset);\n const key = `${half}:${bottom}:${top}:${inset}:${bevel}:${rounded}:${hexagon}`;\n this.material.uniforms.uCutHalf.value = half - inset;\n this.material.uniforms.uCutBottom.value = bottom;\n this.material.uniforms.uMiniWaterBevel.value = bevel;\n if (key === this._key) return;\n this._key = key;\n this.mesh.geometry.dispose();\n this.mesh.geometry = buildMiniWaterCutGeometry(half, bottom, top, inset, bevel, rounded, hexagon);\n }\n\n dispose() {\n this.mesh.removeFromParent();\n this.mesh.geometry.dispose();\n this.material.dispose();\n }\n}\n","import * as THREE from 'three';\nimport { MINI_BEVEL_GLSL } from './MiniBevel.js';\n\n// ============================================================================\n// MiniLightMap — soft sun shadows and ambient occlusion for the diorama.\n//\n// The engine has no shadow maps and the terrain is displaced in its vertex\n// shader, so instead of touching every terrain program (and its 16-sampler\n// budget) the Mini presentation:\n// 1. BAKES a small light map over the footprint on the GPU, from a grid of\n// the terrain's own VERTEX heights (TerrainHeightBaker.renderHeightGrid:\n// the compiled height program, one sample per surface vertex). The\n// terrain displaces its vertices analytically, so this grid is exact and\n// current in the very frame of an edit; the slow progressive full bake\n// (fragment normals only) is never waited for:\n// R = sun visibility (height-field ray march toward the sun, soft\n// penumbra growing with distance to the occluder),\n// G = ambient occlusion (8-direction horizon estimate),\n// B = terrain height (world units, filtered: smooth water depth);\n// 2. APPLIES it with a decal mesh on the same vertex grid, drawn\n// right after the terrain with multiplicative blending (dst × factor), so\n// it darkens terrain only (props and water are separate objects).\n// The water shader samples the same map for cliff shadows on the surface.\n//\n// Re-baked only when the terrain field, the sun direction or the footprint\n// change (at most once per frame while a slider is dragged).\n// Static loop bounds, masks instead of break — ANGLE/FXC friendly.\n// ============================================================================\n\nconst BAKE_VERTEX = /* glsl */ `\nvarying vec2 vUv;\nvoid main() {\n vUv = uv;\n gl_Position = vec4(position.xy, 0.0, 1.0);\n}\n`;\n\n// Texel i of the (segments + 1)^2 grid holds the height of vertex i, at\n// x = -half + i * width / segments: sampling a vertex position hits a texel\n// centre exactly, in between it interpolates like the terrain triangles.\nconst HEIGHT_FETCH = /* glsl */ `\nuniform sampler2D uMiniHeightGrid;\nuniform float uMiniGridSegments;\nuniform float uHalf;\nuniform float uMiniTerrainBevel;\nuniform float uMiniBevelRounded;\nuniform float uHeightScale;\nfloat miniBakedHeight(vec2 xz) {\n vec2 g = (xz + uHalf) / max(uHalf * 2.0, 1.0) * uMiniGridSegments;\n vec2 uv = (g + 0.5) / (uMiniGridSegments + 1.0);\n return textureLod(uMiniHeightGrid, clamp(uv, 0.0, 1.0), 0.0).a * uHeightScale;\n}\n`;\n\nconst BAKE_FRAGMENT = /* glsl */ `\nprecision highp float;\n${HEIGHT_FETCH}\n${MINI_BEVEL_GLSL}\nuniform vec3 uSunDir;\nuniform float uSoftness;\nvarying vec2 vUv;\n\nvoid main() {\n vec2 xz = (vUv * 2.0 - 1.0) * uHalf;\n float h = miniBakedHeight(xz) + 0.6;\n vec3 sun = normalize(uSunDir);\n float horiz = max(length(sun.xz), 1e-3);\n vec2 dir = sun.xz / horiz;\n float rise = sun.y / horiz; // ray climb per horizontal unit\n float stepLen = uHalf / 96.0;\n\n float occluded = 0.0;\n for (int i = 1; i <= 72; i++) {\n float t = float(i) * stepLen * (1.0 + float(i) * 0.02);\n vec2 q = xz + dir * t;\n float inside = step(0.0, miniBevelDistance(q, uHalf, uMiniTerrainBevel, uMiniBevelRounded));\n float above = miniBakedHeight(q) - (h + t * rise);\n // penumbra widens with distance to the occluder\n occluded = max(occluded, inside * smoothstep(0.0, uSoftness + t * 0.12, above));\n }\n\n float occ = 0.0;\n for (int k = 0; k < 8; k++) {\n float a = float(k) * 0.7853982 + 0.39;\n vec2 d = vec2(cos(a), sin(a));\n occ += clamp((miniBakedHeight(xz + d * 5.0) - h) / 5.0, 0.0, 1.0);\n occ += clamp((miniBakedHeight(xz + d * 16.0) - h) / 16.0, 0.0, 1.0);\n occ += clamp((miniBakedHeight(xz + d * 42.0) - h) / 42.0, 0.0, 1.0) * 0.8;\n }\n float ao = 1.0 - clamp(occ / 22.4 * 1.9, 0.0, 1.0) * 0.7;\n gl_FragColor = vec4(1.0 - occluded, ao, h - 0.6, 1.0);\n}\n`;\n\nconst DECAL_VERTEX = /* glsl */ `\n${HEIGHT_FETCH}\n${MINI_BEVEL_GLSL}\nvarying vec2 vXZ;\nvoid main() {\n vec2 xz = position.xz * uHalf;\n xz = miniBevelPoint(xz, uHalf, uMiniTerrainBevel, uMiniBevelRounded);\n vXZ = xz;\n vec4 wp = vec4(xz.x, miniBakedHeight(xz) + 0.25, xz.y, 1.0);\n gl_Position = projectionMatrix * viewMatrix * wp;\n}\n`;\n\nconst DECAL_FRAGMENT = /* glsl */ `\nprecision highp float;\nuniform sampler2D uMiniLightTex;\nuniform float uHalf;\nuniform float uShadowStrength;\nuniform float uAOStrength;\nuniform vec3 uShadowTint;\nvarying vec2 vXZ;\nvoid main() {\n vec2 uv = vXZ / (uHalf * 2.0) + 0.5;\n vec2 light = texture2D(uMiniLightTex, uv).rg;\n float shade = (1.0 - light.r) * uShadowStrength;\n // shadowed areas keep the cool sky fill instead of turning grey\n vec3 factor = mix(vec3(1.0), uShadowTint, shade);\n factor *= mix(1.0, light.g, uAOStrength);\n gl_FragColor = vec4(factor, 1.0);\n}\n`;\n\nconst COPY_FRAGMENT = /* glsl */ `\nprecision highp float;\nuniform sampler2D uSource;\nvarying vec2 vUv;\nvoid main() {\n gl_FragColor = texture2D(uSource, vUv);\n}\n`;\n\nfunction buildDecalGrid(segments) {\n const geo = new THREE.PlaneGeometry(2, 2, segments, segments);\n geo.rotateX(-Math.PI / 2);\n return geo;\n}\n\nexport class MiniLightMap {\n constructor(sharedUniforms, { size = 512 } = {}) {\n this.shared = sharedUniforms;\n this.size = size;\n this.target = new THREE.WebGLRenderTarget(size, size, {\n type: THREE.HalfFloatType,\n depthBuffer: false,\n stencilBuffer: false,\n });\n this.target.texture.minFilter = THREE.LinearFilter;\n this.target.texture.magFilter = THREE.LinearFilter;\n this.target.texture.generateMipmaps = false;\n this.target.texture.name = 'MiniLightMap';\n\n this.grid = null; // (segments + 1)^2 vertex heights, see ensureGrid\n const heightUniforms = {\n uMiniHeightGrid: { value: null },\n uMiniGridSegments: { value: 256 },\n uHalf: { value: 512 },\n uMiniTerrainBevel: sharedUniforms.uMiniTerrainBevel ?? { value: 0 },\n uMiniHexagon: sharedUniforms.uMiniHexagon ?? { value: 0 },\n uMiniBevelRounded: sharedUniforms.uMiniBevelRounded ?? { value: 0 },\n uHeightScale: sharedUniforms.uHeightScale,\n };\n this._heightUniforms = heightUniforms;\n this.bakeMaterial = new THREE.ShaderMaterial({\n name: 'MiniLightMapBake',\n uniforms: {\n ...heightUniforms,\n uSunDir: { value: new THREE.Vector3(0.5, 0.7, 0.3) },\n uSoftness: { value: 3 },\n },\n vertexShader: BAKE_VERTEX,\n fragmentShader: BAKE_FRAGMENT,\n depthTest: false,\n depthWrite: false,\n });\n this.bakeScene = new THREE.Scene();\n this.bakeCamera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1);\n const quad = new THREE.Mesh(new THREE.PlaneGeometry(2, 2), this.bakeMaterial);\n quad.frustumCulled = false;\n this.bakeScene.add(quad);\n this._quad = quad;\n\n this.decalMaterial = new THREE.ShaderMaterial({\n name: 'MiniLightDecal',\n uniforms: {\n ...heightUniforms,\n uMiniLightTex: { value: this.target.texture },\n uShadowStrength: { value: 0.62 },\n uAOStrength: { value: 0.85 },\n uShadowTint: { value: new THREE.Vector3(0.6, 0.66, 0.8) },\n },\n vertexShader: DECAL_VERTEX,\n fragmentShader: DECAL_FRAGMENT,\n blending: THREE.CustomBlending,\n blendEquation: THREE.AddEquation,\n blendSrc: THREE.DstColorFactor,\n blendDst: THREE.ZeroFactor,\n depthTest: true,\n depthWrite: false,\n polygonOffset: true,\n polygonOffsetFactor: -2,\n polygonOffsetUnits: -4,\n });\n this.decal = new THREE.Mesh(buildDecalGrid(256), this.decalMaterial);\n this.decal.name = 'mini-light-decal';\n this.decal.frustumCulled = false;\n this.decal.renderOrder = 6; // right after the terrain (0), before water (10)\n this._segments = 256;\n this._key = '';\n this.ready = false;\n\n // CPU copy of the vertex-height grid for prop placement (see\n // requestHeightField): the half-float grid is copied into a float target\n // (always readable) and read back asynchronously, never stalling a frame.\n this.field = null;\n this._readTarget = null;\n this._readPending = false;\n this._readQueued = null;\n this._copyMaterial = new THREE.ShaderMaterial({\n name: 'MiniLightMapCopy',\n uniforms: { uSource: { value: null } },\n vertexShader: BAKE_VERTEX,\n fragmentShader: COPY_FRAGMENT,\n depthTest: false,\n depthWrite: false,\n });\n }\n\n /**\n * Read the current vertex-height grid back to the CPU. Resolves into\n * `this.field` = { revision, n, half, heights: Float32Array(n * n) } with\n * heights[j * n + i] = world height of the vertex at\n * (x, z) = (-half + i * step, -half + j * step), step = 2 * half / (n - 1).\n * One read in flight at a time; a newer request replaces a queued one.\n * `onReady(field)` runs when the data lands.\n */\n requestHeightField(renderer, revision, heightScale, onReady) {\n if (!renderer || !this.grid || !renderer.readRenderTargetPixelsAsync) return;\n const request = { revision, heightScale, half: this._heightUniforms.uHalf.value, onReady };\n if (this._readPending) {\n this._readQueued = request;\n return;\n }\n const n = this.grid.width;\n if (!this._readTarget || this._readTarget.width !== n) {\n this._readTarget?.dispose();\n this._readTarget = new THREE.WebGLRenderTarget(n, n, {\n type: THREE.FloatType,\n format: THREE.RGBAFormat,\n minFilter: THREE.NearestFilter,\n magFilter: THREE.NearestFilter,\n depthBuffer: false,\n stencilBuffer: false,\n generateMipmaps: false,\n });\n this._readTarget.texture.name = 'MiniHeightFieldReadback';\n }\n const target = this._readTarget;\n const previous = renderer.getRenderTarget();\n try {\n this._copyMaterial.uniforms.uSource.value = this.grid.texture;\n this._quad.material = this._copyMaterial;\n renderer.setRenderTarget(target);\n renderer.render(this.bakeScene, this.bakeCamera);\n } finally {\n this._quad.material = this.bakeMaterial;\n renderer.setRenderTarget(previous);\n }\n this._readPending = true;\n const rgba = new Float32Array(n * n * 4);\n renderer.readRenderTargetPixelsAsync(target, 0, 0, n, n, rgba)\n .then(() => {\n if (this._readTarget !== target) return;\n const heights = new Float32Array(n * n);\n for (let i = 0; i < heights.length; i++) heights[i] = rgba[i * 4 + 3] * request.heightScale;\n this.field = { revision: request.revision, n, half: request.half, heights };\n request.onReady?.(this.field);\n })\n .catch(() => {})\n .finally(() => {\n this._readPending = false;\n const next = this._readQueued;\n this._readQueued = null;\n if (next && this._readTarget === target) {\n this.requestHeightField(renderer, next.revision, next.heightScale, next.onReady);\n }\n });\n }\n\n get texture() {\n return this.ready ? this.target.texture : null;\n }\n\n setLayout({ half, segments }) {\n this._heightUniforms.uHalf.value = half;\n this.bakeMaterial.uniforms.uSoftness.value = Math.max(1.5, half * 0.006);\n if (segments && segments !== this._segments) {\n this._segments = segments;\n this.decal.geometry.dispose();\n this.decal.geometry = buildDecalGrid(segments);\n this.invalidate();\n }\n }\n\n /** The vertex-height grid render target ((segments + 1)^2, half float). */\n ensureGrid() {\n const n = this._segments + 1;\n if (!this.grid || this.grid.width !== n) {\n this.grid?.dispose();\n this.grid = new THREE.WebGLRenderTarget(n, n, {\n type: THREE.HalfFloatType,\n format: THREE.RGBAFormat,\n minFilter: THREE.LinearFilter,\n magFilter: THREE.LinearFilter,\n depthBuffer: false,\n stencilBuffer: false,\n generateMipmaps: false,\n });\n this.grid.texture.colorSpace = THREE.NoColorSpace;\n this.grid.texture.name = 'MiniVertexHeightGrid';\n this._heightUniforms.uMiniHeightGrid.value = this.grid.texture;\n this.ready = false;\n this._key = '';\n }\n this._heightUniforms.uMiniGridSegments.value = this._segments;\n return this.grid;\n }\n\n /** Whether the published bake was made for `key`. */\n isCurrent(key) {\n return this.ready && this._key === key;\n }\n\n /**\n * Re-bake when the key (terrain generation, height program, sun, footprint)\n * changed. `renderHeights(gridTarget)` fills the vertex-height grid and\n * returns false when no height program is available (nothing is changed).\n * Returns true when a bake was rendered this call.\n */\n update(renderer, key, sunDir, renderHeights) {\n if (!renderer || !renderHeights) return false;\n if (key === this._key && this.ready) return false;\n const grid = this.ensureGrid();\n if (!renderHeights(grid)) return false;\n this._key = key;\n this.bakeMaterial.uniforms.uSunDir.value.copy(sunDir);\n const previous = renderer.getRenderTarget();\n const autoClear = renderer.autoClear;\n try {\n renderer.autoClear = true;\n renderer.setRenderTarget(this.target);\n renderer.render(this.bakeScene, this.bakeCamera);\n } finally {\n renderer.setRenderTarget(previous);\n renderer.autoClear = autoClear;\n }\n this.ready = true;\n return true;\n }\n\n invalidate() {\n this._key = '';\n }\n\n get materials() {\n return [this.bakeMaterial, this.decalMaterial, this._copyMaterial];\n }\n\n dispose() {\n this.decal.removeFromParent();\n this.decal.geometry.dispose();\n this._quad.geometry.dispose();\n this.bakeMaterial.dispose();\n this.decalMaterial.dispose();\n this.target.dispose();\n this.grid?.dispose();\n this.grid = null;\n this._readTarget?.dispose();\n this._readTarget = null;\n this.field = null;\n this._copyMaterial.dispose();\n }\n}\n","import * as THREE from 'three';\nimport {\n MINI_CUT_STYLES,\n MINI_RECIPES,\n createMiniTerrainState,\n miniCompositionUniformValues,\n miniLodSegments,\n miniParamsPatch,\n normalizeMiniTerrainState,\n normalizeMiniView,\n resolveMiniCloudLayout,\n resolveMiniFraming,\n resolveMiniLayout,\n} from './MiniTerrainSettings.js';\nimport { miniCutColor } from './miniCutGLSL.js';\nimport { MiniStudioStage } from './MiniStudioStage.js';\nimport { MiniWaterCut } from './MiniWaterCut.js';\nimport { MiniLightMap } from './MiniLightMap.js';\nimport { applyMiniWaterLook, createMiniWaterSurfaceMaterial } from './MiniWaterMaterial.js';\nimport { miniStylePatch, miniWaterColors } from './MiniLook.js';\n\n// ============================================================================\n// MiniTerrainController — the engine-side owner of the Mini Terrain\n// presentation. The engine stays the orchestrator: it calls a handful of\n// hooks (uniforms, LOD segments, wall/base sizes, plinth sync, underwater\n// volume, per-frame water-cut sync) and this class answers them from the\n// normalized Mini document. Presentation objects (studio stage, water cut)\n// are created on first activation and disposed with the engine.\n//\n// Mini is a specialisation of the finite studio world, so `active` also\n// requires worldMode === 'studio': no other mode ever sees Mini behaviour.\n// ============================================================================\n\n// Which Mini fields map to which params scope (see miniParamsPatch).\nconst FIELD_SCOPES = Object.freeze({\n waterLevel: 'water',\n vegetation: 'props',\n propScale: 'propScale',\n clouds: 'clouds',\n quality: 'quality',\n});\n\nexport class MiniTerrainController {\n constructor(engine) {\n this.engine = engine;\n this.state = null;\n this.stage = null;\n this.waterCut = null;\n this.waterSurface = null;\n this.lightMap = null;\n this._waterEntry = null;\n this._surfaceEntry = null;\n this._registeredWaterSystem = null;\n this._presentationKey = '';\n this._homeKey = '';\n this._fieldKey = '';\n this._fieldStructure = '';\n }\n\n get active() {\n return !!this.state && this.engine.worldMode === 'studio';\n }\n\n get layout() {\n return resolveMiniLayout(this.state);\n }\n\n serialize() {\n return this.state ? structuredClone(this.state) : null;\n }\n\n /** Install a (possibly null) Mini document. Never touches params. */\n install(state) {\n const next = state ? normalizeMiniTerrainState(state) : null;\n const wasActive = !!this.state;\n this.state = next;\n if (next) this._ensureObjects();\n if (wasActive && !next) this._deactivate();\n this._presentationKey = '';\n this._homeKey = '';\n return this.state;\n }\n\n /** Create a fresh document for a new project. */\n createState(spec = {}) {\n return createMiniTerrainState({ recipe: spec.recipe, seed: spec.seed, preset: spec.preset });\n }\n\n /** Params that realise the current document (scope: see miniParamsPatch). */\n paramsPatch(scope = 'all') {\n return this.state ? miniParamsPatch(this.state, scope) : {};\n }\n\n recipe() {\n return this.state ? MINI_RECIPES[this.state.recipe] : null;\n }\n\n /**\n * Compute the params patch for a document change. Returns\n * { state, params, palette, composition } describing what must be\n * invalidated — relief composition, palette and water/cloud/props params\n * are separate categories so a vegetation change never rebuilds terrain.\n */\n planChange(patch = {}) {\n if (!this.state) return null;\n const prev = this.state;\n if ((patch.bevelSync ?? prev.bevelSync) && (patch.waterBevel !== undefined || patch.terrainBevel !== undefined)) {\n const bevel = patch.waterBevel ?? patch.terrainBevel;\n patch = { ...patch, waterBevel: bevel, terrainBevel: bevel };\n }\n const next = normalizeMiniTerrainState({ ...prev, ...patch });\n const changed = Object.keys(next).filter((key) => JSON.stringify(next[key]) !== JSON.stringify(prev[key]));\n let params = {};\n let palette = null;\n let composition = false;\n if (changed.includes('recipe') || changed.includes('preset')) {\n // A new recipe is a new look: relief, water look, palette, clouds, props.\n const r = MINI_RECIPES[next.recipe];\n next.vegetation = patch.vegetation ?? r.vegetation;\n next.clouds = patch.clouds ?? r.clouds;\n next.cutStyle = patch.cutStyle ?? r.cutStyle;\n params = miniParamsPatch(next, 'all');\n palette = miniStylePatch(next.recipe, next.preset);\n composition = true;\n } else {\n if (changed.includes('seed')) {\n // A seed replaces the generated composition, detail noise and the\n // scattered props; amounts, quality and presentation are kept.\n const all = miniParamsPatch(next, 'all');\n params.seed = all.seed;\n params.propsSeed = all.propsSeed;\n composition = true;\n }\n if (changed.includes('relief')) {\n // Relief scales the whole height range: the composition heights, and\n // for a procedural diorama the stack itself (heightScale) with the\n // formation and water levels that are expressed in the same units.\n const all = miniParamsPatch(next, 'all');\n const structure = miniParamsPatch(next, 'structure');\n params.heightScale = structure.heightScale;\n params.terrainFormationSeaLevel = structure.terrainFormationSeaLevel;\n Object.assign(params, miniParamsPatch(next, 'water'));\n params.cloudAltitude = all.cloudAltitude;\n composition = true;\n }\n if (changed.includes('width')) {\n params = { ...params, ...miniParamsPatch(next, 'all') };\n composition = true;\n }\n for (const [field, scope] of Object.entries(FIELD_SCOPES)) {\n if (changed.includes(field)) Object.assign(params, miniParamsPatch(next, scope));\n }\n }\n return { state: next, changed, params, palette, composition };\n }\n\n // ------------------------------------------------------------------ hooks\n\n /** Composition + cut uniforms (shape 0 / cut 0 when not active). */\n applyUniforms(u) {\n const active = this.active;\n const c = miniCompositionUniformValues(active ? this.state : null);\n if (u.uMiniShape) u.uMiniShape.value = c.shape;\n u.uMiniFrame?.value.set(...c.frame);\n u.uMiniGeometry?.value.set(...c.geometry);\n u.uMiniHeights?.value.set(...c.heights);\n u.uMiniWobble?.value.set(...c.wobble);\n u.uMiniDetail?.value.set(...c.detail);\n if (u.uMiniCut) u.uMiniCut.value = active ? 1 : 0;\n if (u.uMiniTerrainBevel) u.uMiniTerrainBevel.value = active ? this.layout.terrainBevel : 0;\n if (u.uMiniBevelRounded) u.uMiniBevelRounded.value = active && this.layout.rounded ? 1 : 0;\n if (u.uMiniHexagon) u.uMiniHexagon.value = active && this.layout.hexagon ? 1 : 0;\n if (!active) return;\n const style = MINI_CUT_STYLES[this.state.cutStyle] ?? MINI_CUT_STYLES.strata;\n const L = this.layout;\n u.uMiniCutTopsoil?.value.set(...miniCutColor(style.topsoil));\n u.uMiniCutBandA?.value.set(...miniCutColor(style.bandA));\n u.uMiniCutBandB?.value.set(...miniCutColor(style.bandB));\n u.uMiniCutDeep?.value.set(...miniCutColor(style.deep));\n u.uMiniCutSediment?.value.set(...miniCutColor(style.sediment));\n u.uMiniCutParams?.value.set(style.bands, -L.baseDepth, Math.max(4, L.width * 0.012), L.reliefHeight);\n }\n\n lodSegments() {\n return miniLodSegments(this.state);\n }\n\n /** Cloud slab placement override (null = the classic board layout). */\n cloudLayout() {\n return this.active ? resolveMiniCloudLayout(this.state) : null;\n }\n\n /**\n * Plinth replacement: hide the classic box, lay out the studio stage and\n * the water cut, install the camera home. Returns true when Mini owns the\n * base (the caller skips its own plinth build).\n */\n syncPresentation() {\n const eng = this.engine;\n if (!this.active) {\n this._deactivate();\n return false;\n }\n this._ensureObjects();\n const L = this.layout;\n const p = eng.params;\n if (eng.plinth) eng.plinth.visible = false;\n if (eng.diskWall) eng.diskWall.visible = false;\n this._ownsPlinth = true;\n const maxHeight = L.formationSea + L.heightScale * 0.8;\n this.stage.setLayout({\n half: L.half,\n baseY: -L.baseDepth,\n socleHeight: L.socleHeight,\n socleMargin: L.socleMargin,\n maxHeight,\n socle: this.state.socle,\n circle: L.shape === 'circle',\n hexagon: L.hexagon,\n });\n this.stage.setBackdrop(this.state.backdrop);\n this.stage.setSocleColor(MINI_CUT_STYLES[this.state.cutStyle]?.sediment ?? [0.7, 0.62, 0.5]);\n this.stage.setVisible(eng._plinthWanted !== false);\n this.waterCut.setBounds({\n half: L.half,\n bottom: -L.baseDepth,\n top: p.seaLevel,\n inset: Math.max(0.35, L.width * 0.0005),\n bevel: L.waterBevel,\n rounded: L.rounded,\n hexagon: L.hexagon,\n });\n this.lightMap.setLayout({ half: L.half, segments: L.segments });\n this._applyWaterLook();\n this.syncLighting();\n eng.waterSystem?.setStudioOverride(this.waterSurface);\n this._syncHome();\n return true;\n }\n\n _applyWaterLook() {\n if (!this.state) return;\n const L = this.layout;\n const look = {\n colors: miniWaterColors(this.state.recipe),\n params: this.engine.params,\n half: L.half,\n depthRange: L.reliefHeight * 0.32,\n edges: this.state.waterEdges,\n bevel: L.waterBevel,\n };\n applyMiniWaterLook(this.waterSurface, look);\n applyMiniWaterLook(this.waterCut?.material, look);\n }\n\n syncLighting(state = null) {\n if (!this.active) return;\n const eng = this.engine;\n const skyActive = eng._skyActive?.() ?? false;\n this.stage?.setLighting(state ?? eng._resolveCloudLighting?.(), skyActive);\n const u = this.waterSurface?.uniforms;\n if (u) {\n const sky = eng.proceduralSky?.uniforms;\n u.uMiniEnvSky.value = skyActive && sky ? 1 : 0;\n if (sky) {\n u.uSkyZenith.value.copy(sky.uSkyZenith.value);\n u.uSkyHorizon.value.copy(sky.uSkyHorizon.value);\n }\n }\n }\n\n /**\n * Per-frame: re-bake the light map when the terrain or sun changed, drive\n * the water animation clock, and keep the cut faces on the water surface.\n */\n beforeRender() {\n if (!this.waterCut) return;\n const eng = this.engine;\n if (this.active && this.lightMap) {\n const sun = eng.uniforms.uSunDir.value;\n const L = this.layout;\n // Structural identity of the diorama: a different recipe/seed/footprint\n // must never be shown with data derived from the previous terrain.\n const structure = [this.state.recipe, this.state.seed, this.state.preset ?? '', L.half].join(':');\n // The light map is baked from the terrain's vertex heights rendered by\n // the compiled height program (one small grid, same frame as an edit),\n // so it follows every slider live. It needs the program that draws the\n // terrain right now: during a structural recompile (or before the first\n // program is ready) the previous map is never shown over a different\n // relief (white foam plains, floating dark \"mountains\").\n const baker = eng.terrainHeightBaker;\n const program = eng._activeHeightProgram?.('studio');\n const programKey = program ? `${Math.round(eng.params.octaves)}:${program.heightSig || program.sig}` : null;\n const programReady = !!baker?.material && baker.programKey === programKey\n && eng._terrainSourcePendingToken == null;\n let lightValid = false;\n if (programReady) {\n const u = eng.uniforms;\n const key = [\n eng._terrainGen, programKey, u.uHeightScale.value,\n sun.x.toFixed(3), sun.y.toFixed(3), sun.z.toFixed(3), L.half, L.segments, L.terrainBevel, L.rounded, L.hexagon,\n ].join(':');\n const renderHeights = (grid) => baker.renderHeightGrid(grid, this._gridTransform(L));\n if (this.lightMap.update(eng.renderer, key, sun, renderHeights)) eng._needsRender = true;\n lightValid = this.lightMap.isCurrent(key);\n if (lightValid) this._lightStructure = structure;\n }\n lightValid = lightValid && this._lightStructure === structure;\n const lightTex = lightValid ? this.lightMap.texture : null;\n // Props are placed from a CPU copy of the same height grid: request it\n // whenever the heights changed (not on a sun-only re-bake).\n if (lightValid && eng._miniReadbackEnabled !== false) {\n const u = eng.uniforms;\n const fieldKey = [eng._terrainGen, programKey, u.uHeightScale.value, L.half, L.segments].join(':');\n if (fieldKey !== this._fieldKey) {\n this._fieldKey = fieldKey;\n this.lightMap.requestHeightField(eng.renderer, eng._terrainGen, u.uHeightScale.value, () => {\n this._fieldStructure = structure;\n eng._needsRender = true;\n });\n }\n }\n const p = eng.params;\n const anim = p.waterAnim ? (eng.uniforms.uTime?.value ?? 0) * (p.waterAnimSpeed ?? 1) * (p.waterWaveSpeed ?? 1) : 0;\n for (const material of [this.waterSurface, this.waterCut.material]) {\n applyMiniWaterLook(material, { lightTex, animTime: anim });\n }\n this.lightMap.decal.visible = !!lightTex && this.stage?.group.visible !== false;\n // Vegetation and rocks are regular props: they receive the diorama's\n // cliff shadows / AO and stand on the live relief (light map B) on the\n // GPU, so they follow a slider drag in the very frame it is drawn. While\n // no valid map exists (structural recompile) they are hidden instead of\n // floating over a relief they were not placed on.\n const pm = eng.propsManager;\n if (pm) {\n pm.setMiniLightMap(lightTex, L.half, true);\n pm.suspended = !lightValid || (!!this.lightMap.field && this._fieldStructure !== structure);\n }\n }\n const visible = this.active && !!eng.water?.visible && eng.params.seaLevel > 0.5;\n this.waterCut.mesh.visible = visible;\n if (visible) {\n const L = this.layout;\n this.waterCut.setBounds({\n half: L.half,\n bottom: -L.baseDepth,\n top: eng.params.seaLevel,\n inset: Math.max(0.35, L.width * 0.0005),\n bevel: L.waterBevel,\n rounded: L.rounded,\n hexagon: L.hexagon,\n });\n }\n }\n\n /**\n * Vertex-height grid read back for prop placement (see\n * MiniLightMap.requestHeightField), or null when there is none for the\n * current diorama yet (the classic analytic sampler is used meanwhile).\n */\n propField() {\n if (!this.active || !this.lightMap?.field) return null;\n const structure = [this.state.recipe, this.state.seed, this.state.preset ?? '', this.layout.half].join(':');\n return this._fieldStructure === structure ? this.lightMap.field : null;\n }\n\n /**\n * uv transform for TerrainHeightBaker.renderHeightGrid so texel i of the\n * (segments + 1)^2 grid lands exactly on surface vertex i\n * (x = -half + i * width / segments), whatever the shared bake rectangle.\n */\n _gridTransform(L) {\n const u = this.engine.uniforms;\n const o = u.uBakeOrigin.value;\n const span = u.uBakeSpan.value;\n const sx = Math.max(span.x, 1);\n const sz = Math.max(span.y, 1);\n const step = (2 * L.half) / L.segments;\n const n = L.segments + 1;\n this._gridUv ||= new THREE.Vector4();\n return this._gridUv.set(\n (-L.half - o.x - 0.5 * step) / sx,\n (-L.half - o.y - 0.5 * step) / sz,\n (step * n) / sx,\n (step * n) / sz,\n );\n }\n\n setStageVisible(visible) {\n this.stage?.setVisible(visible && this.active);\n if (this.waterCut && !visible) this.waterCut.mesh.visible = false;\n }\n\n /** Bounded water volume for the underwater detector (null = unbounded). */\n underwaterVolume() {\n if (!this.active) return null;\n const L = this.layout;\n return { minX: -L.half, maxX: L.half, minZ: -L.half, maxZ: L.half, floorY: -L.baseDepth, bevel: L.waterBevel, rounded: L.rounded, hexagon: L.hexagon };\n }\n\n /** Walkable rectangle: the footprint, a step inside the cut faces. */\n walkBounds() {\n if (!this.active) return null;\n const L = this.layout;\n const m = Math.max(1.5, L.width * 0.004);\n const bounds = { minX: -L.half + m, maxX: L.half - m, minZ: -L.half + m, maxZ: L.half - m };\n if (L.shape === 'circle') bounds.radius = L.half - m;\n if (L.hexagon) bounds.hexagonHalf = L.half - m * 2 / Math.sqrt(3);\n return bounds;\n }\n\n framing() {\n const cam = this.engine.camera;\n return resolveMiniFraming(this.state, { fov: cam?.fov ?? 45, aspect: cam?.aspect || 16 / 9 });\n }\n\n /** Recentre on the composition (blend = ease, else cut). */\n frame({ blend = true } = {}) {\n if (!this.active) return;\n this._syncHome(true);\n this.engine.controls.goToView(this.engine.controls.home, { blend });\n this.engine._needsRender = true;\n }\n\n saveView(name) {\n if (!this.state) return null;\n const view = normalizeMiniView({ name: name || `View ${(this.state.camera?.views?.length ?? 0) + 1}`, ...this.engine.controls.getView() });\n const views = [...(this.state.camera?.views ?? []), view].slice(-8);\n this.state = normalizeMiniTerrainState({ ...this.state, camera: { views } });\n return this.state;\n }\n\n removeView(index) {\n if (!this.state?.camera?.views) return this.state;\n const views = this.state.camera.views.filter((_, i) => i !== index);\n this.state = normalizeMiniTerrainState({ ...this.state, camera: { views } });\n return this.state;\n }\n\n goToView(index) {\n const view = this.state?.camera?.views?.[index];\n if (!view) return false;\n this.engine.controls.goToView(view, { blend: true });\n this.engine._needsRender = true;\n return true;\n }\n\n diagnostics() {\n if (!this.state) return null;\n const L = this.layout;\n return {\n active: this.active,\n recipe: this.state.recipe,\n seed: this.state.seed,\n width: L.width,\n segments: L.segments,\n surfaceTriangles: 2 * L.segments * L.segments,\n wallTriangles: 8 * L.segments,\n lightDecalTriangles: 2 * L.segments * L.segments,\n lightMapReady: !!this.lightMap?.ready,\n props: this.engine.propsManager?.getDiagnostics?.()?.instances ?? null,\n waterCutVisible: !!this.waterCut?.mesh.visible,\n };\n }\n\n /**\n * What the exporter needs to rebuild the diorama outside the app: section\n * depth and strata, water colours (linear) and the socle. Null when off.\n */\n exportSpec() {\n if (!this.active) return null;\n const L = this.layout;\n const style = MINI_CUT_STYLES[this.state.cutStyle] ?? MINI_CUT_STYLES.strata;\n const water = miniWaterColors(this.state.recipe);\n return {\n width: L.width,\n half: L.half,\n baseDepth: L.baseDepth,\n terrainBevel: L.terrainBevel,\n waterBevel: L.waterBevel,\n rounded: L.rounded,\n hexagon: L.hexagon,\n cut: {\n topsoil: miniCutColor(style.topsoil),\n bandA: miniCutColor(style.bandA),\n bandB: miniCutColor(style.bandB),\n deep: miniCutColor(style.deep),\n sediment: miniCutColor(style.sediment),\n bands: style.bands,\n topsoilDepth: Math.max(4, L.width * 0.012),\n reliefHeight: L.reliefHeight,\n },\n water: { ...water, depthRange: L.reliefHeight * 0.32 },\n socle: this.state.socle\n ? { height: L.socleHeight, margin: L.socleMargin, color: miniCutColor(style.sediment), circle: L.shape === 'circle', hexagon: L.hexagon }\n : null,\n };\n }\n\n /** Materials the engine should warm with the Mini scene. */\n compileMaterials() {\n return [\n this.waterSurface, this.waterCut?.material, ...(this.lightMap?.materials ?? []),\n ...(this.stage?.materials ?? []),\n ].filter(Boolean);\n }\n\n dispose() {\n this._deactivate();\n this._bindWaterSystem(null);\n this._waterEntry = null;\n this._surfaceEntry = null;\n this.lightMap?.dispose();\n this.waterSurface?.dispose();\n this.stage?.dispose();\n this.waterCut?.dispose();\n this.lightMap = null;\n this.waterSurface = null;\n this.stage = null;\n this.waterCut = null;\n }\n\n // ---------------------------------------------------------------- internal\n\n _ensureObjects() {\n const eng = this.engine;\n if (!eng.scene || !eng.uniforms) return;\n if (!this.stage) {\n this.stage = new MiniStudioStage(eng.uniforms);\n eng.scene.add(this.stage.group);\n }\n if (!this.waterCut) {\n this.waterCut = new MiniWaterCut(eng.uniforms);\n eng.scene.add(this.waterCut.mesh);\n this._waterEntry = {\n mesh: this.waterCut.mesh,\n material: this.waterCut.material,\n applySettings: (params) => applyMiniWaterLook(this.waterCut?.material, { params }),\n };\n }\n if (!this.waterSurface) {\n // Rendered on the studio water mesh through the WaterSystem override;\n // registered as auxiliary so it receives the water-free scene capture.\n this.waterSurface = createMiniWaterSurfaceMaterial(eng.uniforms);\n this._surfaceEntry = {\n material: this.waterSurface,\n applySettings: (params) => applyMiniWaterLook(this.waterSurface, { params }),\n };\n }\n if (!this.lightMap) {\n this.lightMap = new MiniLightMap(eng.uniforms);\n this.stage.group.add(this.lightMap.decal);\n }\n this._bindWaterSystem(eng.waterSystem ?? null);\n }\n\n _bindWaterSystem(system) {\n const previous = this._registeredWaterSystem;\n if (previous === system) return;\n for (const entry of [this._waterEntry, this._surfaceEntry]) {\n if (entry) previous?.removeAuxiliaryWater(entry);\n }\n if (previous?.studioOverride === this.waterSurface) previous.setStudioOverride(null);\n this._registeredWaterSystem = system;\n for (const entry of [this._waterEntry, this._surfaceEntry]) {\n if (entry) system?.addAuxiliaryWater(entry);\n }\n }\n\n _deactivate() {\n const eng = this.engine;\n if (this.stage) this.stage.setVisible(false);\n if (this.waterCut) this.waterCut.mesh.visible = false;\n eng.propsManager?.setMiniLightMap(null);\n if (eng.propsManager) eng.propsManager.suspended = false;\n this._fieldKey = '';\n if (eng.waterSystem?.studioOverride && eng.waterSystem.studioOverride === this.waterSurface) {\n eng.waterSystem.setStudioOverride(null);\n }\n if (this._ownsPlinth) {\n this._ownsPlinth = false;\n if (eng.plinth) eng.plinth.visible = eng._plinthWanted !== false;\n eng._plinthGeometryKey = null;\n }\n if (eng.controls?.home) {\n eng.controls.setHome(null);\n eng._plinthGeometryKey = null;\n }\n this._homeKey = '';\n }\n\n _syncHome(force = false) {\n const controls = this.engine.controls;\n if (!controls) return;\n const f = this.framing();\n const key = JSON.stringify([f.theta, f.radius, f.target, f.minRadius, f.maxRadius]);\n if (!force && key === this._homeKey && controls.home) return;\n this._homeKey = key;\n controls.setHome(f);\n }\n}\n","import * as THREE from 'three';\nimport { DEFAULT_PARAMS } from '../../engine/presets.js';\nimport { createTerrain } from '../FiniteTerrain.js';\nimport { MiniTerrainController } from '../../engine/mini/MiniTerrainController.js';\nimport {\n createMiniTerrainState,\n normalizeMiniTerrainState,\n miniParamsPatch,\n resolveMiniLayout,\n} from '../../engine/mini/MiniTerrainSettings.js';\nimport { miniStylePatch } from '../../engine/mini/MiniLook.js';\nimport { terrainMaterial, terrainStyle } from '../TerrainAppearance.js';\nimport { applyTerrainShapeUniforms, applyTerrainShadingUniforms } from '../TerrainParameters.js';\nimport { TerrainHeightCache } from '../effects/TerrainHeightCache.js';\nimport { compileMaterial } from '../resources/CompileMaterial.js';\nimport { withRendererState } from '../resources/RendererState.js';\n\nconst SOURCE_KEYS = ['seed', 'octaves', 'noiseScale', 'noiseStrength', 'terrainSmoothing',\n 'terrainDetail', 'persistence', 'lacunarity', 'ridge', 'warp', 'falloff', 'edgeFalloffMode'];\n\nfunction configuration(state) {\n const p = { ...DEFAULT_PARAMS, ...miniParamsPatch(state, 'all') },\n l = resolveMiniLayout(state);\n return {\n terrainFormationSeaLevel: p.terrainFormationSeaLevel,\n material: terrainMaterial(p),\n layout: { chunkCount: 1, chunkSize: l.width },\n heightScale: l.heightScale,\n seaLevel: l.seaLevel,\n source: {\n kind: 'noise',\n seed: p.seed,\n octaves: p.octaves,\n scale: p.noiseScale,\n strength: p.noiseStrength,\n smoothing: p.terrainSmoothing,\n detail: p.terrainDetail,\n persistence: p.persistence,\n lacunarity: p.lacunarity,\n ridge: p.ridge,\n warp: p.warp,\n falloff: p.falloff,\n edgeFalloffMode: p.edgeFalloffMode,\n },\n quality: { mergeEnabled: false, morphEnabled: false },\n };\n}\n\n/** Mini is a finite presentation. It suggests framing; the host owns its camera. */\nexport class MiniPresentation {\n constructor(terrain, state, { backdrop = false } = {}) {\n this.terrain = terrain;\n this.backdrop = backdrop;\n this.disposed = false;\n const t = terrain;\n this.context = {\n renderer: t._renderer,\n scene: t.object,\n uniforms: t._uniforms,\n worldMode: 'studio',\n _miniReadbackEnabled: false,\n params: t._params,\n camera: t._viewCamera,\n _activeHeightProgram: () => t._stackGLSL,\n _terrainGen: t._revision,\n _terrainSourcePendingToken: null,\n };\n this.controller = new MiniTerrainController(this.context);\n this.controller.install(state);\n this.cache = new TerrainHeightCache({ terrain, resolution: 256, attach: false });\n this.context.terrainHeightBaker = this.cache.baker;\n this._detach = t.addLayer(this);\n t.mini = this;\n this._apply();\n }\n get state() {\n return this.controller.serialize();\n }\n _apply() {\n const t = this.terrain,\n l = this.controller.layout,\n p = t._params;\n // Mini decorates the saved terrain. Recipe defaults are applied only when\n // creating or explicitly changing a recipe, never while loading/preparing.\n this.context.params = { ...p, ...[...t._layers].find((layer) => layer.system)?.parameters };\n this.context._terrainGen = t._revision;\n const water = [...t._layers].find((layer) => layer.system);\n this.context.water = water?.context.mesh;\n this.context.waterSystem = water?.system;\n applyTerrainShapeUniforms(t._uniforms, p, l.width);\n applyTerrainShadingUniforms(t._uniforms, p, {\n size: l.width,\n skirtDepth: l.baseDepth,\n wallThickness: 0,\n });\n this.controller.applyUniforms(t._uniforms);\n t._runtime.board.syncCells({\n chunkCount: 1,\n chunkSize: l.width,\n maxHeight: Math.max(p.heightScale * 1.35 + 2, t._source.maxHeight),\n skirtDepth: l.baseDepth,\n lodSegments: this.controller.lodSegments(),\n cells: [{ cx: 0, cz: 0 }],\n progressive: false,\n });\n while (t._runtime.board._lodRebuildQueue.length) t._runtime.board.updateLOD(t._cameraPosition);\n t._runtime.board.setMorphEnabled(false);\n t._runtime.board.setMergeOptions({ enabled: false });\n this.controller.syncPresentation();\n this.controller.stage.backdrop.visible = this.backdrop;\n t._miniCloudLayout = this.controller.cloudLayout();\n t._miniVolume = this.controller.underwaterVolume();\n }\n async configure(patch = {}, options = {}) {\n const plan = this.controller.planChange(patch);\n const state = plan.state;\n const p = { ...this.terrain._params, ...plan.params };\n const c = this.terrain.configuration;\n const next = {\n heightScale: p.heightScale, seaLevel: p.seaLevel,\n terrainFormationSeaLevel: p.terrainFormationSeaLevel,\n layout: { chunkCount: 1, chunkSize: state.width },\n material: terrainMaterial(plan.params),\n ...(plan.palette ? { palette: plan.palette.palette, style: terrainStyle(plan.palette) } : {}),\n };\n if (SOURCE_KEYS.some(key => Object.hasOwn(plan.params, key))) {\n next.source = {\n ...c.source, seed: p.seed, octaves: p.octaves,\n scale: p.noiseScale, strength: p.noiseStrength,\n smoothing: p.terrainSmoothing, detail: p.terrainDetail,\n persistence: p.persistence, lacunarity: p.lacunarity, ridge: p.ridge,\n warp: p.warp, falloff: p.falloff, edgeFalloffMode: p.edgeFalloffMode,\n };\n }\n this._nextState = state;\n try {\n await this.terrain.configure(next, options);\n // The effects own their saved parameters; update only the fields changed\n // by this Mini action, preserving edits from the shared water/cloud API.\n for (const layer of this.terrain._layers) {\n if (!layer.system && !layer.layer) continue;\n const parameters = Object.fromEntries(Object.entries(plan.params).filter(([key]) =>\n Object.hasOwn(layer.parameters, key) || (layer.system && key === 'seaLevel')));\n if (Object.keys(parameters).length) await layer.configure({\n parameters,\n ...(layer.system && plan.params.waterMode ? { mode: plan.params.waterMode } : {}),\n }, options);\n }\n } finally {\n if (this._nextState === state) this._nextState = null;\n }\n }\n\n async prepare(camera, options = {}) {\n this.context.camera = camera;\n this._apply();\n await this.cache.prepare(camera, options);\n for (const material of this.controller.compileMaterials())\n await compileMaterial(this.terrain._renderer, material, camera);\n this.beforeRender();\n }\n async onTerrainChanged(options = {}) {\n if (this._nextState) {\n this.controller.install(this._nextState);\n this._nextState = null;\n }\n this._apply();\n await this.cache.prepare(this.terrain._viewCamera ?? new THREE.PerspectiveCamera(), options);\n }\n update(_dt, { camera }) {\n this.context.camera = camera;\n this.context._terrainGen = this.terrain._revision;\n }\n beforeRender() {\n this._applyWater();\n withRendererState(this.terrain._renderer, () => this.controller.beforeRender());\n }\n _applyWater() {\n const water = [...this.terrain._layers].find((layer) => layer.system);\n if (water?.system !== this.context.waterSystem) {\n this.context.params = { ...this.terrain._params, ...water?.parameters };\n this.context.water = water?.context.mesh;\n this.context.waterSystem = water?.system;\n this.controller.syncPresentation();\n this.controller.stage.backdrop.visible = this.backdrop;\n }\n }\n framing() {\n return this.controller.framing();\n }\n serialize() {\n return { type: 'mini', state: this.state, backdrop: this.backdrop };\n }\n getDiagnostics() {\n return this.controller.diagnostics();\n }\n dispose() {\n if (this.disposed) return;\n this.disposed = true;\n this._detach();\n this.controller.dispose();\n this.cache.dispose();\n delete this.terrain.mini;\n }\n}\n\nexport async function createMiniTerrain({ mini = {}, backdrop = false, ...options } = {}) {\n const state = normalizeMiniTerrainState({ ...createMiniTerrainState(mini), ...mini });\n const defaults = configuration(state);\n const look = miniStylePatch(state.recipe, state.preset);\n const custom = options.configuration ?? {};\n const terrain = await createTerrain({\n ...options,\n configuration: {\n ...defaults, ...custom,\n source: { ...defaults.source, ...custom.source },\n material: { ...defaults.material, ...custom.material },\n style: { ...terrainStyle(look), ...custom.style },\n palette: { ...look.palette, ...custom.palette },\n quality: { ...defaults.quality, ...custom.quality },\n layout: { chunkCount: 1, chunkSize: state.width },\n },\n });\n try {\n new MiniPresentation(terrain, state, { backdrop });\n return terrain;\n } catch (error) {\n terrain.dispose();\n throw error;\n }\n}\n"],"names":[],"mappings":"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"}
@@ -1,8 +1,8 @@
1
- import { T as TERRAIN_CLOUD_SHADOW_GLSL, a as TERRAIN_DETAIL_GLSL } from "./TerrainParameters-A3fcNJTR.js";
1
+ import { T as TERRAIN_CLOUD_SHADOW_GLSL, a as TERRAIN_DETAIL_GLSL } from "./TerrainParameters-DMCjnnxz.js";
2
2
  import { i as installSurfaceMaterialBackend, P as PALETTE_UNIFORMS_GLSL, T as TERRAIN_COLOR_FUNCTIONS_GLSL, S as SURFACE_TEXTURE_UNIFORMS_GLSL, a as SURFACE_TEXTURE_FUNCTIONS_GLSL } from "./TerrainSources-Bye63rDk.js";
3
3
  import * as THREE from "three";
4
- import { W as WATER_DEPTH_PULL_GLSL, C as COMMON_UNIFORMS_GLSL, N as NOISE_GLSL, B as BIOME_GLSL, M as MANUAL_SURFACE_WEIGHTS_GLSL } from "./biomeGLSL-CIkhxIlH.js";
5
- import { b as buildPlanetHeightGLSL, P as PLANET_UNIFORMS_GLSL, a as PLANET_NOISE_GLSL, c as PLANET_CLIMATE_CACHE_GLSL } from "./planetGLSL-2xas0f3o.js";
4
+ import { W as WATER_DEPTH_PULL_GLSL, C as COMMON_UNIFORMS_GLSL, N as NOISE_GLSL, B as BIOME_GLSL, M as MANUAL_SURFACE_WEIGHTS_GLSL } from "./biomeGLSL-DWGDDBqT.js";
5
+ import { b as buildPlanetHeightGLSL, P as PLANET_UNIFORMS_GLSL, a as PLANET_NOISE_GLSL, c as PLANET_CLIMATE_CACHE_GLSL } from "./planetGLSL-D9Zy2IAw.js";
6
6
  import { g as generateStackGLSL, d as defaultLegacyStack } from "./noiseStackCodegen-C4R9Y3L8.js";
7
7
  import { c as createWaterLightingUniforms, W as WATER_LIGHTING_UNIFORMS_GLSL } from "./waterLightingGLSL-DJ1lX0Cy.js";
8
8
  const DEFAULT_STACK_GLSL = generateStackGLSL(defaultLegacyStack());
@@ -586,4 +586,4 @@ export {
586
586
  createPlanetWaterMaterial as a,
587
587
  createPlanetMaterial as c
588
588
  };
589
- //# sourceMappingURL=PlanetMaterial-B1_ZPlx5.js.map
589
+ //# sourceMappingURL=PlanetMaterial-Cs-_x6vr.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PlanetMaterial-B1_ZPlx5.js","sources":["../../../src/engine/terrain/PlanetMaterial.js"],"sourcesContent":["import { TERRAIN_CLOUD_SHADOW_GLSL } from '../sky/CloudShadowPass.js';\nimport { installSurfaceMaterialBackend } from './surface/SurfaceArrayGLSL.js';\nimport * as THREE from 'three';\nimport {\n COMMON_UNIFORMS_GLSL,\n MANUAL_SURFACE_WEIGHTS_GLSL,\n NOISE_GLSL,\n WATER_DEPTH_PULL_GLSL,\n} from './terrainGLSL.js';\nimport { BIOME_GLSL } from './biomeGLSL.js';\nimport {\n PLANET_UNIFORMS_GLSL, PLANET_NOISE_GLSL, PLANET_CLIMATE_CACHE_GLSL, buildPlanetHeightGLSL,\n} from './planetGLSL.js';\nimport {\n PALETTE_UNIFORMS_GLSL,\n TERRAIN_COLOR_FUNCTIONS_GLSL,\n} from '../shaders/terrainColor.glsl.js';\nimport { TERRAIN_DETAIL_GLSL } from './TerrainDetailMaterial.js';\nimport {\n SURFACE_TEXTURE_UNIFORMS_GLSL,\n SURFACE_TEXTURE_FUNCTIONS_GLSL,\n} from './surface/terrainSurfaceTextureGLSL.js';\nimport { generateStackGLSL } from './noise/noiseStackCodegen.js';\nimport { defaultLegacyStack } from './noise/NoiseStack.js';\nimport {\n WATER_LIGHTING_UNIFORMS_GLSL,\n createWaterLightingUniforms,\n} from '../water/waterLightingGLSL.js';\n\nconst DEFAULT_STACK_GLSL = generateStackGLSL(defaultLegacyStack());\n\n// ============================================================================\n// Planet (cube-sphere) terrain shader. Shares the terrain uniform objects so\n// every style / palette / noise tweak applies in all modes.\n// - vertex: chunk grid local position -> unit cube point (via per-chunk face\n// basis) -> normalize() -> radial displacement by heightAt3D(dir); border\n// skirt vertices drop radially inward to hide LOD cracks.\n// - fragment: analytic tangent-frame normal from heightAt3D, biome color from\n// the shared palette, spherical-up lighting, exp2 fog.\n// ============================================================================\n\nconst buildVertex = (planetHeightGLSL) => /* glsl */ `\n${COMMON_UNIFORMS_GLSL}\n${PLANET_UNIFORMS_GLSL}\n${NOISE_GLSL}\n${BIOME_GLSL}\n${PLANET_NOISE_GLSL}\n${planetHeightGLSL}\n\nuniform float uSkirtDepth;\n\n// Per-chunk cube-face mapping: a local grid point (position.xz in [0,1])\n// becomes uFaceOrigin + position.x*uFaceU + position.z*uFaceV on the unit\n// cube, which is then projected to the sphere.\nuniform vec3 uFaceOrigin;\nuniform vec3 uFaceU;\nuniform vec3 uFaceV;\n\n#ifdef USE_INSTANCING\nattribute vec3 aFaceOrigin;\nattribute vec3 aFaceU;\nattribute vec3 aFaceV;\n#endif\n\nattribute float aSkirt;\nattribute float aLod;\nattribute float aMorph; // 1 on the shared per-LOD chunk grids (absent = 0)\n#ifdef USE_INSTANCING\nattribute float aMorphK; // per-chunk temporal geomorph factor, animated by PlanetWorld\n#endif\n\n// Temporal geomorph in face-grid space. Planet chunks are too large for\n// distance bands (a band would sit right in front of the camera), so the LOD\n// decisions stay exactly as before and PlanetWorld animates each LOD change:\n// the finer grid's odd vertices slide onto the coarser grid (aMorphK 0 -> 1)\n// before a coarsening swap, and back out (1 -> 0) after a refining swap. At\n// rest aMorphK is 0, so settled geometry is unchanged.\nuniform vec4 uLodGridSegments;\n\nvec2 planetMorphedGrid(vec2 grid) {\n#ifdef USE_INSTANCING\n if (aMorph < 0.5 || aLod > 2.5 || aMorphK <= 0.0) return grid;\n float segments = aLod < 0.5 ? uLodGridSegments.x : aLod < 1.5 ? uLodGridSegments.y : uLodGridSegments.z;\n float coarser = aLod < 0.5 ? uLodGridSegments.y : aLod < 1.5 ? uLodGridSegments.z : uLodGridSegments.w;\n if (abs(coarser * 2.0 - segments) > 0.5) return grid;\n vec2 index = floor(grid * segments + 0.5);\n return grid - mod(index, 2.0) / segments * clamp(aMorphK, 0.0, 1.0);\n#else\n return grid;\n#endif\n}\n\nvarying vec3 vDir;\nvarying vec3 vWorldPos;\nvarying float vLod;\nvarying float vSkirt;\n\nvoid main() {\n #ifdef USE_INSTANCING\n vec2 grid = planetMorphedGrid(position.xz);\n vec3 cube = aFaceOrigin + grid.x * aFaceU + grid.y * aFaceV;\n #else\n vec2 grid = planetMorphedGrid(position.xz);\n vec3 cube = uFaceOrigin + grid.x * uFaceU + grid.y * uFaceV;\n #endif\n vec3 dir = normalize(cube);\n\n float h = heightAt3D(dir);\n float r = uPlanetRadius + h - aSkirt * uSkirtDepth;\n vec3 wp = dir * r;\n\n vDir = dir;\n vWorldPos = wp;\n vLod = aLod;\n vSkirt = aSkirt;\n\n gl_Position = projectionMatrix * viewMatrix * vec4(wp, 1.0);\n}\n`;\n\nconst buildFragment = (planetHeightGLSL) => /* glsl */ `\nprecision highp float;\n\n${COMMON_UNIFORMS_GLSL}\n${TERRAIN_CLOUD_SHADOW_GLSL}\n${PLANET_UNIFORMS_GLSL}\n${NOISE_GLSL}\n${BIOME_GLSL}\n${PLANET_NOISE_GLSL}\n${planetHeightGLSL}\n${PLANET_CLIMATE_CACHE_GLSL}\n${PALETTE_UNIFORMS_GLSL}\n${TERRAIN_COLOR_FUNCTIONS_GLSL}\n${SURFACE_TEXTURE_UNIFORMS_GLSL}\n${MANUAL_SURFACE_WEIGHTS_GLSL}\n${SURFACE_TEXTURE_FUNCTIONS_GLSL}\n${TERRAIN_DETAIL_GLSL}\n\nuniform float uNormalStrength;\nuniform float uAO;\nuniform float uLodDebug;\nuniform float uMergeDebug;\nuniform samplerCube uPlanetHeightTex;\nuniform float uUsePlanetHeightTex;\n\nvarying vec3 vDir;\nvarying vec3 vWorldPos;\nvarying float vLod;\nvarying float vSkirt;\n\nconst vec3 LOD_COLORS[4] = vec3[4](\n vec3(0.90, 0.28, 0.30),\n vec3(0.96, 0.65, 0.14),\n vec3(0.96, 0.85, 0.04),\n vec3(0.23, 0.51, 0.96)\n);\n\n// Merge-debug ramp keyed off aLod (4..8 = quadtree fold tier): green (small\n// 2x2 fold) → yellow → orange → red → magenta (whole face).\nvec3 mergeTierColor(float vlod) {\n float t = clamp(vlod - 4.0, 0.0, 4.0);\n if (t < 1.0) return mix(vec3(0.18, 0.95, 0.45), vec3(0.95, 0.95, 0.15), t);\n else if (t < 2.0) return mix(vec3(0.95, 0.95, 0.15), vec3(0.98, 0.55, 0.10), t - 1.0);\n else if (t < 3.0) return mix(vec3(0.98, 0.55, 0.10), vec3(0.95, 0.20, 0.20), t - 2.0);\n else return mix(vec3(0.95, 0.20, 0.20), vec3(0.95, 0.20, 0.95), t - 3.0);\n}\n\nvec3 applyTerrainDetailNormalPlanet(vec3 n, vec3 nGeo, vec3 worldPos, vec3 t1, vec3 t2, float fade, float rockMask, float shoreMask) {\n float strength = uTerrainDetailNormalStrength * fade * (0.45 + 0.55 * terrainDetailQualityFactor());\n if (strength <= 0.0001) return n;\n float scale = uTerrainDetailScale * mix(0.55, 1.25, terrainDetailQualityFactor());\n float e = max(0.45, 0.55 / max(scale, 0.0001));\n float c = terrainDetailRelief(worldPos, nGeo, scale);\n float d1 = terrainDetailRelief(worldPos + t1 * e, nGeo, scale) - c;\n float d2 = terrainDetailRelief(worldPos + t2 * e, nGeo, scale) - c;\n float matStrength = strength * (0.55 + rockMask * 1.05 + shoreMask * 0.25);\n vec3 detailN = normalize(n - t1 * d1 * matStrength * 5.5 - t2 * d2 * matStrength * 5.5);\n return normalize(mix(n, detailN, terrainDetailEnabled()));\n}\n\nvoid main() {\n vec3 dir = normalize(vDir);\n\n // tangent basis around dir for analytic normals + finite differences\n vec3 ref = abs(dir.y) < 0.99 ? vec3(0.0, 1.0, 0.0) : vec3(1.0, 0.0, 0.0);\n vec3 t1 = normalize(cross(ref, dir));\n vec3 t2 = cross(dir, t1);\n\n float eps = uPlanetEps;\n vec3 dA = normalize(dir + t1 * eps);\n vec3 dB = normalize(dir + t2 * eps);\n\n // Stable packed bake: the centre fetch contains the exact geometric normal\n // and height; neighbour heights remain available for concavity AO.\n // The branch is on a uniform, so it stays coherent across the warp (a real\n // GPU saving, not just fewer ALU on paper).\n float hC, hA, hB;\n vec3 nGeo;\n if (uUsePlanetHeightTex > 0.5) {\n vec4 packedHeightNormal = textureLod(uPlanetHeightTex, dir, 0.0);\n hC = packedHeightNormal.a * uHeightScale;\n hA = textureLod(uPlanetHeightTex, dA, 0.0).a * uHeightScale;\n hB = textureLod(uPlanetHeightTex, dB, 0.0).a * uHeightScale;\n nGeo = normalize(packedHeightNormal.rgb * 2.0 - 1.0);\n } else {\n // One inlined copy of the 3D height graph: the three samples share a\n // loop whose bound the compiler cannot fold (uLoopGuard is always 0).\n vec3 samples = vec3(0.0);\n for (int sampleIndex = 0; sampleIndex < 3 + uLoopGuard; sampleIndex++) {\n vec3 sampleDir = sampleIndex == 1 ? dA : sampleIndex == 2 ? dB : dir;\n samples[sampleIndex] = heightAt3D(sampleDir);\n }\n hC = samples.x;\n hA = samples.y;\n hB = samples.z;\n vec3 pC = dir * (uPlanetRadius + hC);\n vec3 pA = dA * (uPlanetRadius + hA);\n vec3 pB = dB * (uPlanetRadius + hB);\n nGeo = normalize(cross(pA - pC, pB - pC));\n if (dot(nGeo, dir) < 0.0) nGeo = -nGeo;\n }\n\n // normal-strength tweak: lean the geometric normal toward/away from up\n float up = clamp(dot(nGeo, dir), 0.0, 1.0);\n vec3 n = normalize(mix(dir, nGeo, uNormalStrength));\n vec3 surfaceBaseNormal = n;\n\n Climate cl = planetCachedClimateAt(dir);\n BiomeWeights bw = biomeWeightsAt(cl);\n\n float slope = 1.0 - up;\n float hRel = length(vWorldPos) - uPlanetRadius - uSeaLevel;\n float h01 = hC / max(uHeightScale, 1e-3);\n\n if (uBiomeDebug > 0.5) {\n vec3 dbg = terrainBiomeDebugColor(bw, h01);\n float shade = 0.55 + 0.45 * max(dot(n, uSunDir), 0.0);\n gl_FragColor = vec4(pow(dbg * shade, vec3(1.0 / 2.2)), 1.0);\n return;\n }\n\n // Triplanar color-detail sampling: a flat vWorldPos.xz projection of the\n // sphere stretches toward the poles / vertical faces (same streaking the\n // water had); blend three axis planes by the normal so the grain is uniform.\n vec3 colP = vWorldPos;\n vec3 colBlend = abs(dir);\n colBlend /= max(colBlend.x + colBlend.y + colBlend.z, 1e-4);\n vec3 colSeed = vec3(uSeedOffset, uSeedOffset.x - uSeedOffset.y);\n\n float jitter = (cl.region - 0.5) * 0.8 + (vnoiseTri(colP * 0.045 + colSeed, colBlend) - 0.5) * 0.6;\n float detail = vnoiseTri(colP * 0.35 + colSeed.yzx, colBlend);\n float microN = vnoiseTri(colP * 0.9, colBlend);\n\n TerrainColorResult tc = computeTerrainAlbedo(cl, bw, hC, hRel, h01, slope, detail, jitter, microN);\n TerrainDetailResult td = applyTerrainDetailLayer(tc, cl, bw, vWorldPos, nGeo, hC, hRel, h01, slope, jitter);\n n = applyTerrainDetailNormalPlanet(n, nGeo, vWorldPos, t1, t2, td.fade, td.rockMask, td.shoreMask);\n\n if (uTerrainDetailDebug > 0.5) {\n vec3 dbg = vec3(0.0);\n if (uTerrainDetailDebug < 1.5) {\n dbg = vec3(clamp(slope * 2.4, 0.0, 1.0));\n } else if (uTerrainDetailDebug < 2.5) {\n dbg = mix(vec3(0.08, 0.10, 0.12), vec3(0.70, 0.72, 0.68), td.rockMask);\n } else if (uTerrainDetailDebug < 3.5) {\n dbg = mix(vec3(0.04, 0.08, 0.10), vec3(0.82, 0.68, 0.40), td.shoreMask);\n } else if (uTerrainDetailDebug < 4.5) {\n dbg = vec3(td.fade);\n } else if (uTerrainDetailDebug < 5.5) {\n dbg = vec3(td.detail);\n } else if (uTerrainDetailDebug < 6.5) {\n dbg = td.albedo;\n } else {\n dbg = n * 0.5 + 0.5;\n }\n gl_FragColor = vec4(pow(max(dbg, vec3(0.0)), vec3(1.0 / 2.2)), 1.0);\n return;\n }\n\n float dist = length(cameraPosition - vWorldPos);\n SurfaceTexResult surf = applySurfaceMaterials(\n td.albedo, n, surfaceBaseNormal, nGeo, vWorldPos, dist, tc, cl, bw, slope, hRel, h01, detail, jitter\n );\n surf.albedo = mix(td.albedo, surf.albedo, uSurfReveal);\n surf.normal = normalize(mix(n, surf.normal, uSurfReveal));\n surf.ao = mix(1.0, surf.ao, uSurfReveal);\n surf.rough = mix(0.8, surf.rough, uSurfReveal);\n surf.amount *= uSurfReveal;\n td.albedo = surf.albedo;\n n = surf.normal;\n\n // ambient occlusion from local concavity + low-altitude valleys\n float concave = clamp(((hA + hB) * 0.5 - hC) / (uHeightScale * 0.02 + 1.0), 0.0, 1.0);\n float valley = 1.0 - smoothstep(0.0, uHeightScale * 0.55, hC);\n float ao = (1.0 - uAO * (concave * 0.45 + valley * 0.22)) * surf.ao;\n ao = applyRidgeAccent(ao, (hC - (hA + hB) * 0.5) / (uHeightScale * 0.02 + 1.0));\n\n // spherical-up lighting (hemisphere term uses planet up = dir, not world +Y)\n vec3 viewDir = normalize(cameraPosition - vWorldPos);\n float diff = max(dot(n, uSunDir), 0.0);\n vec3 sunCol = uTerrainSunCol * uTerrainSunIntensity * (1.0 - terrainCloudShadow(vWorldPos));\n vec3 skyAmb = uTerrainSkyAmb * 0.50 * (up * 0.5 + 0.5);\n vec3 bounce = uTerrainBounce * 0.25 * (1.0 - up * 0.5);\n vec3 col = td.albedo * (sunCol * diff + skyAmb + bounce) * ao;\n\n float spec = pow(max(dot(reflect(-uSunDir, n), viewDir), 0.0), 32.0);\n float shoreSheen = 1.0 - smoothstep(0.0, max(tc.sandBand, 0.5), abs(hRel));\n float proceduralSheen = 1.0 - clamp(surf.amount, 0.0, 1.0);\n col += spec * (tc.snow * 0.30 + shoreSheen * 0.10 + bw.wetland * tc.flatness * 0.15) * proceduralSheen;\n if (surf.amount > 0.001) {\n float gloss = 1.0 - clamp(surf.rough, 0.0, 1.0);\n col += spec * gloss * gloss * surf.amount * 0.08 * max(uSunDir.y, 0.0);\n }\n\n if (uLodDebug > 0.5) {\n int li = int(clamp(vLod, 0.0, 3.0) + 0.5);\n col = mix(col, LOD_COLORS[li], 0.55);\n }\n\n if (uMergeDebug > 0.5 && vLod > 3.5) {\n col = mix(col, mergeTierColor(vLod), 0.55);\n }\n\n col *= 1.0 - vSkirt * 0.55;\n\n float fogF = 1.0 - exp(-uFogDensity * uFogDensity * dist * dist);\n col = mix(col, uFogColor, clamp(fogF, 0.0, 1.0));\n\n col = pow(col, vec3(1.0 / 2.2));\n gl_FragColor = vec4(col, 1.0);\n}\n`;\n\n// Minimal boot fragment for planet mode: height/normal + a simple banded\n// colour + spherical sun light + fog. Skips the palette/colour, surface-texture\n// and terrain-detail blocks so ANGLE's synchronous GLSL→HLSL translation is a\n// fraction of the full fragment's (the multi-second freeze on planet entry).\n// The full source is compiled in the background and swapped in place via\n// upgradePlanetMaterialSource — an instant program-cache hit.\nconst buildMinimalFragment = (planetHeightGLSL) => /* glsl */ `\nprecision highp float;\n\n${COMMON_UNIFORMS_GLSL}\n${TERRAIN_CLOUD_SHADOW_GLSL}\n${PLANET_UNIFORMS_GLSL}\n${NOISE_GLSL}\n${BIOME_GLSL}\n${PLANET_NOISE_GLSL}\n${planetHeightGLSL}\n${PALETTE_UNIFORMS_GLSL}\n\nuniform float uNormalStrength;\nuniform samplerCube uPlanetHeightTex;\nuniform float uUsePlanetHeightTex;\n\nvarying vec3 vDir;\nvarying vec3 vWorldPos;\nvarying float vSkirt;\n\nvoid main() {\n vec3 dir = normalize(vDir);\n\n vec3 ref = abs(dir.y) < 0.99 ? vec3(0.0, 1.0, 0.0) : vec3(1.0, 0.0, 0.0);\n vec3 t1 = normalize(cross(ref, dir));\n vec3 t2 = cross(dir, t1);\n\n float eps = uPlanetEps;\n vec3 dA = normalize(dir + t1 * eps);\n vec3 dB = normalize(dir + t2 * eps);\n float hC;\n float hA;\n float hB;\n vec3 nGeo;\n if (uUsePlanetHeightTex > 0.5) {\n vec4 packedHeightNormal = textureLod(uPlanetHeightTex, dir, 0.0);\n hC = packedHeightNormal.a * uHeightScale;\n hA = textureLod(uPlanetHeightTex, dA, 0.0).a * uHeightScale;\n hB = textureLod(uPlanetHeightTex, dB, 0.0).a * uHeightScale;\n nGeo = normalize(packedHeightNormal.rgb * 2.0 - 1.0);\n } else {\n // One inlined copy of the 3D height graph: the three samples share a\n // loop whose bound the compiler cannot fold (uLoopGuard is always 0).\n vec3 samples = vec3(0.0);\n for (int sampleIndex = 0; sampleIndex < 3 + uLoopGuard; sampleIndex++) {\n vec3 sampleDir = sampleIndex == 1 ? dA : sampleIndex == 2 ? dB : dir;\n samples[sampleIndex] = heightAt3D(sampleDir);\n }\n hC = samples.x;\n hA = samples.y;\n hB = samples.z;\n vec3 pC = dir * (uPlanetRadius + hC);\n vec3 pA = dA * (uPlanetRadius + hA);\n vec3 pB = dB * (uPlanetRadius + hB);\n nGeo = normalize(cross(pA - pC, pB - pC));\n if (dot(nGeo, dir) < 0.0) nGeo = -nGeo;\n }\n\n float up = clamp(dot(nGeo, dir), 0.0, 1.0);\n vec3 n = normalize(mix(dir, nGeo, uNormalStrength));\n\n float slope = 1.0 - up;\n float h01 = clamp(hC / max(uHeightScale, 1e-3), 0.0, 1.0);\n float hRel = length(vWorldPos) - uPlanetRadius - uSeaLevel;\n\n // banded albedo from the REAL palette uniforms so the interim look already\n // matches the user's style (see TerrainMaterial buildMinimalFragment)\n vec3 albedo = mix(uColGrass, uColDryGrass, smoothstep(0.18, 0.45, h01));\n albedo = mix(albedo, uColRock, smoothstep(0.40, 0.75, h01));\n albedo = mix(albedo, uColRock, clamp(slope * 1.8, 0.0, 1.0) * 0.6);\n albedo = mix(albedo, uColRockHi, smoothstep(0.60, 0.85, h01) * (1.0 - slope));\n albedo = mix(albedo, uColSnow, smoothstep(uSnowLine - 0.08, uSnowLine + 0.06, h01 - slope * 0.25));\n albedo = mix(uColSand, albedo, smoothstep(0.0, 6.0, hRel));\n float luma = dot(albedo, vec3(0.299, 0.587, 0.114));\n albedo = max((mix(vec3(luma), albedo, uPaletteSaturation) - 0.5) * uPaletteContrast + 0.5, vec3(0.0)) * uPaletteTint;\n\n float diff = max(dot(n, uSunDir), 0.0);\n vec3 col = albedo * (uTerrainSunCol * uTerrainSunIntensity * diff * (1.0 - terrainCloudShadow(vWorldPos))\n + uTerrainSkyAmb * 0.50 * (up * 0.5 + 0.5)\n + uTerrainBounce * 0.25 * (1.0 - up * 0.5));\n\n col *= 1.0 - vSkirt * 0.55;\n\n float dist = length(cameraPosition - vWorldPos);\n float fogF = 1.0 - exp(-uFogDensity * uFogDensity * dist * dist);\n col = mix(col, uFogColor, clamp(fogF, 0.0, 1.0));\n gl_FragColor = vec4(pow(col, vec3(1.0 / 2.2)), 1.0);\n}\n`;\n\nfunction makeFaceUniforms() {\n return {\n uFaceOrigin: { value: new THREE.Vector3(-1, -1, 1) },\n uFaceU: { value: new THREE.Vector3(2, 0, 0) },\n uFaceV: { value: new THREE.Vector3(0, 2, 0) },\n };\n}\n\nexport function createPlanetMaterial(uniforms, octaves = 7, stackGLSL = DEFAULT_STACK_GLSL, { minimal = false } = {}) {\n const ph = buildPlanetHeightGLSL(stackGLSL.body3d);\n // Per-chunk face uniforms must NOT be shared — clone fresh ones, merged with\n // the shared terrain/palette uniform objects.\n const mat = new THREE.ShaderMaterial({\n uniforms: { ...uniforms, ...makeFaceUniforms() },\n defines: { OCTAVES: octaves, PLANET_MODE: 1 },\n vertexShader: buildVertex(ph),\n // `minimal` boots on the cheap fragment (fast ANGLE translation); the full\n // source is swapped in later via upgradePlanetMaterialSource.\n fragmentShader: minimal ? buildMinimalFragment(ph) : buildFragment(ph),\n // analytic outward normal is computed in the shader, so two-sided shading\n // stays correct; matches the studio/infinite terrain materials.\n side: THREE.DoubleSide,\n });\n mat.userData.minimalFragment = minimal;\n return installSurfaceMaterialBackend(mat);\n}\n\n// Upgrade a live minimal-fragment planet material to the full shader source in\n// place. The identical full program must have been warm-compiled first so the\n// relink is served from three's program cache (no freeze). All planet chunk\n// materials share one program, so flipping each one's source is free after the\n// first.\nexport function rebuildPlanetMaterialSource(\n mat, stackGLSL = DEFAULT_STACK_GLSL, { minimal = mat?.userData?.minimalFragment === true } = {},\n) {\n const ph = buildPlanetHeightGLSL(stackGLSL.body3d);\n mat.vertexShader = buildVertex(ph);\n mat.fragmentShader = minimal ? buildMinimalFragment(ph) : buildFragment(ph);\n mat.userData.minimalFragment = minimal;\n mat.needsUpdate = true;\n}\n\nexport function upgradePlanetMaterialSource(mat, stackGLSL = DEFAULT_STACK_GLSL) {\n rebuildPlanetMaterialSource(mat, stackGLSL, { minimal: false });\n}\n\n// ============================================================================\n// Planet water: a sphere shell at radius (planetRadius + seaLevel). The\n// fragment uses the exact terrain height field as its wet/dry mask, so ocean\n// visibility, depth shading, and shoreline foam share one coastline authority.\n// ============================================================================\n\nconst WATER_VERTEX = /* glsl */ `\n${WATER_DEPTH_PULL_GLSL}\nvarying vec3 vDir;\nvarying vec3 vWorldPos;\nvoid main() {\n vec4 wp = modelMatrix * vec4(position, 1.0);\n vWorldPos = wp.xyz;\n vDir = normalize(wp.xyz);\n gl_Position = waterClipPosition(wp);\n}\n`;\n\nconst buildWaterFragment = (planetHeightGLSL) => /* glsl */ `\nprecision highp float;\n\n${COMMON_UNIFORMS_GLSL}\n${PLANET_UNIFORMS_GLSL}\n${NOISE_GLSL}\n${BIOME_GLSL}\n${PLANET_NOISE_GLSL}\n${planetHeightGLSL}\n${PALETTE_UNIFORMS_GLSL}\n${WATER_LIGHTING_UNIFORMS_GLSL}\n\nuniform float uWaterAnim;\nuniform float uWaterQuality;\nuniform float uWaterDetail;\nuniform float uWaterReflection;\nuniform float uWaveComplexity;\nuniform float uFoamWidth;\nuniform samplerCube uPlanetHeightTex;\nuniform float uUsePlanetHeightTex;\n\nvarying vec3 vDir;\nvarying vec3 vWorldPos;\n\n// Triplanar value-noise ripple. Sampling by the 3D surface position and\n// blending the three axis planes by the surface normal keeps the wavelet\n// roughly uniform everywhere on the sphere — a single flat xz projection\n// stretches badly toward the poles and the \"vertical\" faces of the globe.\nfloat rippleTri(vec3 p, vec3 blend, float t) {\n vec2 oa = vec2(t * 0.6, t * 0.45);\n float h = vnoise(p.yz + oa) * blend.x\n + vnoise(p.zx + oa) * blend.y\n + vnoise(p.xy + oa) * blend.z;\n if (uWaterQuality > 0.5) {\n vec2 ob = vec2(t * 0.8, t * 0.3);\n h += 0.5 * uWaterDetail * (\n vnoise(p.yz * 2.7 - ob) * blend.x\n + vnoise(p.zx * 2.7 - ob) * blend.y\n + vnoise(p.xy * 2.7 - ob) * blend.z);\n }\n return h;\n}\n\nvoid main() {\n vec3 dir = normalize(vDir);\n\n // The terrain field is the wet/dry authority, matching the stable 1.0.0-b\n // planet coastline and keeping foam attached to the spherical relief.\n // Statement branch: the procedural field is skipped whenever the baked\n // cubemap is published.\n float terrainH;\n if (uUsePlanetHeightTex > 0.5) {\n terrainH = textureLod(uPlanetHeightTex, dir, 0.0).a * uHeightScale;\n } else {\n terrainH = heightAt3D(dir);\n }\n float terrainR = uPlanetRadius + terrainH;\n float waterR = uPlanetRadius + uSeaLevel;\n float depth = waterR - terrainR;\n if (depth <= 0.02) discard;\n\n // tangent frame around the local up (= dir)\n vec3 up = dir;\n vec3 ref = abs(up.y) < 0.99 ? vec3(0.0, 1.0, 0.0) : vec3(1.0, 0.0, 0.0);\n vec3 t1 = normalize(cross(ref, up));\n vec3 t2 = cross(up, t1);\n\n // triplanar blend weights from the surface normal (= local up)\n vec3 blend = abs(up);\n blend /= max(blend.x + blend.y + blend.z, 1e-4);\n\n float t = uTime * uWaterAnim;\n float scale = 0.055;\n vec3 wp = vWorldPos * scale;\n float e = 1.6 * scale;\n float r0 = rippleTri(wp, blend, t);\n float rX = rippleTri(wp + t1 * e, blend, t);\n float rZ = rippleTri(wp + t2 * e, blend, t);\n float nStr = 0.03 * uWaveComplexity;\n vec3 n = normalize(up - t1 * ((rX - r0) * nStr * 30.0) - t2 * ((rZ - r0) * nStr * 30.0));\n\n float dGrade = clamp(depth / 55.0, 0.0, 1.0);\n vec3 col = mix(uColShallow, uColDeep, dGrade);\n col = mix(vec3(dot(col, vec3(0.299, 0.587, 0.114))), col, uPaletteSaturation);\n col *= uPaletteTint;\n\n vec3 viewDir = normalize(cameraPosition - vWorldPos);\n float diff = max(dot(n, uSunDir), 0.0);\n vec3 legacyLight = vec3(0.55 + 0.65 * diff);\n vec3 resolvedLight = waterResolveLighting(\n n,\n up,\n diff,\n legacyLight\n );\n col *= resolvedLight;\n float spec = pow(max(dot(reflect(-uSunDir, n), viewDir), 0.0), 90.0);\n vec3 resolvedSunLight = waterResolveSunLight(vec3(1.0, 0.95, 0.85));\n col += resolvedSunLight * spec * 0.55 * uWaterReflection;\n\n // spherical fresnel: up is the local normal, not world +Y\n float fres = pow(1.0 - max(dot(viewDir, up), 0.0), 3.0);\n vec3 resolvedSkyLight = waterResolveSkyLight(vec3(0.30, 0.42, 0.55));\n col += resolvedSkyLight * fres * 0.25 * uWaterReflection;\n\n float foamNoise = 0.0;\n if (uWaterQuality > 0.5) {\n vec3 fp = vWorldPos * 0.22;\n vec2 fo = vec2(t * 1.4, -t * 1.1);\n foamNoise = vnoise(fp.yz + fo) * blend.x\n + vnoise(fp.zx + fo) * blend.y\n + vnoise(fp.xy + fo) * blend.z;\n }\n float shoreDistance = max(uFoamWidth, 0.5);\n float shoreInner = min(0.6, shoreDistance * 0.5);\n float foam = 1.0 - smoothstep(shoreInner, shoreDistance, depth + foamNoise * 2.4);\n vec3 litFoamColor = waterResolveFoamColor(uColFoam, resolvedLight);\n col = mix(col, litFoamColor, foam * 0.75);\n\n float alpha = clamp(0.50 + dGrade * 0.42 + fres * 0.15 + foam * 0.3, 0.0, 0.94);\n\n col = pow(col, vec3(1.0 / 2.2));\n gl_FragColor = vec4(col, alpha);\n}\n`;\n\nexport function createPlanetWaterMaterial(uniforms, octaves = 7, stackGLSL = DEFAULT_STACK_GLSL) {\n return new THREE.ShaderMaterial({\n uniforms: {\n ...uniforms,\n // water knobs are private (never shared with terrain)\n uWaterAnim: { value: 1.0 },\n uWaterQuality: { value: 2.0 },\n uWaterDetail: { value: 1.0 },\n uWaterReflection: { value: 1.0 },\n uWaveComplexity: { value: 1.0 },\n uFoamWidth: { value: 3.2 },\n ...createWaterLightingUniforms(),\n },\n defines: { OCTAVES: octaves, PLANET_MODE: 1 },\n vertexShader: WATER_VERTEX,\n fragmentShader: buildWaterFragment(buildPlanetHeightGLSL(stackGLSL.body3d)),\n transparent: true,\n depthTest: true,\n depthWrite: false,\n // Outer shell only: cull the inner (back) faces so the far hemisphere of\n // the ocean sphere isn't drawn behind the planet, and overdraw is halved.\n side: THREE.FrontSide,\n });\n}\n\nexport function rebuildPlanetWaterMaterialSource(mat, stackGLSL = DEFAULT_STACK_GLSL) {\n mat.fragmentShader = buildWaterFragment(buildPlanetHeightGLSL(stackGLSL.body3d));\n mat.needsUpdate = true;\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"PlanetMaterial-Cs-_x6vr.js","sources":["../../../src/engine/terrain/PlanetMaterial.js"],"sourcesContent":["import { TERRAIN_CLOUD_SHADOW_GLSL } from '../sky/CloudShadowPass.js';\nimport { installSurfaceMaterialBackend } from './surface/SurfaceArrayGLSL.js';\nimport * as THREE from 'three';\nimport {\n COMMON_UNIFORMS_GLSL,\n MANUAL_SURFACE_WEIGHTS_GLSL,\n NOISE_GLSL,\n WATER_DEPTH_PULL_GLSL,\n} from './terrainGLSL.js';\nimport { BIOME_GLSL } from './biomeGLSL.js';\nimport {\n PLANET_UNIFORMS_GLSL, PLANET_NOISE_GLSL, PLANET_CLIMATE_CACHE_GLSL, buildPlanetHeightGLSL,\n} from './planetGLSL.js';\nimport {\n PALETTE_UNIFORMS_GLSL,\n TERRAIN_COLOR_FUNCTIONS_GLSL,\n} from '../shaders/terrainColor.glsl.js';\nimport { TERRAIN_DETAIL_GLSL } from './TerrainDetailMaterial.js';\nimport {\n SURFACE_TEXTURE_UNIFORMS_GLSL,\n SURFACE_TEXTURE_FUNCTIONS_GLSL,\n} from './surface/terrainSurfaceTextureGLSL.js';\nimport { generateStackGLSL } from './noise/noiseStackCodegen.js';\nimport { defaultLegacyStack } from './noise/NoiseStack.js';\nimport {\n WATER_LIGHTING_UNIFORMS_GLSL,\n createWaterLightingUniforms,\n} from '../water/waterLightingGLSL.js';\n\nconst DEFAULT_STACK_GLSL = generateStackGLSL(defaultLegacyStack());\n\n// ============================================================================\n// Planet (cube-sphere) terrain shader. Shares the terrain uniform objects so\n// every style / palette / noise tweak applies in all modes.\n// - vertex: chunk grid local position -> unit cube point (via per-chunk face\n// basis) -> normalize() -> radial displacement by heightAt3D(dir); border\n// skirt vertices drop radially inward to hide LOD cracks.\n// - fragment: analytic tangent-frame normal from heightAt3D, biome color from\n// the shared palette, spherical-up lighting, exp2 fog.\n// ============================================================================\n\nconst buildVertex = (planetHeightGLSL) => /* glsl */ `\n${COMMON_UNIFORMS_GLSL}\n${PLANET_UNIFORMS_GLSL}\n${NOISE_GLSL}\n${BIOME_GLSL}\n${PLANET_NOISE_GLSL}\n${planetHeightGLSL}\n\nuniform float uSkirtDepth;\n\n// Per-chunk cube-face mapping: a local grid point (position.xz in [0,1])\n// becomes uFaceOrigin + position.x*uFaceU + position.z*uFaceV on the unit\n// cube, which is then projected to the sphere.\nuniform vec3 uFaceOrigin;\nuniform vec3 uFaceU;\nuniform vec3 uFaceV;\n\n#ifdef USE_INSTANCING\nattribute vec3 aFaceOrigin;\nattribute vec3 aFaceU;\nattribute vec3 aFaceV;\n#endif\n\nattribute float aSkirt;\nattribute float aLod;\nattribute float aMorph; // 1 on the shared per-LOD chunk grids (absent = 0)\n#ifdef USE_INSTANCING\nattribute float aMorphK; // per-chunk temporal geomorph factor, animated by PlanetWorld\n#endif\n\n// Temporal geomorph in face-grid space. Planet chunks are too large for\n// distance bands (a band would sit right in front of the camera), so the LOD\n// decisions stay exactly as before and PlanetWorld animates each LOD change:\n// the finer grid's odd vertices slide onto the coarser grid (aMorphK 0 -> 1)\n// before a coarsening swap, and back out (1 -> 0) after a refining swap. At\n// rest aMorphK is 0, so settled geometry is unchanged.\nuniform vec4 uLodGridSegments;\n\nvec2 planetMorphedGrid(vec2 grid) {\n#ifdef USE_INSTANCING\n if (aMorph < 0.5 || aLod > 2.5 || aMorphK <= 0.0) return grid;\n float segments = aLod < 0.5 ? uLodGridSegments.x : aLod < 1.5 ? uLodGridSegments.y : uLodGridSegments.z;\n float coarser = aLod < 0.5 ? uLodGridSegments.y : aLod < 1.5 ? uLodGridSegments.z : uLodGridSegments.w;\n if (abs(coarser * 2.0 - segments) > 0.5) return grid;\n vec2 index = floor(grid * segments + 0.5);\n return grid - mod(index, 2.0) / segments * clamp(aMorphK, 0.0, 1.0);\n#else\n return grid;\n#endif\n}\n\nvarying vec3 vDir;\nvarying vec3 vWorldPos;\nvarying float vLod;\nvarying float vSkirt;\n\nvoid main() {\n #ifdef USE_INSTANCING\n vec2 grid = planetMorphedGrid(position.xz);\n vec3 cube = aFaceOrigin + grid.x * aFaceU + grid.y * aFaceV;\n #else\n vec2 grid = planetMorphedGrid(position.xz);\n vec3 cube = uFaceOrigin + grid.x * uFaceU + grid.y * uFaceV;\n #endif\n vec3 dir = normalize(cube);\n\n float h = heightAt3D(dir);\n float r = uPlanetRadius + h - aSkirt * uSkirtDepth;\n vec3 wp = dir * r;\n\n vDir = dir;\n vWorldPos = wp;\n vLod = aLod;\n vSkirt = aSkirt;\n\n gl_Position = projectionMatrix * viewMatrix * vec4(wp, 1.0);\n}\n`;\n\nconst buildFragment = (planetHeightGLSL) => /* glsl */ `\nprecision highp float;\n\n${COMMON_UNIFORMS_GLSL}\n${TERRAIN_CLOUD_SHADOW_GLSL}\n${PLANET_UNIFORMS_GLSL}\n${NOISE_GLSL}\n${BIOME_GLSL}\n${PLANET_NOISE_GLSL}\n${planetHeightGLSL}\n${PLANET_CLIMATE_CACHE_GLSL}\n${PALETTE_UNIFORMS_GLSL}\n${TERRAIN_COLOR_FUNCTIONS_GLSL}\n${SURFACE_TEXTURE_UNIFORMS_GLSL}\n${MANUAL_SURFACE_WEIGHTS_GLSL}\n${SURFACE_TEXTURE_FUNCTIONS_GLSL}\n${TERRAIN_DETAIL_GLSL}\n\nuniform float uNormalStrength;\nuniform float uAO;\nuniform float uLodDebug;\nuniform float uMergeDebug;\nuniform samplerCube uPlanetHeightTex;\nuniform float uUsePlanetHeightTex;\n\nvarying vec3 vDir;\nvarying vec3 vWorldPos;\nvarying float vLod;\nvarying float vSkirt;\n\nconst vec3 LOD_COLORS[4] = vec3[4](\n vec3(0.90, 0.28, 0.30),\n vec3(0.96, 0.65, 0.14),\n vec3(0.96, 0.85, 0.04),\n vec3(0.23, 0.51, 0.96)\n);\n\n// Merge-debug ramp keyed off aLod (4..8 = quadtree fold tier): green (small\n// 2x2 fold) → yellow → orange → red → magenta (whole face).\nvec3 mergeTierColor(float vlod) {\n float t = clamp(vlod - 4.0, 0.0, 4.0);\n if (t < 1.0) return mix(vec3(0.18, 0.95, 0.45), vec3(0.95, 0.95, 0.15), t);\n else if (t < 2.0) return mix(vec3(0.95, 0.95, 0.15), vec3(0.98, 0.55, 0.10), t - 1.0);\n else if (t < 3.0) return mix(vec3(0.98, 0.55, 0.10), vec3(0.95, 0.20, 0.20), t - 2.0);\n else return mix(vec3(0.95, 0.20, 0.20), vec3(0.95, 0.20, 0.95), t - 3.0);\n}\n\nvec3 applyTerrainDetailNormalPlanet(vec3 n, vec3 nGeo, vec3 worldPos, vec3 t1, vec3 t2, float fade, float rockMask, float shoreMask) {\n float strength = uTerrainDetailNormalStrength * fade * (0.45 + 0.55 * terrainDetailQualityFactor());\n if (strength <= 0.0001) return n;\n float scale = uTerrainDetailScale * mix(0.55, 1.25, terrainDetailQualityFactor());\n float e = max(0.45, 0.55 / max(scale, 0.0001));\n float c = terrainDetailRelief(worldPos, nGeo, scale);\n float d1 = terrainDetailRelief(worldPos + t1 * e, nGeo, scale) - c;\n float d2 = terrainDetailRelief(worldPos + t2 * e, nGeo, scale) - c;\n float matStrength = strength * (0.55 + rockMask * 1.05 + shoreMask * 0.25);\n vec3 detailN = normalize(n - t1 * d1 * matStrength * 5.5 - t2 * d2 * matStrength * 5.5);\n return normalize(mix(n, detailN, terrainDetailEnabled()));\n}\n\nvoid main() {\n vec3 dir = normalize(vDir);\n\n // tangent basis around dir for analytic normals + finite differences\n vec3 ref = abs(dir.y) < 0.99 ? vec3(0.0, 1.0, 0.0) : vec3(1.0, 0.0, 0.0);\n vec3 t1 = normalize(cross(ref, dir));\n vec3 t2 = cross(dir, t1);\n\n float eps = uPlanetEps;\n vec3 dA = normalize(dir + t1 * eps);\n vec3 dB = normalize(dir + t2 * eps);\n\n // Stable packed bake: the centre fetch contains the exact geometric normal\n // and height; neighbour heights remain available for concavity AO.\n // The branch is on a uniform, so it stays coherent across the warp (a real\n // GPU saving, not just fewer ALU on paper).\n float hC, hA, hB;\n vec3 nGeo;\n if (uUsePlanetHeightTex > 0.5) {\n vec4 packedHeightNormal = textureLod(uPlanetHeightTex, dir, 0.0);\n hC = packedHeightNormal.a * uHeightScale;\n hA = textureLod(uPlanetHeightTex, dA, 0.0).a * uHeightScale;\n hB = textureLod(uPlanetHeightTex, dB, 0.0).a * uHeightScale;\n nGeo = normalize(packedHeightNormal.rgb * 2.0 - 1.0);\n } else {\n // One inlined copy of the 3D height graph: the three samples share a\n // loop whose bound the compiler cannot fold (uLoopGuard is always 0).\n vec3 samples = vec3(0.0);\n for (int sampleIndex = 0; sampleIndex < 3 + uLoopGuard; sampleIndex++) {\n vec3 sampleDir = sampleIndex == 1 ? dA : sampleIndex == 2 ? dB : dir;\n samples[sampleIndex] = heightAt3D(sampleDir);\n }\n hC = samples.x;\n hA = samples.y;\n hB = samples.z;\n vec3 pC = dir * (uPlanetRadius + hC);\n vec3 pA = dA * (uPlanetRadius + hA);\n vec3 pB = dB * (uPlanetRadius + hB);\n nGeo = normalize(cross(pA - pC, pB - pC));\n if (dot(nGeo, dir) < 0.0) nGeo = -nGeo;\n }\n\n // normal-strength tweak: lean the geometric normal toward/away from up\n float up = clamp(dot(nGeo, dir), 0.0, 1.0);\n vec3 n = normalize(mix(dir, nGeo, uNormalStrength));\n vec3 surfaceBaseNormal = n;\n\n Climate cl = planetCachedClimateAt(dir);\n BiomeWeights bw = biomeWeightsAt(cl);\n\n float slope = 1.0 - up;\n float hRel = length(vWorldPos) - uPlanetRadius - uSeaLevel;\n float h01 = hC / max(uHeightScale, 1e-3);\n\n if (uBiomeDebug > 0.5) {\n vec3 dbg = terrainBiomeDebugColor(bw, h01);\n float shade = 0.55 + 0.45 * max(dot(n, uSunDir), 0.0);\n gl_FragColor = vec4(pow(dbg * shade, vec3(1.0 / 2.2)), 1.0);\n return;\n }\n\n // Triplanar color-detail sampling: a flat vWorldPos.xz projection of the\n // sphere stretches toward the poles / vertical faces (same streaking the\n // water had); blend three axis planes by the normal so the grain is uniform.\n vec3 colP = vWorldPos;\n vec3 colBlend = abs(dir);\n colBlend /= max(colBlend.x + colBlend.y + colBlend.z, 1e-4);\n vec3 colSeed = vec3(uSeedOffset, uSeedOffset.x - uSeedOffset.y);\n\n float jitter = (cl.region - 0.5) * 0.8 + (vnoiseTri(colP * 0.045 + colSeed, colBlend) - 0.5) * 0.6;\n float detail = vnoiseTri(colP * 0.35 + colSeed.yzx, colBlend);\n float microN = vnoiseTri(colP * 0.9, colBlend);\n\n TerrainColorResult tc = computeTerrainAlbedo(cl, bw, hC, hRel, h01, slope, detail, jitter, microN);\n TerrainDetailResult td = applyTerrainDetailLayer(tc, cl, bw, vWorldPos, nGeo, hC, hRel, h01, slope, jitter);\n n = applyTerrainDetailNormalPlanet(n, nGeo, vWorldPos, t1, t2, td.fade, td.rockMask, td.shoreMask);\n\n if (uTerrainDetailDebug > 0.5) {\n vec3 dbg = vec3(0.0);\n if (uTerrainDetailDebug < 1.5) {\n dbg = vec3(clamp(slope * 2.4, 0.0, 1.0));\n } else if (uTerrainDetailDebug < 2.5) {\n dbg = mix(vec3(0.08, 0.10, 0.12), vec3(0.70, 0.72, 0.68), td.rockMask);\n } else if (uTerrainDetailDebug < 3.5) {\n dbg = mix(vec3(0.04, 0.08, 0.10), vec3(0.82, 0.68, 0.40), td.shoreMask);\n } else if (uTerrainDetailDebug < 4.5) {\n dbg = vec3(td.fade);\n } else if (uTerrainDetailDebug < 5.5) {\n dbg = vec3(td.detail);\n } else if (uTerrainDetailDebug < 6.5) {\n dbg = td.albedo;\n } else {\n dbg = n * 0.5 + 0.5;\n }\n gl_FragColor = vec4(pow(max(dbg, vec3(0.0)), vec3(1.0 / 2.2)), 1.0);\n return;\n }\n\n float dist = length(cameraPosition - vWorldPos);\n SurfaceTexResult surf = applySurfaceMaterials(\n td.albedo, n, surfaceBaseNormal, nGeo, vWorldPos, dist, tc, cl, bw, slope, hRel, h01, detail, jitter\n );\n surf.albedo = mix(td.albedo, surf.albedo, uSurfReveal);\n surf.normal = normalize(mix(n, surf.normal, uSurfReveal));\n surf.ao = mix(1.0, surf.ao, uSurfReveal);\n surf.rough = mix(0.8, surf.rough, uSurfReveal);\n surf.amount *= uSurfReveal;\n td.albedo = surf.albedo;\n n = surf.normal;\n\n // ambient occlusion from local concavity + low-altitude valleys\n float concave = clamp(((hA + hB) * 0.5 - hC) / (uHeightScale * 0.02 + 1.0), 0.0, 1.0);\n float valley = 1.0 - smoothstep(0.0, uHeightScale * 0.55, hC);\n float ao = (1.0 - uAO * (concave * 0.45 + valley * 0.22)) * surf.ao;\n ao = applyRidgeAccent(ao, (hC - (hA + hB) * 0.5) / (uHeightScale * 0.02 + 1.0));\n\n // spherical-up lighting (hemisphere term uses planet up = dir, not world +Y)\n vec3 viewDir = normalize(cameraPosition - vWorldPos);\n float diff = max(dot(n, uSunDir), 0.0);\n vec3 sunCol = uTerrainSunCol * uTerrainSunIntensity * (1.0 - terrainCloudShadow(vWorldPos));\n vec3 skyAmb = uTerrainSkyAmb * 0.50 * (up * 0.5 + 0.5);\n vec3 bounce = uTerrainBounce * 0.25 * (1.0 - up * 0.5);\n vec3 col = td.albedo * (sunCol * diff + skyAmb + bounce) * ao;\n\n float spec = pow(max(dot(reflect(-uSunDir, n), viewDir), 0.0), 32.0);\n float shoreSheen = 1.0 - smoothstep(0.0, max(tc.sandBand, 0.5), abs(hRel));\n float proceduralSheen = 1.0 - clamp(surf.amount, 0.0, 1.0);\n col += spec * (tc.snow * 0.30 + shoreSheen * 0.10 + bw.wetland * tc.flatness * 0.15) * proceduralSheen;\n if (surf.amount > 0.001) {\n float gloss = 1.0 - clamp(surf.rough, 0.0, 1.0);\n col += spec * gloss * gloss * surf.amount * 0.08 * max(uSunDir.y, 0.0);\n }\n\n if (uLodDebug > 0.5) {\n int li = int(clamp(vLod, 0.0, 3.0) + 0.5);\n col = mix(col, LOD_COLORS[li], 0.55);\n }\n\n if (uMergeDebug > 0.5 && vLod > 3.5) {\n col = mix(col, mergeTierColor(vLod), 0.55);\n }\n\n col *= 1.0 - vSkirt * 0.55;\n\n float fogF = 1.0 - exp(-uFogDensity * uFogDensity * dist * dist);\n col = mix(col, uFogColor, clamp(fogF, 0.0, 1.0));\n\n col = pow(col, vec3(1.0 / 2.2));\n gl_FragColor = vec4(col, 1.0);\n}\n`;\n\n// Minimal boot fragment for planet mode: height/normal + a simple banded\n// colour + spherical sun light + fog. Skips the palette/colour, surface-texture\n// and terrain-detail blocks so ANGLE's synchronous GLSL→HLSL translation is a\n// fraction of the full fragment's (the multi-second freeze on planet entry).\n// The full source is compiled in the background and swapped in place via\n// upgradePlanetMaterialSource — an instant program-cache hit.\nconst buildMinimalFragment = (planetHeightGLSL) => /* glsl */ `\nprecision highp float;\n\n${COMMON_UNIFORMS_GLSL}\n${TERRAIN_CLOUD_SHADOW_GLSL}\n${PLANET_UNIFORMS_GLSL}\n${NOISE_GLSL}\n${BIOME_GLSL}\n${PLANET_NOISE_GLSL}\n${planetHeightGLSL}\n${PALETTE_UNIFORMS_GLSL}\n\nuniform float uNormalStrength;\nuniform samplerCube uPlanetHeightTex;\nuniform float uUsePlanetHeightTex;\n\nvarying vec3 vDir;\nvarying vec3 vWorldPos;\nvarying float vSkirt;\n\nvoid main() {\n vec3 dir = normalize(vDir);\n\n vec3 ref = abs(dir.y) < 0.99 ? vec3(0.0, 1.0, 0.0) : vec3(1.0, 0.0, 0.0);\n vec3 t1 = normalize(cross(ref, dir));\n vec3 t2 = cross(dir, t1);\n\n float eps = uPlanetEps;\n vec3 dA = normalize(dir + t1 * eps);\n vec3 dB = normalize(dir + t2 * eps);\n float hC;\n float hA;\n float hB;\n vec3 nGeo;\n if (uUsePlanetHeightTex > 0.5) {\n vec4 packedHeightNormal = textureLod(uPlanetHeightTex, dir, 0.0);\n hC = packedHeightNormal.a * uHeightScale;\n hA = textureLod(uPlanetHeightTex, dA, 0.0).a * uHeightScale;\n hB = textureLod(uPlanetHeightTex, dB, 0.0).a * uHeightScale;\n nGeo = normalize(packedHeightNormal.rgb * 2.0 - 1.0);\n } else {\n // One inlined copy of the 3D height graph: the three samples share a\n // loop whose bound the compiler cannot fold (uLoopGuard is always 0).\n vec3 samples = vec3(0.0);\n for (int sampleIndex = 0; sampleIndex < 3 + uLoopGuard; sampleIndex++) {\n vec3 sampleDir = sampleIndex == 1 ? dA : sampleIndex == 2 ? dB : dir;\n samples[sampleIndex] = heightAt3D(sampleDir);\n }\n hC = samples.x;\n hA = samples.y;\n hB = samples.z;\n vec3 pC = dir * (uPlanetRadius + hC);\n vec3 pA = dA * (uPlanetRadius + hA);\n vec3 pB = dB * (uPlanetRadius + hB);\n nGeo = normalize(cross(pA - pC, pB - pC));\n if (dot(nGeo, dir) < 0.0) nGeo = -nGeo;\n }\n\n float up = clamp(dot(nGeo, dir), 0.0, 1.0);\n vec3 n = normalize(mix(dir, nGeo, uNormalStrength));\n\n float slope = 1.0 - up;\n float h01 = clamp(hC / max(uHeightScale, 1e-3), 0.0, 1.0);\n float hRel = length(vWorldPos) - uPlanetRadius - uSeaLevel;\n\n // banded albedo from the REAL palette uniforms so the interim look already\n // matches the user's style (see TerrainMaterial buildMinimalFragment)\n vec3 albedo = mix(uColGrass, uColDryGrass, smoothstep(0.18, 0.45, h01));\n albedo = mix(albedo, uColRock, smoothstep(0.40, 0.75, h01));\n albedo = mix(albedo, uColRock, clamp(slope * 1.8, 0.0, 1.0) * 0.6);\n albedo = mix(albedo, uColRockHi, smoothstep(0.60, 0.85, h01) * (1.0 - slope));\n albedo = mix(albedo, uColSnow, smoothstep(uSnowLine - 0.08, uSnowLine + 0.06, h01 - slope * 0.25));\n albedo = mix(uColSand, albedo, smoothstep(0.0, 6.0, hRel));\n float luma = dot(albedo, vec3(0.299, 0.587, 0.114));\n albedo = max((mix(vec3(luma), albedo, uPaletteSaturation) - 0.5) * uPaletteContrast + 0.5, vec3(0.0)) * uPaletteTint;\n\n float diff = max(dot(n, uSunDir), 0.0);\n vec3 col = albedo * (uTerrainSunCol * uTerrainSunIntensity * diff * (1.0 - terrainCloudShadow(vWorldPos))\n + uTerrainSkyAmb * 0.50 * (up * 0.5 + 0.5)\n + uTerrainBounce * 0.25 * (1.0 - up * 0.5));\n\n col *= 1.0 - vSkirt * 0.55;\n\n float dist = length(cameraPosition - vWorldPos);\n float fogF = 1.0 - exp(-uFogDensity * uFogDensity * dist * dist);\n col = mix(col, uFogColor, clamp(fogF, 0.0, 1.0));\n gl_FragColor = vec4(pow(col, vec3(1.0 / 2.2)), 1.0);\n}\n`;\n\nfunction makeFaceUniforms() {\n return {\n uFaceOrigin: { value: new THREE.Vector3(-1, -1, 1) },\n uFaceU: { value: new THREE.Vector3(2, 0, 0) },\n uFaceV: { value: new THREE.Vector3(0, 2, 0) },\n };\n}\n\nexport function createPlanetMaterial(uniforms, octaves = 7, stackGLSL = DEFAULT_STACK_GLSL, { minimal = false } = {}) {\n const ph = buildPlanetHeightGLSL(stackGLSL.body3d);\n // Per-chunk face uniforms must NOT be shared — clone fresh ones, merged with\n // the shared terrain/palette uniform objects.\n const mat = new THREE.ShaderMaterial({\n uniforms: { ...uniforms, ...makeFaceUniforms() },\n defines: { OCTAVES: octaves, PLANET_MODE: 1 },\n vertexShader: buildVertex(ph),\n // `minimal` boots on the cheap fragment (fast ANGLE translation); the full\n // source is swapped in later via upgradePlanetMaterialSource.\n fragmentShader: minimal ? buildMinimalFragment(ph) : buildFragment(ph),\n // analytic outward normal is computed in the shader, so two-sided shading\n // stays correct; matches the studio/infinite terrain materials.\n side: THREE.DoubleSide,\n });\n mat.userData.minimalFragment = minimal;\n return installSurfaceMaterialBackend(mat);\n}\n\n// Upgrade a live minimal-fragment planet material to the full shader source in\n// place. The identical full program must have been warm-compiled first so the\n// relink is served from three's program cache (no freeze). All planet chunk\n// materials share one program, so flipping each one's source is free after the\n// first.\nexport function rebuildPlanetMaterialSource(\n mat, stackGLSL = DEFAULT_STACK_GLSL, { minimal = mat?.userData?.minimalFragment === true } = {},\n) {\n const ph = buildPlanetHeightGLSL(stackGLSL.body3d);\n mat.vertexShader = buildVertex(ph);\n mat.fragmentShader = minimal ? buildMinimalFragment(ph) : buildFragment(ph);\n mat.userData.minimalFragment = minimal;\n mat.needsUpdate = true;\n}\n\nexport function upgradePlanetMaterialSource(mat, stackGLSL = DEFAULT_STACK_GLSL) {\n rebuildPlanetMaterialSource(mat, stackGLSL, { minimal: false });\n}\n\n// ============================================================================\n// Planet water: a sphere shell at radius (planetRadius + seaLevel). The\n// fragment uses the exact terrain height field as its wet/dry mask, so ocean\n// visibility, depth shading, and shoreline foam share one coastline authority.\n// ============================================================================\n\nconst WATER_VERTEX = /* glsl */ `\n${WATER_DEPTH_PULL_GLSL}\nvarying vec3 vDir;\nvarying vec3 vWorldPos;\nvoid main() {\n vec4 wp = modelMatrix * vec4(position, 1.0);\n vWorldPos = wp.xyz;\n vDir = normalize(wp.xyz);\n gl_Position = waterClipPosition(wp);\n}\n`;\n\nconst buildWaterFragment = (planetHeightGLSL) => /* glsl */ `\nprecision highp float;\n\n${COMMON_UNIFORMS_GLSL}\n${PLANET_UNIFORMS_GLSL}\n${NOISE_GLSL}\n${BIOME_GLSL}\n${PLANET_NOISE_GLSL}\n${planetHeightGLSL}\n${PALETTE_UNIFORMS_GLSL}\n${WATER_LIGHTING_UNIFORMS_GLSL}\n\nuniform float uWaterAnim;\nuniform float uWaterQuality;\nuniform float uWaterDetail;\nuniform float uWaterReflection;\nuniform float uWaveComplexity;\nuniform float uFoamWidth;\nuniform samplerCube uPlanetHeightTex;\nuniform float uUsePlanetHeightTex;\n\nvarying vec3 vDir;\nvarying vec3 vWorldPos;\n\n// Triplanar value-noise ripple. Sampling by the 3D surface position and\n// blending the three axis planes by the surface normal keeps the wavelet\n// roughly uniform everywhere on the sphere — a single flat xz projection\n// stretches badly toward the poles and the \"vertical\" faces of the globe.\nfloat rippleTri(vec3 p, vec3 blend, float t) {\n vec2 oa = vec2(t * 0.6, t * 0.45);\n float h = vnoise(p.yz + oa) * blend.x\n + vnoise(p.zx + oa) * blend.y\n + vnoise(p.xy + oa) * blend.z;\n if (uWaterQuality > 0.5) {\n vec2 ob = vec2(t * 0.8, t * 0.3);\n h += 0.5 * uWaterDetail * (\n vnoise(p.yz * 2.7 - ob) * blend.x\n + vnoise(p.zx * 2.7 - ob) * blend.y\n + vnoise(p.xy * 2.7 - ob) * blend.z);\n }\n return h;\n}\n\nvoid main() {\n vec3 dir = normalize(vDir);\n\n // The terrain field is the wet/dry authority, matching the stable 1.0.0-b\n // planet coastline and keeping foam attached to the spherical relief.\n // Statement branch: the procedural field is skipped whenever the baked\n // cubemap is published.\n float terrainH;\n if (uUsePlanetHeightTex > 0.5) {\n terrainH = textureLod(uPlanetHeightTex, dir, 0.0).a * uHeightScale;\n } else {\n terrainH = heightAt3D(dir);\n }\n float terrainR = uPlanetRadius + terrainH;\n float waterR = uPlanetRadius + uSeaLevel;\n float depth = waterR - terrainR;\n if (depth <= 0.02) discard;\n\n // tangent frame around the local up (= dir)\n vec3 up = dir;\n vec3 ref = abs(up.y) < 0.99 ? vec3(0.0, 1.0, 0.0) : vec3(1.0, 0.0, 0.0);\n vec3 t1 = normalize(cross(ref, up));\n vec3 t2 = cross(up, t1);\n\n // triplanar blend weights from the surface normal (= local up)\n vec3 blend = abs(up);\n blend /= max(blend.x + blend.y + blend.z, 1e-4);\n\n float t = uTime * uWaterAnim;\n float scale = 0.055;\n vec3 wp = vWorldPos * scale;\n float e = 1.6 * scale;\n float r0 = rippleTri(wp, blend, t);\n float rX = rippleTri(wp + t1 * e, blend, t);\n float rZ = rippleTri(wp + t2 * e, blend, t);\n float nStr = 0.03 * uWaveComplexity;\n vec3 n = normalize(up - t1 * ((rX - r0) * nStr * 30.0) - t2 * ((rZ - r0) * nStr * 30.0));\n\n float dGrade = clamp(depth / 55.0, 0.0, 1.0);\n vec3 col = mix(uColShallow, uColDeep, dGrade);\n col = mix(vec3(dot(col, vec3(0.299, 0.587, 0.114))), col, uPaletteSaturation);\n col *= uPaletteTint;\n\n vec3 viewDir = normalize(cameraPosition - vWorldPos);\n float diff = max(dot(n, uSunDir), 0.0);\n vec3 legacyLight = vec3(0.55 + 0.65 * diff);\n vec3 resolvedLight = waterResolveLighting(\n n,\n up,\n diff,\n legacyLight\n );\n col *= resolvedLight;\n float spec = pow(max(dot(reflect(-uSunDir, n), viewDir), 0.0), 90.0);\n vec3 resolvedSunLight = waterResolveSunLight(vec3(1.0, 0.95, 0.85));\n col += resolvedSunLight * spec * 0.55 * uWaterReflection;\n\n // spherical fresnel: up is the local normal, not world +Y\n float fres = pow(1.0 - max(dot(viewDir, up), 0.0), 3.0);\n vec3 resolvedSkyLight = waterResolveSkyLight(vec3(0.30, 0.42, 0.55));\n col += resolvedSkyLight * fres * 0.25 * uWaterReflection;\n\n float foamNoise = 0.0;\n if (uWaterQuality > 0.5) {\n vec3 fp = vWorldPos * 0.22;\n vec2 fo = vec2(t * 1.4, -t * 1.1);\n foamNoise = vnoise(fp.yz + fo) * blend.x\n + vnoise(fp.zx + fo) * blend.y\n + vnoise(fp.xy + fo) * blend.z;\n }\n float shoreDistance = max(uFoamWidth, 0.5);\n float shoreInner = min(0.6, shoreDistance * 0.5);\n float foam = 1.0 - smoothstep(shoreInner, shoreDistance, depth + foamNoise * 2.4);\n vec3 litFoamColor = waterResolveFoamColor(uColFoam, resolvedLight);\n col = mix(col, litFoamColor, foam * 0.75);\n\n float alpha = clamp(0.50 + dGrade * 0.42 + fres * 0.15 + foam * 0.3, 0.0, 0.94);\n\n col = pow(col, vec3(1.0 / 2.2));\n gl_FragColor = vec4(col, alpha);\n}\n`;\n\nexport function createPlanetWaterMaterial(uniforms, octaves = 7, stackGLSL = DEFAULT_STACK_GLSL) {\n return new THREE.ShaderMaterial({\n uniforms: {\n ...uniforms,\n // water knobs are private (never shared with terrain)\n uWaterAnim: { value: 1.0 },\n uWaterQuality: { value: 2.0 },\n uWaterDetail: { value: 1.0 },\n uWaterReflection: { value: 1.0 },\n uWaveComplexity: { value: 1.0 },\n uFoamWidth: { value: 3.2 },\n ...createWaterLightingUniforms(),\n },\n defines: { OCTAVES: octaves, PLANET_MODE: 1 },\n vertexShader: WATER_VERTEX,\n fragmentShader: buildWaterFragment(buildPlanetHeightGLSL(stackGLSL.body3d)),\n transparent: true,\n depthTest: true,\n depthWrite: false,\n // Outer shell only: cull the inner (back) faces so the far hemisphere of\n // the ocean sphere isn't drawn behind the planet, and overdraw is halved.\n side: THREE.FrontSide,\n });\n}\n\nexport function rebuildPlanetWaterMaterialSource(mat, stackGLSL = DEFAULT_STACK_GLSL) {\n mat.fragmentShader = buildWaterFragment(buildPlanetHeightGLSL(stackGLSL.body3d));\n mat.needsUpdate = true;\n}\n"],"names":[],"mappings":"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"}
@@ -1,10 +1,10 @@
1
1
  import * as THREE from "three";
2
- import { b as buildChunkGeometry, s as setChunkBounds, a as stepTemporalLod, F as FiniteTerrain } from "./FiniteTerrain-B34WMz5S.js";
2
+ import { b as buildChunkGeometry, s as setChunkBounds, a as stepTemporalLod, F as FiniteTerrain } from "./FiniteTerrain-B5_3y6xX.js";
3
3
  import { P as PlanetHeightSampler } from "./PlanetHeightSampler-CVP8-zSR.js";
4
- import { C as COMMON_UNIFORMS_GLSL, N as NOISE_GLSL, B as BIOME_GLSL } from "./biomeGLSL-CIkhxIlH.js";
5
- import { P as PLANET_UNIFORMS_GLSL, a as PLANET_NOISE_GLSL, d as PLANET_CLIMATE_GLSL, b as buildPlanetHeightGLSL } from "./planetGLSL-2xas0f3o.js";
4
+ import { C as COMMON_UNIFORMS_GLSL, N as NOISE_GLSL, B as BIOME_GLSL } from "./biomeGLSL-DWGDDBqT.js";
5
+ import { P as PLANET_UNIFORMS_GLSL, a as PLANET_NOISE_GLSL, d as PLANET_CLIMATE_GLSL, b as buildPlanetHeightGLSL } from "./planetGLSL-D9Zy2IAw.js";
6
6
  import { g as generateStackGLSL, d as defaultLegacyStack } from "./noiseStackCodegen-C4R9Y3L8.js";
7
- import { c as createPlanetMaterial } from "./PlanetMaterial-B1_ZPlx5.js";
7
+ import { c as createPlanetMaterial } from "./PlanetMaterial-Cs-_x6vr.js";
8
8
  import { c as compileMaterial } from "./CompileMaterial-DZiWxNZC.js";
9
9
  import { w as withRendererState } from "./RendererState-BwgUc9ze.js";
10
10
  const FACES = [
@@ -1180,4 +1180,4 @@ async function createPlanetTerrain(options) {
1180
1180
  export {
1181
1181
  createPlanetTerrain as c
1182
1182
  };
1183
- //# sourceMappingURL=PlanetTerrain-DCvxS1Q8.js.map
1183
+ //# sourceMappingURL=PlanetTerrain-Bsfx7YA6.js.map