@3driseai/3drise-core 1.0.19 → 1.0.21

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 (155) hide show
  1. package/dist/animations/index.d.ts +2 -0
  2. package/dist/animations/index.d.ts.map +1 -0
  3. package/dist/animations/index.js +1 -0
  4. package/dist/animations/trackGenerators.d.ts +140 -0
  5. package/dist/animations/trackGenerators.d.ts.map +1 -0
  6. package/dist/animations/trackGenerators.js +443 -0
  7. package/dist/autoAnimate/bounds.d.ts +7 -0
  8. package/dist/autoAnimate/bounds.d.ts.map +1 -0
  9. package/dist/autoAnimate/bounds.js +23 -0
  10. package/dist/autoAnimate/composer.d.ts +30 -0
  11. package/dist/autoAnimate/composer.d.ts.map +1 -0
  12. package/dist/autoAnimate/composer.js +251 -0
  13. package/dist/autoAnimate/describeScene.d.ts +105 -0
  14. package/dist/autoAnimate/describeScene.d.ts.map +1 -0
  15. package/dist/autoAnimate/describeScene.js +165 -0
  16. package/dist/autoAnimate/draft.d.ts +59 -0
  17. package/dist/autoAnimate/draft.d.ts.map +1 -0
  18. package/dist/autoAnimate/draft.js +2 -0
  19. package/dist/autoAnimate/index.d.ts +14 -0
  20. package/dist/autoAnimate/index.d.ts.map +1 -0
  21. package/dist/autoAnimate/index.js +9 -0
  22. package/dist/autoAnimate/recipes.d.ts +87 -0
  23. package/dist/autoAnimate/recipes.d.ts.map +1 -0
  24. package/dist/autoAnimate/recipes.js +224 -0
  25. package/dist/autoAnimate/rng.d.ts +10 -0
  26. package/dist/autoAnimate/rng.d.ts.map +1 -0
  27. package/dist/autoAnimate/rng.js +16 -0
  28. package/dist/autoAnimate/sceneAnalyzer.d.ts +7 -0
  29. package/dist/autoAnimate/sceneAnalyzer.d.ts.map +1 -0
  30. package/dist/autoAnimate/sceneAnalyzer.js +291 -0
  31. package/dist/autoAnimate/types.d.ts +124 -0
  32. package/dist/autoAnimate/types.d.ts.map +1 -0
  33. package/dist/autoAnimate/types.js +1 -0
  34. package/dist/autoAnimate/validator.d.ts +10 -0
  35. package/dist/autoAnimate/validator.d.ts.map +1 -0
  36. package/dist/autoAnimate/validator.js +59 -0
  37. package/dist/data/effectsDefaults.d.ts +4 -0
  38. package/dist/data/effectsDefaults.d.ts.map +1 -1
  39. package/dist/data/effectsDefaults.js +393 -2
  40. package/dist/data/gridsDefaults.d.ts +5 -0
  41. package/dist/data/gridsDefaults.d.ts.map +1 -0
  42. package/dist/data/gridsDefaults.js +419 -0
  43. package/dist/data/index.d.ts +1 -0
  44. package/dist/data/index.d.ts.map +1 -1
  45. package/dist/data/index.js +1 -0
  46. package/dist/data/particlesDefaults.d.ts +3 -1
  47. package/dist/data/particlesDefaults.d.ts.map +1 -1
  48. package/dist/data/particlesDefaults.js +78 -0
  49. package/dist/environment/cloudConfigs.d.ts +313 -0
  50. package/dist/environment/cloudConfigs.d.ts.map +1 -0
  51. package/dist/environment/cloudConfigs.js +342 -0
  52. package/dist/environment/index.d.ts +5 -0
  53. package/dist/environment/index.d.ts.map +1 -0
  54. package/dist/environment/index.js +6 -0
  55. package/dist/environment/landscapeConfigs.d.ts +220 -0
  56. package/dist/environment/landscapeConfigs.d.ts.map +1 -0
  57. package/dist/environment/landscapeConfigs.js +256 -0
  58. package/dist/environment/oceanConfigs.d.ts +293 -0
  59. package/dist/environment/oceanConfigs.d.ts.map +1 -0
  60. package/dist/environment/oceanConfigs.js +380 -0
  61. package/dist/environment/terrainConfigs.d.ts +254 -0
  62. package/dist/environment/terrainConfigs.d.ts.map +1 -0
  63. package/dist/environment/terrainConfigs.js +292 -0
  64. package/dist/index.d.ts +4 -0
  65. package/dist/index.d.ts.map +1 -1
  66. package/dist/index.js +4 -0
  67. package/dist/properties/index.d.ts +4 -0
  68. package/dist/properties/index.d.ts.map +1 -0
  69. package/dist/properties/index.js +3 -0
  70. package/dist/properties/registry.d.ts +44 -0
  71. package/dist/properties/registry.d.ts.map +1 -0
  72. package/dist/properties/registry.js +343 -0
  73. package/dist/properties/tables/effectsProperties.d.ts +40 -0
  74. package/dist/properties/tables/effectsProperties.d.ts.map +1 -0
  75. package/dist/properties/tables/effectsProperties.js +512 -0
  76. package/dist/properties/tables/geometryProperties.d.ts +38 -0
  77. package/dist/properties/tables/geometryProperties.d.ts.map +1 -0
  78. package/dist/properties/tables/geometryProperties.js +91 -0
  79. package/dist/properties/tables/getPropertyConfig.d.ts +3 -0
  80. package/dist/properties/tables/getPropertyConfig.d.ts.map +1 -0
  81. package/dist/properties/tables/getPropertyConfig.js +16 -0
  82. package/dist/properties/tables/gridProperties.d.ts +6 -0
  83. package/dist/properties/tables/gridProperties.d.ts.map +1 -0
  84. package/dist/properties/tables/gridProperties.js +199 -0
  85. package/dist/properties/tables/index.d.ts +8 -0
  86. package/dist/properties/tables/index.d.ts.map +1 -0
  87. package/dist/properties/tables/index.js +7 -0
  88. package/dist/properties/tables/lightProperties.d.ts +14 -0
  89. package/dist/properties/tables/lightProperties.d.ts.map +1 -0
  90. package/dist/properties/tables/lightProperties.js +263 -0
  91. package/dist/properties/tables/materialBounds.d.ts +33 -0
  92. package/dist/properties/tables/materialBounds.d.ts.map +1 -0
  93. package/dist/properties/tables/materialBounds.js +180 -0
  94. package/dist/properties/tables/optionalProperties.d.ts +83 -0
  95. package/dist/properties/tables/optionalProperties.d.ts.map +1 -0
  96. package/dist/properties/tables/optionalProperties.js +710 -0
  97. package/dist/properties/tables/particlesProperties.d.ts +17 -0
  98. package/dist/properties/tables/particlesProperties.d.ts.map +1 -0
  99. package/dist/properties/tables/particlesProperties.js +334 -0
  100. package/dist/properties/types.d.ts +43 -0
  101. package/dist/properties/types.d.ts.map +1 -0
  102. package/dist/properties/types.js +12 -0
  103. package/dist/services/ShadersLibrary.d.ts +1 -1
  104. package/dist/services/ShadersLibrary.d.ts.map +1 -1
  105. package/dist/shaders/ApollonianGridMaterial.d.ts +70 -0
  106. package/dist/shaders/ApollonianGridMaterial.d.ts.map +1 -0
  107. package/dist/shaders/ApollonianGridMaterial.js +289 -0
  108. package/dist/shaders/ConformalGridMaterial.d.ts +91 -0
  109. package/dist/shaders/ConformalGridMaterial.d.ts.map +1 -0
  110. package/dist/shaders/ConformalGridMaterial.js +335 -0
  111. package/dist/shaders/HilbertGridMaterial.d.ts +79 -0
  112. package/dist/shaders/HilbertGridMaterial.d.ts.map +1 -0
  113. package/dist/shaders/HilbertGridMaterial.js +329 -0
  114. package/dist/shaders/LensingGridMaterial.d.ts +73 -0
  115. package/dist/shaders/LensingGridMaterial.d.ts.map +1 -0
  116. package/dist/shaders/LensingGridMaterial.js +253 -0
  117. package/dist/shaders/ParastichyGridMaterial.d.ts +76 -0
  118. package/dist/shaders/ParastichyGridMaterial.d.ts.map +1 -0
  119. package/dist/shaders/ParastichyGridMaterial.js +282 -0
  120. package/dist/shaders/PhyllotaxisGridMaterial.d.ts +85 -0
  121. package/dist/shaders/PhyllotaxisGridMaterial.d.ts.map +1 -0
  122. package/dist/shaders/PhyllotaxisGridMaterial.js +532 -0
  123. package/dist/shaders/TruchetGridMaterial.d.ts +76 -0
  124. package/dist/shaders/TruchetGridMaterial.d.ts.map +1 -0
  125. package/dist/shaders/TruchetGridMaterial.js +290 -0
  126. package/dist/shaders/WallpaperGridMaterial.d.ts.map +1 -1
  127. package/dist/shaders/WallpaperGridMaterial.js +6 -1
  128. package/dist/shaders/index.d.ts +7 -0
  129. package/dist/shaders/index.d.ts.map +1 -1
  130. package/dist/shaders/index.js +7 -0
  131. package/dist/three/GalleryLayoutV.d.ts.map +1 -1
  132. package/dist/three/GalleryLayoutV.js +0 -10
  133. package/dist/three/SceneBuilderV.d.ts.map +1 -1
  134. package/dist/three/SceneBuilderV.js +1 -7
  135. package/dist/types/generativeEffects.d.ts +0 -4
  136. package/dist/types/generativeEffects.d.ts.map +1 -1
  137. package/dist/types/generativeParticles.d.ts +175 -2
  138. package/dist/types/generativeParticles.d.ts.map +1 -1
  139. package/dist/types/objectSettings.d.ts +45 -4
  140. package/dist/types/objectSettings.d.ts.map +1 -1
  141. package/dist/types/scene3d.d.ts +3 -3
  142. package/dist/types/scene3d.d.ts.map +1 -1
  143. package/dist/utils/generativeAnimatable.d.ts +1 -1
  144. package/dist/utils/generativeAnimatable.d.ts.map +1 -1
  145. package/dist/utils/generativeAnimatable.js +7 -1
  146. package/dist/utils/getAnimatableProperties.d.ts +12 -1
  147. package/dist/utils/getAnimatableProperties.d.ts.map +1 -1
  148. package/dist/utils/getAnimatableProperties.js +35 -138
  149. package/dist/utils/index.d.ts +1 -0
  150. package/dist/utils/index.d.ts.map +1 -1
  151. package/dist/utils/index.js +1 -0
  152. package/dist/utils/objectEffects.d.ts +6 -0
  153. package/dist/utils/objectEffects.d.ts.map +1 -0
  154. package/dist/utils/objectEffects.js +5 -0
  155. package/package.json +1 -1
