Hidden Realities — Milkweed & shared wind field
First plate of the hidden-realities series: natural subjects as instrument photographs. One invisible wind field, three detectors — dunes (time-integrated, what the sand remembers), water (instantaneous), milkweed seeds (advected test particles). - src/field/wind.js: divergence-free curl-noise field with closed-form time integral; displacement / scalar / stepped-vec samplers. - src/scene/umbel.js: milkweed head as a particle interaction vertex; burst releases pedicels to seed. src/scene/drift.js: seeds advected, same track contract as track.js. - composition.js: switch -> GROUP_BUILDERS registry; fieldLake/flora/ drift layers + wind plumbing. carpet.js/perspgrid.js: warpFn/phaseFn/ modesFn/heightFn injection hooks (default off, no regression). - schema + composer panels, dunelake ink palette, dune-lake template, tools/dunelake.mjs (17-plate matrix) and its curated SVG set. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -8,6 +8,10 @@
|
||||
============================================================ */
|
||||
export const DEFAULT_COMPOSITION = {
|
||||
size: 1600, seed: 'MESON-5113',
|
||||
// ONE shared wind field (see src/field/wind.js). Consumed by fieldSea
|
||||
// (time-integrated warp), fieldLake/fieldGrid (instantaneous ripple) and
|
||||
// drift (seed advection). Groups opt in via their own `wind` sub-config.
|
||||
wind: { seed: 'ZEPHYR-001', strength: 1, scale: 1.6, gust: 0.35, time: 1 },
|
||||
background: {
|
||||
color: 'rgb(229,222,203)',
|
||||
film: { opacity: 0.6, density: 0.5, seed: 8 },
|
||||
@@ -16,16 +20,24 @@ export const DEFAULT_COMPOSITION = {
|
||||
glow: { strength: 0.55, followSun: true }, // lit-page glow; centre tracks the disk
|
||||
vignette: { strength: 0.4, mode: 'radial', cx: 0.5, cy: 0.48, radius: 0.75, angle: 90, start: 0.5 },
|
||||
},
|
||||
fieldLake: {
|
||||
enabled: false, layerOpacity: 1, transform: { x: 0, y: 0, rotation: 0, scale: 1 }, seed: 'LIMNOS-001',
|
||||
color: { hueBack: 0.55, hueFront: 0.56, sat: 0.45, light: 0.5 },
|
||||
layers: 2, chaos: 0.12, blips: 0.25, mound: 0, horizonY: 0.36, lines: 26,
|
||||
wind: { warp: 0.5 }, // instantaneous — the water shows the wind live
|
||||
},
|
||||
fieldSea: {
|
||||
enabled: true, layerOpacity: 1, transform: { x: 0, y: 0, rotation: 0, scale: 1 }, seed: 'VACUUM-5113',
|
||||
color: { hueBack: 0.54, hueFront: 0.47, sat: 0.6, light: 0.36 }, // light > ~0.6 → waves lighter than ground
|
||||
layers: 3, chaos: 0.3, blips: 0.7, mound: 0.3, horizonY: 0.36, lines: 46,
|
||||
wind: { warp: 0 }, // time-integrated — what the sand remembers
|
||||
},
|
||||
fieldGrid: {
|
||||
enabled: true, layerOpacity: 1, pos: 'over', style: 'floor', transform: { x: 0, y: 0, rotation: 0, scale: 1 },
|
||||
color: { hue: 0.5, hue2: 0.55, sat: 0.32, lightNear: 0.34, lightFar: 0.62 }, opacity: 0.44,
|
||||
pitch: 0.45, yaw: 0.42, persp: 1.1, dist: 2.8, nx: 16, nz: 24, originY: 0.34, ripple: { amp: 0, freqI: 0.5, freqK: 0.35, phase: 0 },
|
||||
resonance: { amp: 0, q: 14, axis: 'ties', hue: 0.06, sat: 0.7, light: 0.45 },
|
||||
wind: { ripple: 0 }, // instantaneous wind as floor height
|
||||
},
|
||||
disk: {
|
||||
enabled: true, layerOpacity: 1, transform: { x: 0, y: -0.26, rotation: 0, scale: 0.78 },
|
||||
@@ -37,6 +49,16 @@ export const DEFAULT_COMPOSITION = {
|
||||
primaries: 18, sweepers: 5, cosmics: 6, eloss: 0.34, bfield: 1.0, deltaRate: 0.6,
|
||||
showBoundary: true, boundaryR: 0.45, boundaryY: 0.35, boundaryOpacity: 0.4, instrument: 0.35,
|
||||
},
|
||||
flora: {
|
||||
enabled: false, layerOpacity: 1, transform: { x: 0, y: 0, rotation: 0, scale: 1 },
|
||||
palette: 'dunelake', saturation: 1.05, count: 1, scale: 0.5,
|
||||
pedicels: 48, droop: 0.35, spread: 1, burst: 0, floretSize: 1,
|
||||
clusterW: 0.9, clusterH: 0.5, // placement spread when count > 1 (no explicit umbels[])
|
||||
},
|
||||
drift: {
|
||||
enabled: false, layerOpacity: 1,
|
||||
palette: 'dunelake', count: 24, slip: 0.35, flutter: 0.5, settle: 0.06, tuft: 2,
|
||||
},
|
||||
fiduciaries: {
|
||||
enabled: true, layerOpacity: 1, label: 'auto', pencil: '#39312a', width: 1.0, arrow: true, corners: false, caption: '',
|
||||
},
|
||||
@@ -66,6 +88,21 @@ export const GROUPS_SCHEMA = [
|
||||
R('vignette.angle', 'Vignette angle°', 0, 360, 1),
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'fieldLake', label: 'Field · Lake', transform: true, enable: true, controls: [
|
||||
R('color.hueBack', 'Hue · far', 0, 1, 0.005),
|
||||
R('color.hueFront', 'Hue · near', 0, 1, 0.005),
|
||||
R('color.sat', 'Saturation', 0, 1, 0.01),
|
||||
R('color.light', 'Wave luminosity', 0, 1, 0.01),
|
||||
R('layers', 'Plate layers', 1, 3, 1),
|
||||
R('chaos', 'Chaos', 0, 1, 0.01),
|
||||
R('blips', 'Blips', 0, 2, 0.05),
|
||||
R('horizonY', 'Horizon Y', 0.2, 0.6, 0.01),
|
||||
R('lines', '# lines', 8, 80, 1),
|
||||
R('wind.warp', 'Wind ripple', 0, 2, 0.02),
|
||||
{ path: 'seed', label: 'Seed', type: 'text' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'fieldSea', label: 'Field · Sea', transform: true, enable: true, controls: [
|
||||
R('color.hueBack', 'Hue · far', 0, 1, 0.005),
|
||||
@@ -78,6 +115,7 @@ export const GROUPS_SCHEMA = [
|
||||
R('mound', 'Mound', 0, 1, 0.01),
|
||||
R('horizonY', 'Horizon Y', 0.2, 0.6, 0.01),
|
||||
R('lines', '# lines', 16, 80, 1),
|
||||
R('wind.warp', 'Wind warp (dune memory)', 0, 2, 0.02),
|
||||
{ path: 'seed', label: 'Seed', type: 'text' },
|
||||
],
|
||||
},
|
||||
@@ -96,6 +134,7 @@ export const GROUPS_SCHEMA = [
|
||||
R('color.hue', 'Hue', 0, 1, 0.005),
|
||||
R('color.sat', 'Saturation', 0, 1, 0.01),
|
||||
R('ripple.amp', 'Floor ripple', 0, 2, 0.02),
|
||||
R('wind.ripple', 'Wind ripple', 0, 2, 0.02),
|
||||
R('resonance.amp', 'Resonance (high-Q)', 0, 1, 0.01),
|
||||
R('resonance.q', 'Resonance Q', 2, 40, 1),
|
||||
R('resonance.hue', 'Resonance hue', 0, 1, 0.005),
|
||||
@@ -131,6 +170,30 @@ export const GROUPS_SCHEMA = [
|
||||
R('instrument', 'Structural geometry', 0, 1, 0.01),
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'flora', label: 'Flora · milkweed', transform: true, enable: true, controls: [
|
||||
{ path: 'palette', label: 'Palette', type: 'select', options: ['dunelake', 'magentarise', 'mono', 'kind', 'kindrise', 'kindlife', 'lifecycle'] },
|
||||
R('saturation', 'Saturation', 0, 1.5, 0.01),
|
||||
R('count', 'Umbels', 1, 7, 1),
|
||||
R('scale', 'Head size', 0.15, 1.2, 0.01),
|
||||
R('pedicels', 'Pedicels', 8, 80, 1),
|
||||
R('droop', 'Droop', 0, 1, 0.01),
|
||||
R('spread', 'Fan looseness', 0, 2, 0.01),
|
||||
R('burst', 'Burst (gone to seed)', 0, 1, 0.01),
|
||||
R('floretSize', 'Floret size', 0.3, 2.5, 0.01),
|
||||
{ path: 'seed', label: 'Seed', type: 'text' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'drift', label: 'Drift · seeds', enable: true, controls: [
|
||||
R('count', 'Seeds (cap)', 0, 80, 1),
|
||||
R('slip', 'Launch slip', 0, 1, 0.01),
|
||||
R('flutter', 'Coma flutter', 0, 1.5, 0.01),
|
||||
R('settle', 'Settle speed', 0, 0.3, 0.005),
|
||||
R('tuft', 'Tuft silks', 0, 5, 1),
|
||||
R('layerOpacity', 'Opacity', 0, 1, 0.01),
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'fiduciaries', label: 'Fiduciaries', transform: true, enable: true, controls: [
|
||||
{ path: 'label', label: 'Label', type: 'text' },
|
||||
|
||||
Reference in New Issue
Block a user