@@ -0,0 +1,263 @@
1
+ // Property table (moved from the client). The registry (../registry.ts) is built on these tables.
2
+ // =============================================================================
3
+ // lightProperties — the knobs LightControllerUi shows, per light type
4
+ // =============================================================================
5
+ //
6
+ // OptionalProperty arrays in the same shape as PARTICLES_PROPERTIES, so the
7
+ // light panel renders with BaseControllerUi's PropertiesTab / ColorsTab and
8
+ // looks like every other controller.
9
+ //
10
+ // `tab` groups a knob; only the bulb has more than one ('light' + 'bulb').
11
+ // LIGHT_DEFAULTS fills in a knob a saved config does not carry yet (every
12
+ // light saved before the bulb existed has no `temperature`, for one), so the
13
+ // control still shows instead of silently disappearing.
14
+ //
15
+ import { DEFAULT_LIGHTS } from '../../data/lightsDefaults.js';
16
+ const enabled = { name: 'enabled', label: 'Enabled', type: 'boolean', description: 'Switch the light off without deleting it' };
17
+ const color = { name: 'color', type: 'color', description: 'Light colour' };
18
+ const intensity = (max) => ({ name: 'intensity', type: 'number', min: 0, max, step: 0.01, description: 'Brightness of the light' });
19
+ const distance = { name: 'distance', type: 'number', min: 0, max: 100, step: 0.1, description: 'Range of the light. 0 = unlimited' };
20
+ const decay = { name: 'decay', type: 'number', min: 0, max: 2, step: 0.01, description: 'How fast the light dims with distance. 2 is physically correct' };
21
+ export const LIGHT_PROPERTIES = {
22
+ ambient: [enabled, intensity(5), color],
23
+ directional: [enabled, intensity(10), color],
24
+ point: [enabled, intensity(20), distance, decay, color],
25
+ spot: [
26
+ enabled, intensity(20), distance, decay,
27
+ { name: 'angle', type: 'number', min: 0.01, max: Math.PI / 2, step: 0.01, description: 'Cone half-angle, radians' },
28
+ { name: 'penumbra', type: 'number', min: 0, max: 1, step: 0.01, description: 'Softness of the cone edge' },
29
+ color,
30
+ ],
31
+ lightBulb: [
32
+ // Light tab
33
+ { ...enabled, tab: 'light' },
34
+ { name: 'on', label: 'Power', type: 'boolean', tab: 'light', description: 'Switch the bulb on or off. Runs the warm-up / cool-down' },
35
+ { name: 'colorMode', label: 'Colour', type: 'select', tab: 'light', options: ['temperature', 'color'], optionLabels: ['Temperature', 'Custom colour'], description: 'Drive the colour from a Kelvin temperature, or pick one' },
36
+ { ...intensity(20), tab: 'light' },
37
+ { name: 'temperature', label: 'Temperature (K)', type: 'number', min: 1000, max: 10000, step: 50, tab: 'light', description: '2700K warm incandescent, 4000K neutral, 6500K daylight' },
38
+ { ...distance, tab: 'light' },
39
+ { ...decay, tab: 'light' },
40
+ { ...color, tab: 'light' },
41
+ // Bulb tab
42
+ { name: 'shape', type: 'select', tab: 'bulb', options: ['classic', 'globe', 'edison', 'tube'], optionLabels: ['Classic', 'Globe', 'Edison', 'Tube'], description: 'Glass silhouette and matching filament' },
43
+ { name: 'glass', type: 'select', tab: 'bulb', options: ['clear', 'frosted', 'tinted'], optionLabels: ['Clear', 'Frosted', 'Tinted'], description: 'Glass finish' },
44
+ { name: 'warmup', label: 'Warm-up (s)', type: 'number', min: 0, max: 3, step: 0.05, tab: 'bulb', description: 'Time for the filament to heat up. Cooling takes ~2.5x longer. 0 = instant' },
45
+ { name: 'flicker', type: 'number', min: 0, max: 1, step: 0.01, tab: 'bulb', description: 'Random dips in brightness' },
46
+ { name: 'halo', type: 'number', min: 0, max: 2, step: 0.01, tab: 'bulb', description: 'Strength of the glow around the bulb' },
47
+ { name: 'glassTint', label: 'Glass tint', type: 'color', tab: 'bulb', description: 'Glass colour when the glass is Tinted' },
48
+ ],
49
+ spotBeam: [
50
+ // Light tab
51
+ { ...enabled, tab: 'light' },
52
+ { name: 'on', label: 'Power', type: 'boolean', tab: 'light', description: 'Switch the lamp on or off. Runs the warm-up' },
53
+ { name: 'colorMode', label: 'Colour', type: 'select', tab: 'light', options: ['temperature', 'color'], optionLabels: ['Temperature', 'Custom colour'], description: 'Drive the colour from a Kelvin temperature, or pick one' },
54
+ { ...intensity(50), tab: 'light' },
55
+ { name: 'temperature', label: 'Temperature (K)', type: 'number', min: 1000, max: 10000, step: 50, tab: 'light', description: '3200K tungsten stage lamp, 5600K daylight' },
56
+ { name: 'angle', type: 'number', min: 0.01, max: Math.PI / 2, step: 0.01, tab: 'light', description: 'Cone half-angle, radians' },
57
+ { name: 'penumbra', type: 'number', min: 0, max: 1, step: 0.01, tab: 'light', description: 'Softness of the cone edge' },
58
+ { ...distance, tab: 'light' },
59
+ { ...decay, tab: 'light' },
60
+ { ...color, tab: 'light' },
61
+ // Beam tab
62
+ { name: 'pattern', label: 'Gobo', type: 'select', tab: 'beam', options: ['round', 'slot', 'bars', 'blinds', 'window', 'leaves'], optionLabels: ['Round', 'Slot', 'Bars', 'Blinds', 'Window', 'Leaves'], description: 'Shapes both the pool on the floor and the haze in the air' },
63
+ { name: 'patternSoftness', label: 'Gobo softness', type: 'number', min: 0, max: 1, step: 0.01, tab: 'beam', description: 'Edge softness of the gobo' },
64
+ { name: 'patternRotation', label: 'Gobo rotation', type: 'number', min: 0, max: Math.PI * 2, step: 0.01, tab: 'beam', description: 'Turns the gobo, radians' },
65
+ { name: 'beamMode', label: 'Beam quality', type: 'select', tab: 'beam', options: ['none', 'soft', 'layered', 'volumetric'], optionLabels: ['None', 'Soft', 'Layered', 'Volumetric'], description: 'How the beam in the air is drawn. Volumetric carries the gobo through the haze and costs the most' },
66
+ { name: 'beam', label: 'Beam', type: 'number', min: 0, max: 3, step: 0.01, tab: 'beam', description: 'Brightness of the beam in the air. 0 hides it' },
67
+ { name: 'beamLength', label: 'Beam length', type: 'number', min: 0.05, max: 1, step: 0.01, tab: 'beam', description: 'How far down the throw the beam reaches' },
68
+ { name: 'beamNoise', label: 'Haze', type: 'number', min: 0, max: 1, step: 0.01, tab: 'beam', description: 'Breakup in the beam, like smoke drifting through it' },
69
+ { name: 'beamSteps', label: 'Beam steps', type: 'number', min: 8, max: 48, step: 1, tab: 'beam', description: 'Raymarch samples for the Volumetric beam. Higher is smoother and slower' },
70
+ { name: 'emitter', label: 'Source', type: 'select', tab: 'beam', options: ['none', 'dot', 'lens'], optionLabels: ['Hidden', 'Dot', 'Lens'], description: 'The bit of visible geometry at the light itself' },
71
+ { name: 'warmup', label: 'Warm-up (s)', type: 'number', min: 0, max: 3, step: 0.05, tab: 'beam', description: 'Time for the lamp to come up to full. 0 = instant' },
72
+ { name: 'flicker', type: 'number', min: 0, max: 1, step: 0.01, tab: 'beam', description: 'Random dips in brightness' },
73
+ { name: 'halo', type: 'number', min: 0, max: 2, step: 0.01, tab: 'beam', description: 'Strength of the glow around the source' },
74
+ ],
75
+ ledArray: [
76
+ // Light tab
77
+ { ...enabled, tab: 'light' },
78
+ { name: 'on', label: 'Power', type: 'boolean', tab: 'light', description: 'Switch the array on or off. An LED has no thermal lag, so this is instant unless Warm-up says otherwise' },
79
+ { name: 'colorMode', label: 'Colour', type: 'select', tab: 'light', options: ['temperature', 'color', 'rgb'], optionLabels: ['Temperature', 'Custom colour', 'RGB'], description: 'Kelvin, one colour, or a hue running across the array' },
80
+ { ...intensity(40), tab: 'light' },
81
+ { name: 'temperature', label: 'Temperature (K)', type: 'number', min: 1800, max: 10000, step: 50, tab: 'light', description: '2700K warm white, 4000K neutral, 6500K cool daylight' },
82
+ { name: 'rgbSpread', label: 'Hue spread', type: 'number', min: 0, max: 2, step: 0.01, tab: 'light', description: 'How many turns of hue fit across the array' },
83
+ { name: 'rgbSpeed', label: 'Chase', type: 'number', min: -2, max: 2, step: 0.01, tab: 'light', description: 'How fast the hue runs along the array' },
84
+ { ...distance, tab: 'light' },
85
+ { ...decay, tab: 'light' },
86
+ { ...color, tab: 'light' },
87
+ // Array tab
88
+ { name: 'layout', type: 'select', tab: 'array', options: ['single', 'strip', 'panel', 'ring'], optionLabels: ['Single', 'Strip', 'Panel', 'Ring'], description: 'How the dies are arranged' },
89
+ { name: 'count', label: 'Dies', type: 'number', min: 1, max: 64, step: 1, tab: 'array', description: 'Dies along the main axis' },
90
+ { name: 'rows', type: 'number', min: 1, max: 12, step: 1, tab: 'array', description: 'Rows of dies. Panel only' },
91
+ { name: 'spacing', type: 'number', min: 0.005, max: 0.5, step: 0.005, tab: 'array', description: 'Distance between dies' },
92
+ { name: 'dieSize', label: 'Die size', type: 'number', min: 0.002, max: 0.1, step: 0.001, tab: 'array', description: 'Size of one die' },
93
+ { name: 'emitter', label: 'Source', type: 'select', tab: 'array', options: ['dies', 'none'], optionLabels: ['Dies', 'Hidden'], description: 'Hide the dies to leave only the light' },
94
+ { name: 'diffuser', type: 'number', min: 0, max: 1, step: 0.01, tab: 'array', description: 'Sheet over the dies. A bigger source, so it softens the shadow too' },
95
+ { name: 'pwm', label: 'PWM', type: 'number', min: 0, max: 1, step: 0.01, tab: 'array', description: 'The high-frequency chop a dimmed LED runs on. Reads as a slow strobe, the way a camera sees it' },
96
+ { name: 'warmup', label: 'Warm-up (s)', type: 'number', min: 0, max: 3, step: 0.05, tab: 'array', description: 'Fade-up time. 0 = instant, which is what an LED actually does' },
97
+ { name: 'flicker', type: 'number', min: 0, max: 1, step: 0.01, tab: 'array', description: 'Random dips in brightness' },
98
+ { name: 'halo', type: 'number', min: 0, max: 2, step: 0.01, tab: 'array', description: 'Strength of the glow around the array' },
99
+ ],
100
+ fluorescentTube: [
101
+ // Light tab
102
+ { ...enabled, tab: 'light' },
103
+ { name: 'on', label: 'Power', type: 'boolean', tab: 'light', description: 'Switch the fixture on or off' },
104
+ { name: 'colorMode', label: 'Colour', type: 'select', tab: 'light', options: ['temperature', 'color'], optionLabels: ['Temperature', 'Custom colour'], description: 'Drive the colour from a Kelvin temperature, or pick one' },
105
+ { ...intensity(60), tab: 'light' },
106
+ { name: 'temperature', label: 'Temperature (K)', type: 'number', min: 2700, max: 8000, step: 50, tab: 'light', description: '3000K warm white, 4000K cool white, 6500K daylight' },
107
+ { name: 'greenShift', label: 'Green spike', type: 'number', min: 0, max: 1, step: 0.01, tab: 'light', description: "The phosphor's green cast. Real halophosphate tubes read distinctly green next to daylight" },
108
+ { name: 'shadowStrength', label: 'Shadow core', type: 'number', min: 0, max: 1, step: 0.01, tab: 'light', description: 'Share of the output coming from a point at the middle of the fixture. A rect-area light cannot cast a shadow, so only this part does. 0 = pure soft area light, no shadow' },
109
+ { ...color, tab: 'light' },
110
+ // Tube tab
111
+ { name: 'tubes', type: 'number', min: 1, max: 4, step: 1, tab: 'tube', description: 'Tubes in the fixture' },
112
+ { name: 'tubeSpacing', label: 'Tube spacing', type: 'number', min: 0.02, max: 0.6, step: 0.005, tab: 'tube', description: 'Distance between tubes' },
113
+ { name: 'length', type: 'number', min: 0.1, max: 4, step: 0.05, tab: 'tube', description: 'Tube length' },
114
+ { name: 'diameter', type: 'number', min: 0.006, max: 0.12, step: 0.002, tab: 'tube', description: 'Tube diameter' },
115
+ { name: 'emitter', label: 'Source', type: 'select', tab: 'tube', options: ['tubes', 'none'], optionLabels: ['Tubes', 'Hidden'], description: 'Hide the tubes to leave only the light' },
116
+ { name: 'startup', type: 'select', tab: 'tube', options: ['instant', 'stutter'], optionLabels: ['Instant', 'Stutter'], description: 'Stutter strikes the arc with false starts first, the way a magnetic ballast does' },
117
+ { name: 'warmup', label: 'Warm-up (s)', type: 'number', min: 0, max: 5, step: 0.05, tab: 'tube', description: 'Time for the mercury vapour to reach full output' },
118
+ { name: 'hum', label: 'Ballast hum', type: 'number', min: 0, max: 1, step: 0.01, tab: 'tube', description: 'Depth of the 100 Hz ripple a magnetic ballast leaves in the light' },
119
+ { name: 'age', type: 'number', min: 0, max: 1, step: 0.01, tab: 'tube', description: 'Wear: dimmer, blackened ends, a longer strike and more flicker' },
120
+ // The rect-area light has neither; these govern the shadow core only.
121
+ { ...distance, tab: 'tube', description: 'Range of the shadow core. 0 = unlimited' },
122
+ { ...decay, tab: 'tube', description: 'How fast the shadow core dims with distance. 2 is physically correct' },
123
+ { name: 'flicker', type: 'number', min: 0, max: 1, step: 0.01, tab: 'tube', description: 'Random dips in brightness, on top of whatever Age adds' },
124
+ { name: 'halo', type: 'number', min: 0, max: 2, step: 0.01, tab: 'tube', description: 'Strength of the wash around the fixture' },
125
+ ],
126
+ candle: [
127
+ // Light tab
128
+ { ...enabled, tab: 'light' },
129
+ { name: 'on', label: 'Lit', type: 'boolean', tab: 'light', description: 'Lighting it runs the ignition; putting it out snuffs the flame and leaves a thread of smoke' },
130
+ { name: 'colorMode', label: 'Colour', type: 'select', tab: 'light', options: ['temperature', 'color'], optionLabels: ['Temperature', 'Custom colour'], description: 'Drive the colour from a Kelvin temperature, or pick one' },
131
+ { ...intensity(6), tab: 'light' },
132
+ { name: 'temperature', label: 'Temperature (K)', type: 'number', min: 1200, max: 3200, step: 10, tab: 'light', description: 'A candle is about 1850K' },
133
+ { ...distance, tab: 'light' },
134
+ { ...decay, tab: 'light' },
135
+ { ...color, tab: 'light' },
136
+ // Flame tab
137
+ { name: 'flameMode', label: 'Flame quality', type: 'select', tab: 'flame', options: ['volumetric', 'billboard'], optionLabels: ['Volumetric', 'Billboard'], description: 'Volumetric raymarches the flame, so it has real depth from every angle. Billboard is the same flame on one quad — for scenes full of candles' },
138
+ { name: 'flameHeight', label: 'Flame height', type: 'number', min: 0.008, max: 0.2, step: 0.001, tab: 'flame', description: 'A real candle flame is 3-6 cm' },
139
+ { name: 'flameWidth', label: 'Flame width', type: 'number', min: 0.2, max: 2, step: 0.01, tab: 'flame', description: 'Width relative to the height' },
140
+ { name: 'movement', type: 'number', min: 0, max: 1, step: 0.01, tab: 'flame', description: 'How much the flame moves at all. 0 holds it perfectly still — it can still flicker in brightness' },
141
+ { name: 'flicker', type: 'number', min: 0, max: 1, step: 0.01, tab: 'flame', description: 'Depth of the brightness dip. This is the light’s output, not its shape' },
142
+ { name: 'flickerHz', label: 'Flicker rate (Hz)', type: 'number', min: 4, max: 20, step: 0.1, tab: 'flame', description: 'Real candle flames oscillate near 11 Hz almost regardless of size' },
143
+ { name: 'draught', type: 'number', min: 0, max: 1, step: 0.01, tab: 'flame', description: 'Air movement: lean, stretch, turbulence, and guttering once it is strong' },
144
+ { name: 'blue', label: 'Blue base', type: 'number', min: 0, max: 1, step: 0.01, tab: 'flame', description: 'The blue cone at the wick, where there is plenty of oxygen' },
145
+ { name: 'blueBasePercentage', label: 'Blue base height', type: 'number', min: 0, max: 100, step: 1, tab: 'flame', description: 'How much of the flame’s height reads blue, as a percentage. Past about 40 it fills in rather than staying a collar' },
146
+ { name: 'soot', type: 'number', min: 0, max: 1, step: 0.01, tab: 'flame', description: 'How much the soot absorbs: gives the flame a body instead of a ghost' },
147
+ { name: 'flameSteps', label: 'Raymarch steps', type: 'number', min: 8, max: 40, step: 1, tab: 'flame', description: 'Volumetric only. Higher is smoother and slower' },
148
+ { name: 'flameGain', label: 'Flame gain', type: 'number', min: 1, max: 20, step: 0.1, tab: 'flame', description: 'Emission scale. Raise for a hotter, whiter flame' },
149
+ { name: 'flameWhite', label: 'White point', type: 'number', min: 1.5, max: 10, step: 0.1, tab: 'flame', description: 'Where the flame\u2019s own knee clips to white. Lower blows the core out sooner' },
150
+ { name: 'ignite', label: 'Ignition (s)', type: 'number', min: 0, max: 5, step: 0.05, tab: 'flame', description: 'Time for the wick to catch and the flame to establish. 0 = instant' },
151
+ { name: 'smoke', label: 'Smoke when snuffed', type: 'boolean', tab: 'flame', description: 'A thread of smoke for a few seconds after it goes out' },
152
+ { name: 'halo', type: 'number', min: 0, max: 2, step: 0.01, tab: 'flame', description: 'Strength of the wash around the flame' },
153
+ // Candle tab
154
+ { name: 'body', type: 'select', tab: 'candle', options: ['pillar', 'taper', 'tealight', 'none'], optionLabels: ['Pillar', 'Taper', 'Tealight', 'None'], description: 'None leaves the flame and the light on their own, to drop into your own candle' },
155
+ { name: 'height', type: 'number', min: 0.01, max: 1, step: 0.005, tab: 'candle', description: 'Candle height, before the body style\u2019s own proportions' },
156
+ { name: 'radius', type: 'number', min: 0.004, max: 0.15, step: 0.001, tab: 'candle', description: 'Candle radius' },
157
+ { name: 'melt', type: 'number', min: 0, max: 1, step: 0.01, tab: 'candle', description: 'How far it has burned down: the depth of the well round the wick' },
158
+ { name: 'waxGlow', label: 'Wax glow', type: 'number', min: 0, max: 1, step: 0.01, tab: 'candle', description: 'How much the wax is lit from inside' },
159
+ { name: 'waxColor', label: 'Wax colour', type: 'color', tab: 'candle', description: 'Wax colour' },
160
+ ],
161
+ };
162
+ /** Re-export under the name the controller already uses; the table itself lives in core. */
163
+ export const LIGHT_DEFAULTS = DEFAULT_LIGHTS;
164
+ /** Knobs hidden by another knob's value (colour vs temperature, tint only when tinted). */
165
+ export function isLightPropertyHidden(name, values) {
166
+ const type = values.type;
167
+ if (type === 'ledArray') {
168
+ const mode = values.colorMode ?? 'temperature';
169
+ if (name === 'color')
170
+ return mode !== 'color';
171
+ if (name === 'temperature')
172
+ return mode === 'rgb';
173
+ if (name === 'rgbSpread' || name === 'rgbSpeed')
174
+ return mode !== 'rgb';
175
+ if (name === 'rows')
176
+ return (values.layout ?? 'panel') !== 'panel';
177
+ if (name === 'count')
178
+ return (values.layout ?? 'panel') === 'single';
179
+ return false;
180
+ }
181
+ if (type === 'candle') {
182
+ const mode = values.colorMode ?? 'temperature';
183
+ if (name === 'color')
184
+ return mode !== 'color';
185
+ if (name === 'temperature')
186
+ return mode !== 'temperature';
187
+ // Only the raymarched flame has steps, and the wax knobs mean nothing
188
+ // when there is no wax.
189
+ if (name === 'flameSteps')
190
+ return (values.flameMode ?? 'volumetric') !== 'volumetric';
191
+ if (name === 'height' || name === 'radius' || name === 'melt' || name === 'waxGlow' || name === 'waxColor')
192
+ return (values.body ?? 'pillar') === 'none';
193
+ return false;
194
+ }
195
+ if (type === 'fluorescentTube') {
196
+ const mode = values.colorMode ?? 'temperature';
197
+ if (name === 'color')
198
+ return mode !== 'color';
199
+ if (name === 'temperature')
200
+ return mode !== 'temperature';
201
+ if (name === 'tubeSpacing')
202
+ return (typeof values.tubes === 'number' ? values.tubes : 1) < 2;
203
+ return false;
204
+ }
205
+ if (type !== 'lightBulb' && type !== 'spotBeam')
206
+ return false;
207
+ const mode = values.colorMode ?? 'temperature';
208
+ if (name === 'color')
209
+ return mode !== 'color';
210
+ if (name === 'temperature')
211
+ return mode !== 'temperature';
212
+ if (type === 'lightBulb') {
213
+ if (name === 'glassTint')
214
+ return (values.glass ?? 'clear') !== 'tinted';
215
+ return false;
216
+ }
217
+ // spotBeam: the beam knobs mean nothing with the beam off, and the step count
218
+ // only drives the raymarched mode.
219
+ const beamMode = values.beamMode ?? 'soft';
220
+ if (name === 'beamSteps')
221
+ return beamMode !== 'volumetric';
222
+ if (name === 'beam' || name === 'beamLength' || name === 'beamNoise')
223
+ return beamMode === 'none';
224
+ return false;
225
+ }
226
+ // -----------------------------------------------------------------------------
227
+ // Shadow
228
+ // -----------------------------------------------------------------------------
229
+ export const SHADOW_MAP_SIZES = ['256', '512', '1024', '2048', '4096'];
230
+ const common = [
231
+ { name: 'enabled', label: 'Cast shadows', type: 'boolean', description: 'A point light / bulb shadow costs six extra renders' },
232
+ { name: 'mapSize', label: 'Resolution', type: 'select', options: SHADOW_MAP_SIZES, description: 'Shadow map size. Higher is sharper and slower' },
233
+ { name: 'intensity', type: 'number', min: 0, max: 1, step: 0.01, description: 'How dark the shadow is' },
234
+ { name: 'radius', label: 'Softness', type: 'number', min: 0, max: 10, step: 0.1, description: 'Blur radius of the shadow edge (PCF shadows)' },
235
+ { name: 'bias', type: 'number', min: -0.01, max: 0.01, step: 0.0001, description: 'Fixes shadow acne. Too far and shadows detach from objects' },
236
+ { name: 'normalBias', label: 'Normal bias', type: 'number', min: 0, max: 0.1, step: 0.001, description: 'Acne fix along the surface normal; better on curved surfaces' },
237
+ { name: 'cameraNear', label: 'Near', type: 'number', min: 0.01, max: 10, step: 0.01, description: 'Closest distance that casts a shadow' },
238
+ { name: 'cameraFar', label: 'Far', type: 'number', min: 1, max: 1000, step: 1, description: 'Farthest distance that casts a shadow' },
239
+ ];
240
+ const spotShadow = [
241
+ ...common,
242
+ { name: 'cameraFov', label: 'Shadow FOV', type: 'number', min: 1, max: 120, step: 1, description: 'Field of view of the shadow camera' },
243
+ { name: 'focus', type: 'number', min: 0, max: 1, step: 0.01, description: 'Tightens the shadow camera around the cone' },
244
+ ];
245
+ export const SHADOW_PROPERTIES = {
246
+ ambient: [],
247
+ point: common,
248
+ lightBulb: common,
249
+ spot: spotShadow,
250
+ spotBeam: spotShadow,
251
+ ledArray: common,
252
+ candle: common,
253
+ // The shadow belongs to the point light at the fixture's centre, so the point
254
+ // light's settings are the ones that matter.
255
+ fluorescentTube: common,
256
+ directional: [
257
+ ...common,
258
+ { name: 'cameraLeft', label: 'Left', type: 'number', min: -200, max: 0, step: 1, description: 'Shadow area, left edge' },
259
+ { name: 'cameraRight', label: 'Right', type: 'number', min: 0, max: 200, step: 1, description: 'Shadow area, right edge' },
260
+ { name: 'cameraTop', label: 'Top', type: 'number', min: 0, max: 200, step: 1, description: 'Shadow area, top edge' },
261
+ { name: 'cameraBottom', label: 'Bottom', type: 'number', min: -200, max: 0, step: 1, description: 'Shadow area, bottom edge' },
262
+ ],
263
+ };
@@ -0,0 +1,33 @@
1
+ export interface MaterialPropertyBounds {
2
+ min: number;
3
+ max: number;
4
+ step: number;
5
+ label?: string;
6
+ accentColor?: 'cyan' | 'purple' | 'pink' | 'green' | 'yellow' | 'blue';
7
+ }
8
+ /**
9
+ * Known bounds for standard Three.js material properties.
10
+ * Used by MaterialControllerUi to render SliderControls with correct ranges.
11
+ *
12
+ * If a property is not in this map, it falls back to a sensible default (0–1, step 0.01).
13
+ */
14
+ export declare const MATERIAL_PROPERTY_BOUNDS: Record<string, MaterialPropertyBounds>;
15
+ /**
16
+ * Default bounds for unknown numeric properties.
17
+ */
18
+ export declare const DEFAULT_MATERIAL_BOUNDS: MaterialPropertyBounds;
19
+ /**
20
+ * Get bounds for a property, falling back to defaults.
21
+ */
22
+ export declare function getMaterialBounds(key: string): MaterialPropertyBounds;
23
+ /**
24
+ * Get a human-readable label for a property key.
25
+ * Uses the bounds label if available, otherwise converts camelCase to Title Case.
26
+ */
27
+ export declare function getMaterialPropertyLabel(key: string): string;
28
+ /**
29
+ * Generate random values for numeric and color properties within their bounds.
30
+ * Skips texture/mapping properties and internal fields.
31
+ */
32
+ export declare function generateRandomMaterialSettings(currentSettings: Record<string, any>): Record<string, any>;
33
+ //# sourceMappingURL=materialBounds.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"materialBounds.d.ts","sourceRoot":"","sources":["../../../src/properties/tables/materialBounds.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,sBAAsB;IACrC,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;CACxE;AAED;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,EAAE,MAAM,CAAC,MAAM,EAAE,sBAAsB,CA6H3E,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,uBAAuB,EAAE,sBAKrC,CAAC;AAEF;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,sBAAsB,CAErE;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAS5D;AAED;;;GAGG;AACH,wBAAgB,8BAA8B,CAC5C,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GACnC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAoCrB"}
@@ -0,0 +1,180 @@
1
+ // Property table (moved from the client). The registry (../registry.ts) is built on these tables.
2
+ // =============================================================================
3
+ // MATERIAL PROPERTY BOUNDS — Min/Max/Step for Slider Controls
4
+ // =============================================================================
5
+ /**
6
+ * Known bounds for standard Three.js material properties.
7
+ * Used by MaterialControllerUi to render SliderControls with correct ranges.
8
+ *
9
+ * If a property is not in this map, it falls back to a sensible default (0–1, step 0.01).
10
+ */
11
+ export const MATERIAL_PROPERTY_BOUNDS = {
12
+ // PBR core
13
+ roughness: { min: 0, max: 1, step: 0.01, label: 'Roughness', accentColor: 'cyan' },
14
+ metalness: { min: 0, max: 1, step: 0.01, label: 'Metalness', accentColor: 'blue' },
15
+ opacity: { min: 0, max: 1, step: 0.01, label: 'Opacity', accentColor: 'purple' },
16
+ // Phong
17
+ shininess: { min: 0, max: 100, step: 1, label: 'Shininess', accentColor: 'yellow' },
18
+ reflectivity: { min: 0, max: 1, step: 0.01, label: 'Reflectivity', accentColor: 'cyan' },
19
+ // Physical
20
+ clearcoat: { min: 0, max: 1, step: 0.01, label: 'Clearcoat', accentColor: 'cyan' },
21
+ clearcoatRoughness: { min: 0, max: 1, step: 0.01, label: 'Clearcoat Roughness', accentColor: 'blue' },
22
+ transmission: { min: 0, max: 1, step: 0.01, label: 'Transmission', accentColor: 'purple' },
23
+ ior: { min: 1, max: 2.5, step: 0.01, label: 'IOR', accentColor: 'pink' },
24
+ thickness: { min: 0, max: 5, step: 0.01, label: 'Thickness', accentColor: 'green' },
25
+ attenuationDistance: { min: 0, max: 100, step: 0.5, label: 'Attenuation Distance', accentColor: 'blue' },
26
+ sheen: { min: 0, max: 1, step: 0.01, label: 'Sheen', accentColor: 'pink' },
27
+ sheenRoughness: { min: 0, max: 1, step: 0.01, label: 'Sheen Roughness', accentColor: 'purple' },
28
+ specularIntensity: { min: 0, max: 2, step: 0.01, label: 'Specular Intensity', accentColor: 'yellow' },
29
+ iridescence: { min: 0, max: 1, step: 0.01, label: 'Iridescence', accentColor: 'pink' },
30
+ iridescenceIOR: { min: 1, max: 2.5, step: 0.01, label: 'Iridescence IOR', accentColor: 'purple' },
31
+ // Maps intensity
32
+ envMapIntensity: { min: 0, max: 5, step: 0.1, label: 'Env Map Intensity', accentColor: 'green' },
33
+ emissiveIntensity: { min: 0, max: 5, step: 0.1, label: 'Emissive Intensity', accentColor: 'yellow' },
34
+ aoMapIntensity: { min: 0, max: 2, step: 0.01, label: 'AO Map Intensity', accentColor: 'blue' },
35
+ bumpScale: { min: 0, max: 2, step: 0.01, label: 'Bump Scale', accentColor: 'cyan' },
36
+ displacementScale: { min: 0, max: 5, step: 0.01, label: 'Displacement Scale', accentColor: 'green' },
37
+ // Shader uniforms (common patterns)
38
+ uOpacity: { min: 0, max: 1, step: 0.01, label: 'Opacity', accentColor: 'purple' },
39
+ uPointSize: { min: 0.1, max: 20, step: 0.1, label: 'Point Size', accentColor: 'cyan' },
40
+ // ==========================================================================
41
+ // GENERATIVE EFFECT PROPERTIES
42
+ // ==========================================================================
43
+ // Base (all effects)
44
+ intensity: { min: 0, max: 5, step: 0.05, label: 'Intensity', accentColor: 'yellow' },
45
+ speed: { min: 0.1, max: 10, step: 0.1, label: 'Speed', accentColor: 'cyan' },
46
+ // Molecules
47
+ atomCount: { min: 3, max: 20, step: 1, label: 'Atom Count', accentColor: 'cyan' },
48
+ orbitRadius: { min: 0.5, max: 5, step: 0.1, label: 'Orbit Radius', accentColor: 'blue' },
49
+ atomSize: { min: 0.01, max: 0.3, step: 0.01, label: 'Atom Size', accentColor: 'purple' },
50
+ // Shockwave / smoke ring
51
+ ringCount: { min: 1, max: 5, step: 1, label: 'Ring Count', accentColor: 'cyan' },
52
+ expansionRadius: { min: 1, max: 6, step: 0.1, label: 'Expansion Radius', accentColor: 'blue' },
53
+ intervalSeconds: { min: 0.5, max: 10, step: 0.1, label: 'Interval (s)', accentColor: 'yellow' },
54
+ // Aura / orb
55
+ layerCount: { min: 1, max: 5, step: 1, label: 'Layer Count', accentColor: 'purple' },
56
+ fresnelPower: { min: 1, max: 8, step: 0.1, label: 'Fresnel Power', accentColor: 'pink' },
57
+ pulseSpeed: { min: 0.1, max: 5, step: 0.1, label: 'Pulse Speed', accentColor: 'pink' },
58
+ noiseAmount: { min: 0, max: 1, step: 0.01, label: 'Noise Amount', accentColor: 'green' },
59
+ sizeMultiplier: { min: 1, max: 3, step: 0.1, label: 'Size Multiplier', accentColor: 'blue' },
60
+ coreSize: { min: 0.05, max: 0.5, step: 0.01, label: 'Core Size', accentColor: 'yellow' },
61
+ glowLayers: { min: 1, max: 5, step: 1, label: 'Glow Layers', accentColor: 'purple' },
62
+ // Data stream / constellation
63
+ particleCount: { min: 20, max: 500, step: 10, label: 'Particle Count', accentColor: 'cyan' },
64
+ spiralTurns: { min: 1, max: 12, step: 1, label: 'Spiral Turns', accentColor: 'blue' },
65
+ streamRadius: { min: 0.5, max: 5, step: 0.1, label: 'Stream Radius', accentColor: 'green' },
66
+ particleSize: { min: 0.01, max: 0.2, step: 0.01, label: 'Particle Size', accentColor: 'purple' },
67
+ connectRadius: { min: 0.5, max: 5, step: 0.1, label: 'Connect Radius', accentColor: 'cyan' },
68
+ twinkleSpeed: { min: 0.1, max: 5, step: 0.1, label: 'Twinkle Speed', accentColor: 'pink' },
69
+ lineOpacity: { min: 0, max: 1, step: 0.01, label: 'Line Opacity', accentColor: 'purple' },
70
+ starCount: { min: 10, max: 200, step: 5, label: 'Star Count', accentColor: 'yellow' },
71
+ starSize: { min: 0.01, max: 0.2, step: 0.01, label: 'Star Size', accentColor: 'yellow' },
72
+ // Hologram
73
+ scanlineCount: { min: 2, max: 20, step: 1, label: 'Scanline Count', accentColor: 'cyan' },
74
+ scanSpeed: { min: 0.1, max: 5, step: 0.1, label: 'Scan Speed', accentColor: 'green' },
75
+ flickerAmount: { min: 0, max: 1, step: 0.01, label: 'Flicker Amount', accentColor: 'yellow' },
76
+ // Portal
77
+ radius: { min: 0.5, max: 5, step: 0.1, label: 'Radius', accentColor: 'purple' },
78
+ rotationSpeed: { min: 0.1, max: 5, step: 0.1, label: 'Rotation Speed', accentColor: 'cyan' },
79
+ // DNA Helix
80
+ helixRadius: { min: 0.2, max: 3, step: 0.1, label: 'Helix Radius', accentColor: 'blue' },
81
+ helixHeight: { min: 0.5, max: 5, step: 0.1, label: 'Helix Height', accentColor: 'green' },
82
+ // Lightning
83
+ boltCount: { min: 1, max: 8, step: 1, label: 'Bolt Count', accentColor: 'yellow' },
84
+ branchDepth: { min: 2, max: 6, step: 1, label: 'Branch Depth', accentColor: 'blue' },
85
+ strikeRadius: { min: 1, max: 4, step: 0.1, label: 'Strike Radius', accentColor: 'purple' },
86
+ flickerRate: { min: 2, max: 20, step: 1, label: 'Flicker Rate', accentColor: 'yellow' },
87
+ branchProbability: { min: 0, max: 1, step: 0.05, label: 'Branch Probability', accentColor: 'pink' },
88
+ // Aurora
89
+ ribbonCount: { min: 3, max: 10, step: 1, label: 'Ribbon Count', accentColor: 'green' },
90
+ waveAmplitude: { min: 0.1, max: 1.5, step: 0.05, label: 'Wave Amplitude', accentColor: 'cyan' },
91
+ colorShift: { min: 0, max: 1, step: 0.01, label: 'Color Shift', accentColor: 'pink' },
92
+ arcWidth: { min: 0.3, max: 1, step: 0.05, label: 'Arc Width', accentColor: 'blue' },
93
+ // Fire / smoke plume
94
+ height: { min: 0.5, max: 3, step: 0.1, label: 'Height', accentColor: 'yellow' },
95
+ spread: { min: 0.2, max: 1.5, step: 0.05, label: 'Spread', accentColor: 'yellow' },
96
+ turbulence: { min: 0, max: 1, step: 0.05, label: 'Turbulence', accentColor: 'green' },
97
+ // Forcefield
98
+ hexSize: { min: 0.02, max: 0.15, step: 0.005, label: 'Hex Size', accentColor: 'cyan' },
99
+ // Neural network
100
+ nodeCount: { min: 8, max: 40, step: 1, label: 'Node Count', accentColor: 'blue' },
101
+ signalSpeed: { min: 0.3, max: 3, step: 0.1, label: 'Signal Speed', accentColor: 'cyan' },
102
+ orbitSpeed: { min: 0.1, max: 1, step: 0.05, label: 'Orbit Speed', accentColor: 'purple' },
103
+ // Black hole
104
+ tilt: { min: 0, max: 45, step: 1, label: 'Tilt (°)', accentColor: 'purple' },
105
+ // Ice crystals
106
+ spikeCount: { min: 10, max: 60, step: 1, label: 'Spike Count', accentColor: 'blue' },
107
+ spikeLength: { min: 0.3, max: 2, step: 0.1, label: 'Spike Length', accentColor: 'cyan' },
108
+ // Volumetric fog
109
+ fogRadius: { min: 0.5, max: 3, step: 0.1, label: 'Fog Radius', accentColor: 'blue' },
110
+ driftSpeed: { min: 0.1, max: 2, step: 0.05, label: 'Drift Speed', accentColor: 'cyan' },
111
+ density: { min: 0, max: 1, step: 0.01, label: 'Density', accentColor: 'purple' },
112
+ // Smoke ring
113
+ riseSpeed: { min: 0.1, max: 2, step: 0.1, label: 'Rise Speed', accentColor: 'green' },
114
+ };
115
+ /**
116
+ * Default bounds for unknown numeric properties.
117
+ */
118
+ export const DEFAULT_MATERIAL_BOUNDS = {
119
+ min: 0,
120
+ max: 1,
121
+ step: 0.01,
122
+ accentColor: 'cyan',
123
+ };
124
+ /**
125
+ * Get bounds for a property, falling back to defaults.
126
+ */
127
+ export function getMaterialBounds(key) {
128
+ return MATERIAL_PROPERTY_BOUNDS[key] || DEFAULT_MATERIAL_BOUNDS;
129
+ }
130
+ /**
131
+ * Get a human-readable label for a property key.
132
+ * Uses the bounds label if available, otherwise converts camelCase to Title Case.
133
+ */
134
+ export function getMaterialPropertyLabel(key) {
135
+ const bounds = MATERIAL_PROPERTY_BOUNDS[key];
136
+ if (bounds?.label)
137
+ return bounds.label;
138
+ // Convert camelCase to Title Case: "envMapIntensity" → "Env Map Intensity"
139
+ return key
140
+ .replace(/([A-Z])/g, ' $1')
141
+ .replace(/^./, s => s.toUpperCase())
142
+ .trim();
143
+ }
144
+ /**
145
+ * Generate random values for numeric and color properties within their bounds.
146
+ * Skips texture/mapping properties and internal fields.
147
+ */
148
+ export function generateRandomMaterialSettings(currentSettings) {
149
+ const randomized = { ...currentSettings };
150
+ for (const [key, value] of Object.entries(currentSettings)) {
151
+ // Skip internal fields
152
+ if (['materialType', 'materialVariant', 'handlers', 'apply', 'uHasTexture', 'transparent', 'side', 'u_time', 'u_resolution', 'u_mouse'].includes(key)) {
153
+ continue;
154
+ }
155
+ // Skip textures/maps
156
+ const lower = key.toLowerCase();
157
+ if (lower.includes('map') || lower.includes('texture'))
158
+ continue;
159
+ // Skip arrays (normalScale, etc.)
160
+ if (Array.isArray(value))
161
+ continue;
162
+ // Randomize numbers within bounds
163
+ if (typeof value === 'number') {
164
+ const bounds = getMaterialBounds(key);
165
+ const range = bounds.max - bounds.min;
166
+ const randomValue = bounds.min + Math.random() * range;
167
+ // Round to step precision
168
+ const precision = bounds.step < 1 ? Math.ceil(-Math.log10(bounds.step)) : 0;
169
+ randomized[key] = Number(randomValue.toFixed(precision));
170
+ }
171
+ // Randomize colors
172
+ if (typeof value === 'string' && value.startsWith('#')) {
173
+ const r = Math.floor(Math.random() * 256).toString(16).padStart(2, '0');
174
+ const g = Math.floor(Math.random() * 256).toString(16).padStart(2, '0');
175
+ const b = Math.floor(Math.random() * 256).toString(16).padStart(2, '0');
176
+ randomized[key] = `#${r}${g}${b}`;
177
+ }
178
+ }
179
+ return randomized;
180
+ }
@@ -0,0 +1,83 @@
1
+ export interface OptionalProperty {
2
+ name: string;
3
+ description: string;
4
+ type: 'number' | 'string' | 'boolean' | 'color' | 'vector3' | 'vector2' | 'select';
5
+ min?: number;
6
+ max?: number;
7
+ step?: number;
8
+ options?: string[];
9
+ /** Display labels for `options` (same order); the values are what is stored. */
10
+ optionLabels?: string[];
11
+ /** Display label; defaults to the name split at capitals ("pointerStrength" -> "Pointer Strength"). */
12
+ label?: string;
13
+ /** false = structural: set only, never driven per frame. Absent = numbers / colours
14
+ * animate. Carried from the env schemas; read by the property registry. */
15
+ animatable?: boolean;
16
+ /** Display unit ('°', 'm', 's'…), shown after the value. */
17
+ unit?: string;
18
+ /** Value the panel shows when the settings do not carry one yet. */
19
+ default?: unknown;
20
+ }
21
+ export declare const skyOptionalProperties: OptionalProperty[];
22
+ export declare const oceanOptionalProperties: OptionalProperty[];
23
+ import { type TerrainType, type WaterHost, type WaterType, type LandscapeHost } from '../../environment/index';
24
+ /** Terrain properties for a given landform. Strata, plateau, incision and the dune
25
+ * terms only appear on the types whose shader branch reads them. */
26
+ export declare const terrainOptionalProperties: (type?: TerrainType) => OptionalProperty[];
27
+ /** Ocean properties for a given water type and host. */
28
+ export declare const oceanSurfaceOptionalProperties: (type?: WaterType, host?: WaterHost) => OptionalProperty[];
29
+ export declare const oceanQualityOptionalProperties: OptionalProperty[];
30
+ export declare const terrainQualityOptionalProperties: OptionalProperty[];
31
+ export declare const landscapeOptionalProperties: (host?: LandscapeHost) => OptionalProperty[];
32
+ /** Height and slope rules for a generated splat. Only shown when splatSource is
33
+ * 'auto' — with authored maps they would do nothing, and a row that does nothing
34
+ * reads as a bug in the renderer. */
35
+ export declare const landscapeAutoSplatOptionalProperties: OptionalProperty[];
36
+ export declare const landscapeQualityOptionalProperties: OptionalProperty[];
37
+ /** One surface's rows. Hand-written rather than schema-driven because a surface
38
+ * is not a shader parameter block — it is a material, and its texture slots are
39
+ * rendered by the surface list itself. */
40
+ export declare const landscapeSurfaceOptionalProperties: OptionalProperty[];
41
+ export declare const textOptionalProperties: OptionalProperty[];
42
+ export declare const plainOptionalProperties: OptionalProperty[];
43
+ export declare const meshOptionalProperties: OptionalProperty[];
44
+ export declare const rainOptionalProperties: OptionalProperty[];
45
+ export declare const pathOptionalProperties: OptionalProperty[];
46
+ export declare const edgesOptionalProperties: OptionalProperty[];
47
+ export declare const fogOptionalProperties: OptionalProperty[];
48
+ export declare const starsOptionalProperties: OptionalProperty[];
49
+ export declare const shootingStarsOptionalProperties: OptionalProperty[];
50
+ export declare const hdrOptionalProperties: OptionalProperty[];
51
+ export declare const cloudsOptionalProperties: OptionalProperty[];
52
+ import { type CloudDeckType } from '../../environment/index';
53
+ /** Deck properties for a given type. Anvil and precipitation only appear on a storm. */
54
+ export declare const cloudDeckOptionalProperties: (deckType?: CloudDeckType) => OptionalProperty[];
55
+ export declare const cirrusOptionalProperties: OptionalProperty[];
56
+ export declare const thunderOptionalProperties: OptionalProperty[];
57
+ export declare const cloudQualityOptionalProperties: OptionalProperty[];
58
+ import type { GalleryLayout } from '../../types/gallery';
59
+ /** Defaults mirror getInitialLayoutSettings, so a row left blank by a previous
60
+ * layout still shows a sane starting value instead of disappearing. */
61
+ export declare const GALLERY_FIELD_DEFAULTS: Record<string, number>;
62
+ export declare const galleryCommonProperties: OptionalProperty[];
63
+ /** Only the layout-math fields the given layout actually reads (LayoutCreator). */
64
+ export declare const layoutFieldOptionalProperties: (layout: GalleryLayout) => OptionalProperty[];
65
+ /** Only the fields GalleryCreator.generateGallery actually reads for this layout. */
66
+ export declare const galleryLayoutOptionalProperties: (layout: GalleryLayout) => OptionalProperty[];
67
+ /** meshSettings.layout — the rows above the per-layout fields in the Transform tab. */
68
+ export declare const objectLayoutCommonProperties: OptionalProperty[];
69
+ export declare const environmentOptionalProperties: {
70
+ readonly sky: OptionalProperty[];
71
+ readonly ocean: OptionalProperty[];
72
+ readonly terrain: OptionalProperty[];
73
+ readonly text: OptionalProperty[];
74
+ readonly plain: OptionalProperty[];
75
+ readonly mesh: OptionalProperty[];
76
+ readonly rain: OptionalProperty[];
77
+ readonly fog: OptionalProperty[];
78
+ readonly stars: OptionalProperty[];
79
+ readonly hdr: OptionalProperty[];
80
+ readonly clouds: OptionalProperty[];
81
+ };
82
+ export type EnvironmentType = keyof typeof environmentOptionalProperties;
83
+ //# sourceMappingURL=optionalProperties.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"optionalProperties.d.ts","sourceRoot":"","sources":["../../../src/properties/tables/optionalProperties.ts"],"names":[],"mappings":"AACA,MAAM,WAAW,gBAAgB;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC;IACnF,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,gFAAgF;IAChF,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,uGAAuG;IACvG,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;gFAC4E;IAC5E,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,4DAA4D;IAC5D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oEAAoE;IACpE,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB;AAID,eAAO,MAAM,qBAAqB,EAAE,gBAAgB,EAOnD,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,gBAAgB,EAmCrD,CAAC;AAKF,OAAO,EAIH,KAAK,WAAW,EAIhB,KAAK,SAAS,EACd,KAAK,SAAS,EAKd,KAAK,aAAa,EACrB,MAAM,yBAAyB,CAAC;AA6BjC;qEACqE;AACrE,eAAO,MAAM,yBAAyB,GAAI,OAAO,WAAW,KAAG,gBAAgB,EAG9E,CAAC;AAyCF,wDAAwD;AACxD,eAAO,MAAM,8BAA8B,GAAI,OAAO,SAAS,EAAE,OAAO,SAAS,KAAG,gBAAgB,EAGnG,CAAC;AAEF,eAAO,MAAM,8BAA8B,EAAE,gBAAgB,EAY5D,CAAC;AAEF,eAAO,MAAM,gCAAgC,EAAE,gBAAgB,EAY9D,CAAC;AA8BF,eAAO,MAAM,2BAA2B,GAAI,OAAO,aAAa,KAAG,gBAAgB,EAGlF,CAAC;AAEF;;sCAEsC;AACtC,eAAO,MAAM,oCAAoC,EAAE,gBAAgB,EAChB,CAAC;AAEpD,eAAO,MAAM,kCAAkC,EAAE,gBAAgB,EAChB,CAAC;AAElD;;2CAE2C;AAC3C,eAAO,MAAM,kCAAkC,EAAE,gBAAgB,EAWhE,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,gBAAgB,EAiEpD,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,gBAAgB,EAqGrD,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,gBAAgB,EA6BpD,CAAC;AAGF,eAAO,MAAM,sBAAsB,EAAE,gBAAgB,EASpD,CAAC;AAGF,eAAO,MAAM,sBAAsB,EAAE,gBAAgB,EAKpD,CAAC;AAIF,eAAO,MAAM,uBAAuB,EAAE,gBAAgB,EAKrD,CAAC;AAEF,eAAO,MAAM,qBAAqB,EAAE,gBAAgB,EAsBnD,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,gBAAgB,EAsCrD,CAAC;AAEF,eAAO,MAAM,+BAA+B,EAAE,gBAAgB,EA8C7D,CAAC;AAEF,eAAO,MAAM,qBAAqB,EAAE,gBAAgB,EAYnD,CAAC;AAEF,eAAO,MAAM,wBAAwB,EAAE,gBAAgB,EAqBtD,CAAC;AAWF,OAAO,EAMH,KAAK,aAAa,EACrB,MAAM,yBAAyB,CAAC;AA6BjC,wFAAwF;AACxF,eAAO,MAAM,2BAA2B,GAAI,WAAW,aAAa,KAAG,gBAAgB,EAGtF,CAAC;AAEF,eAAO,MAAM,wBAAwB,EAAE,gBAAgB,EAGtD,CAAC;AAEF,eAAO,MAAM,yBAAyB,EAAE,gBAAgB,EAGvD,CAAC;AAEF,eAAO,MAAM,8BAA8B,EAAE,gBAAgB,EAO5D,CAAC;AAaF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAqBzD;wEACwE;AACxE,eAAO,MAAM,sBAAsB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAqBzD,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,gBAAgB,EAKrD,CAAC;AAEF,mFAAmF;AACnF,eAAO,MAAM,6BAA6B,GAAI,QAAQ,aAAa,KAAG,gBAAgB,EAKrF,CAAC;AAEF,qFAAqF;AACrF,eAAO,MAAM,+BAA+B,GAAI,QAAQ,aAAa,KAAG,gBAAgB,EAGvF,CAAC;AAEF,uFAAuF;AACvF,eAAO,MAAM,4BAA4B,EAAE,gBAAgB,EAG1D,CAAC;AAGF,eAAO,MAAM,6BAA6B;;;;;;;;;;;;CAYhC,CAAC;AAGX,MAAM,MAAM,eAAe,GAAG,MAAM,OAAO,6BAA6B,CAAC"}