vireuikit 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NOTICE +2 -5
- package/README.md +4 -84
- package/dist/index.cjs +0 -1143
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -96
- package/dist/index.d.ts +1 -96
- package/dist/index.js +1 -1
- package/package.json +2 -14
- package/dist/chunk-VY22O2II.js +0 -1148
- package/dist/chunk-VY22O2II.js.map +0 -1
- package/dist/dynamics-DqGk_f1n.d.cts +0 -415
- package/dist/dynamics-DqGk_f1n.d.ts +0 -415
- package/dist/web/index.cjs +0 -1865
- package/dist/web/index.cjs.map +0 -1
- package/dist/web/index.d.cts +0 -152
- package/dist/web/index.d.ts +0 -152
- package/dist/web/index.js +0 -899
- package/dist/web/index.js.map +0 -1
|
@@ -1,415 +0,0 @@
|
|
|
1
|
-
type VireUIKitMediumChannel = readonly [number, number, number];
|
|
2
|
-
/**
|
|
3
|
-
* A static light source, as data — the chamber's illumination is a separate entity from the gas it
|
|
4
|
-
* lights (see `MEDIUM_COMPOSITE_SHADER`): the medium itself is dark, and everything visible is
|
|
5
|
-
* light scattered by mist, condensate and tracks inside a light's reach.
|
|
6
|
-
*/
|
|
7
|
-
type VireUIKitMediumLight = {
|
|
8
|
-
/** Fraction of the frame, 0…1 both axes. `y=0` is the chamber's visual BOTTOM edge, `y=1` the
|
|
9
|
-
* top — the same convention `gravityBottomBoost` already uses in `MEDIUM_COMPOSITE_SHADER`. */
|
|
10
|
-
position: readonly [number, number];
|
|
11
|
-
/** Unit direction (any nonzero vector is normalized before upload) the light points into the
|
|
12
|
-
* chamber, in the SAME up-is-positive-y convention as `position`. Kept off the exact
|
|
13
|
-
* vertical/horizontal axes by default: an on-axis beam edge is itself axis-aligned, which is
|
|
14
|
-
* exactly the straight-line artifact `check:medium`'s isotropy gate polices, and an angled shaft
|
|
15
|
-
* also reads more like a real illuminated volume than a spotlight aimed straight down a wall. */
|
|
16
|
-
direction: readonly [number, number];
|
|
17
|
-
/** Half-angle of the light's cone, radians. Wide (close to a right angle or beyond) for an edge
|
|
18
|
-
* strip that washes the whole chamber width — there the shaping comes from distance falloff, not
|
|
19
|
-
* a cone edge — narrow for a spotlight, where the cone edge IS the visible beam. */
|
|
20
|
-
coneAngle: number;
|
|
21
|
-
/** 1/(fraction of frame height) — how fast illumination drops off with distance from the light.
|
|
22
|
-
* Distance is normalized by frame HEIGHT (not a raw fraction of each axis) so a circular pool of
|
|
23
|
-
* light stays circular on screen regardless of the frame's aspect ratio. */
|
|
24
|
-
falloff: number;
|
|
25
|
-
/** sRGB 0…1. Defaults to a cool neutral; a caller deriving a light rig from cover art applies
|
|
26
|
-
* `speciesFamily`/`characterOf` (`species.ts`) to THESE colors now, not to `channelColors` —
|
|
27
|
-
* see the comment on `channelColors` below. */
|
|
28
|
-
color: VireUIKitMediumChannel;
|
|
29
|
-
/** ≥0 multiplier on this light's contribution. 0 turns it off without removing it from the array. */
|
|
30
|
-
intensity: number;
|
|
31
|
-
};
|
|
32
|
-
/** How many lights `MEDIUM_COMPOSITE_SHADER` reads — a fixed, small count of flat uniforms
|
|
33
|
-
* (`u_light0*`/`u_light1*`/`u_light2*`), the same pattern `u_lab0/1/2` already uses for species:
|
|
34
|
-
* `setUniform` (vireglass/web) has no array form, only scalars up to vec4. A `lights` array
|
|
35
|
-
* shorter than this is padded with intensity-0 entries; a longer one is truncated. */
|
|
36
|
-
declare const MEDIUM_MAX_LIGHTS = 3;
|
|
37
|
-
type VireUIKitMediumParams = {
|
|
38
|
-
/** 1/s — how fast the TRACK density decays per second. Water (vapor+condensate) does not decay:
|
|
39
|
-
* it is a conserved volume, only moving between phases and being transported. */
|
|
40
|
-
decay: number;
|
|
41
|
-
/** Spatial frequency of the curl-noise potential, 1/px of the simulation grid. */
|
|
42
|
-
curlFreq: number;
|
|
43
|
-
/** Drift speed of the noise domain over time, 1/s. */
|
|
44
|
-
curlSpeed: number;
|
|
45
|
-
/** Velocity field scale, grid-px/s — how far the smoke can be carried in a second. */
|
|
46
|
-
advectSpeed: number;
|
|
47
|
-
/** Turbulence gate, 0…1 (playback drives it: playing is alive, paused cools down). The
|
|
48
|
-
* per-frame value is computed by `createMediumDynamics` (`dynamics.ts`) — it arrives here
|
|
49
|
-
* already resolved. */
|
|
50
|
-
turbulence: number;
|
|
51
|
-
/** 1/s — the fraction of vapor EXCESS above `condensationFloor` that turns into condensate every
|
|
52
|
-
* second from background seeding: weak, everywhere, all the time — the chamber is never
|
|
53
|
-
* perfectly clean. */
|
|
54
|
-
condensationRate: number;
|
|
55
|
-
/** Vapor density (in seed-density units, a spot's peak ≈1) below which condensation does not
|
|
56
|
-
* happen at all — only the excess above it condenses. Without a floor, the condensate would
|
|
57
|
-
* exactly retrace the vapor spot's shape (the same outline, or softer from growth blur), and
|
|
58
|
-
* the two phases would have nowhere to visually diverge: vapor is already soft, so the floor
|
|
59
|
-
* concentrates condensate in dense turbulence cores, leaving the sparse vapor around it
|
|
60
|
-
* uncondensed. Keep it NOTICEABLY below the settled mean vapor level (turbulence stirs spots
|
|
61
|
-
* into a nearly flat background of ~0.3 over a few minutes — a known limit of the numerical
|
|
62
|
-
* advection): a floor above that mean eventually stops finding any excess at all, and
|
|
63
|
-
* condensation dies out for good. */
|
|
64
|
-
condensationFloor: number;
|
|
65
|
-
/** 1/s — the fraction of condensate evaporating back into vapor. Larger than the condensation
|
|
66
|
-
* rate: at equilibrium most of the water stays vapor, which is the "supersaturated" one. */
|
|
67
|
-
evaporationRate: number;
|
|
68
|
-
/** grid-px/s — condensate drift downward, on top of the shared velocity field: gravity touches
|
|
69
|
-
* droplets and leaves vapor alone. */
|
|
70
|
-
condensateSettleSpeed: number;
|
|
71
|
-
/** Multiplier on the ambient curl field's OWN x-component, added to settling UNCONDITIONALLY
|
|
72
|
-
* (not gated by `turbulence` the way the shared velocity field is) — see
|
|
73
|
-
* MEDIUM_ADVECT_VELOCITY_SETTLE in advect-shader.ts. Without it, a droplet falling at a constant
|
|
74
|
-
* `condensateSettleSpeed` with only a turbulence-gated sideways push traces a near-straight
|
|
75
|
-
* vertical line whenever turbulence is low (rest/paused: 0.045, over 20x below the gated push
|
|
76
|
-
* needed to bend the fall) — many droplets in nearby columns then read as parallel vertical
|
|
77
|
-
* streaks, one of the axis-aligned artifacts `check-medium.mjs`'s isotropy gate measures. Reuses
|
|
78
|
-
* the SAME seamless curl field `vel` already reads rather than a second noise system, so it adds
|
|
79
|
-
* no new seam of its own. Calibrated against that gate at the product's default grid (1920x952,
|
|
80
|
-
* 74x37) — see the gate's own report for the measured ratio at this value. */
|
|
81
|
-
condensateSettleWiggle: number;
|
|
82
|
-
/** 1/s — the rate at which a droplet blends with its grid neighbors. There is no separate age
|
|
83
|
-
* counter: the blend repeats every frame, and whatever has survived more frames ends up more
|
|
84
|
-
* blended with its neighbors on its own — that IS "growth". Keep it NOTICEABLY below
|
|
85
|
-
* `evaporationRate`: over a droplet's average lifetime (1/evaporationRate) only a small
|
|
86
|
-
* fraction should get to blend — otherwise the blur outruns evaporation and the whole grid
|
|
87
|
-
* levels into flat fog before a droplet gets a chance to return to vapor (visible by eye: the
|
|
88
|
-
* contrast between "a patch of droplets" and the vapor background disappears within seconds). */
|
|
89
|
-
condensateSpreadRate: number;
|
|
90
|
-
/** 0…1 — how much of the local vapor hue shows through in the condensate. Droplets carry no
|
|
91
|
-
* color of their own (droplets scatter light rather than tint it) — this is only a faint hint
|
|
92
|
-
* of the surroundings. */
|
|
93
|
-
condensateTint: number;
|
|
94
|
-
/** Condensate's visibility multiplier in the Oklab mix relative to vapor at equal density —
|
|
95
|
-
* droplets hold a small share of the water's mass, but they are mostly what's visible (as in a
|
|
96
|
-
* real cloud: vapor is transparent, droplets create the visibility). */
|
|
97
|
-
condensateGain: number;
|
|
98
|
-
/** Near-white sRGB tone of droplets with no hue seeding (`condensateTint=0`) — droplets scatter
|
|
99
|
-
* light rather than color it. */
|
|
100
|
-
condensateColor: VireUIKitMediumChannel;
|
|
101
|
-
/** Each vapor species' hue, sRGB 0…1, folded into the dark ambient mix underneath the lit layer
|
|
102
|
-
* (see `MEDIUM_COMPOSITE_SHADER`) — a minor, near-neutral hint by default. Colour now lives on
|
|
103
|
-
* `lights`, not here: a real chamber's gas is invisible, only what scatters light reads at all
|
|
104
|
-
* (see `channelScatter`). Kept for callers that still want a tinted ambient base, and because the
|
|
105
|
-
* isotropy/contrast/depth gates in `check-medium.mjs` measure structure through it directly. */
|
|
106
|
-
channelColors: readonly [VireUIKitMediumChannel, VireUIKitMediumChannel, VireUIKitMediumChannel];
|
|
107
|
-
/** How strongly each vapor species scatters light, relative to the others — what a species IS,
|
|
108
|
-
* now that colour lives on `lights` (see `channelColors`). `[1, 1, 1]` (equal) by default; a
|
|
109
|
-
* caller can make one species read as denser mist than another without touching its hue. */
|
|
110
|
-
channelScatter: VireUIKitMediumChannel;
|
|
111
|
-
/** The platform's neutral tone — what the medium is, alone, with no source playing. */
|
|
112
|
-
baseColor: VireUIKitMediumChannel;
|
|
113
|
-
/** Background weight in the Oklab mix: keeps the platform tone visible even where the smoke is dense. */
|
|
114
|
-
baseWeight: number;
|
|
115
|
-
/** Field-sample scale for the far depth plane, k ≥ 1 (see `MEDIUM_COMPOSITE_SHADER`): the far
|
|
116
|
-
* plane reads the SAME vapor/condensate field as the near plane, at `src * k + offset` instead
|
|
117
|
-
* of `src`. A larger k folds more of the field into the same screen area, so the identical
|
|
118
|
-
* evolving field reads as both finer-grained structure (features occupy fewer screen-px) and,
|
|
119
|
-
* because the field's own motion maps to screen motion as v/k, slower apparent motion — parallax
|
|
120
|
-
* and scale-of-structure from one number, with no second simulation. Measured against
|
|
121
|
-
* `check-medium.mjs`'s parallax gate (a cross-correlation best-shift, not a centroid — see the
|
|
122
|
-
* gate's own comment on why): 1.6 puts the far/near screen-speed ratio at 0.630, matching the
|
|
123
|
-
* naive prediction 1/1.6 = 0.625 almost exactly, comfortably inside a band that reads as depth
|
|
124
|
-
* without the far plane looking frozen. */
|
|
125
|
-
depthFarScale: number;
|
|
126
|
-
/** Offset into the shared field for the far plane, as a FRACTION of the grid's own width/height
|
|
127
|
-
* (per axis) rather than a fixed grid-px value — the field wraps (`gl.REPEAT`), so a fixed
|
|
128
|
-
* grid-px offset's EFFECTIVE (wrapped) distance from zero depends on whatever grid size it
|
|
129
|
-
* happens to run at, and can land close to zero by accident at a size nobody tested against.
|
|
130
|
-
* (This shipped once as `[41, 67]` grid-px: harmless at the 96px grid the depth gates tested
|
|
131
|
-
* against, but 67 wraps to just 5px at the 72px grid height this package's own README uses as
|
|
132
|
-
* its example — the far plane nearly re-read the near one, exactly the echo depth exists to
|
|
133
|
-
* avoid.) A fraction keeps the wrapped distance proportional to the grid at any size — see
|
|
134
|
-
* `depthFarOffsetPx` below and `check-medium.mjs`'s decorrelation gate, which measures this
|
|
135
|
-
* directly at the README's own 128x72. */
|
|
136
|
-
depthFarOffsetFrac: readonly [number, number];
|
|
137
|
-
/** Grid-px radius of the far plane's 8-tap ring blur, rotated so no tap pair lies on a grid
|
|
138
|
-
* axis. A spatial average cannot raise local
|
|
139
|
-
* variance, so the same blur that softens the far plane's edges also, by construction, lowers
|
|
140
|
-
* its measured contrast — one mechanism for both aerial-perspective cues (no separate contrast
|
|
141
|
-
* knob exists). 0 disables it (the near plane stays sharp). Measured: reading the far plane's
|
|
142
|
-
* own scale/offset with no blur already drops contrast ~6% (a fixed offset can land on a
|
|
143
|
-
* locally denser or sparser patch of a field that isn't spatially uniform); this radius takes
|
|
144
|
-
* the total to 24% — see the aerial-perspective gate, whose two thresholds isolate blur's own
|
|
145
|
-
* share from that baseline. */
|
|
146
|
-
depthFarBlurRadius: number;
|
|
147
|
-
/** The far plane's share of the mix, relative to the near plane's implicit 1 — aerial
|
|
148
|
-
* perspective's other half: even at equal density the far plane must not compete with the near
|
|
149
|
-
* one for attention. */
|
|
150
|
-
depthFarWeight: number;
|
|
151
|
-
/** grid-px/s — a small downward drift added to VAPOR's own velocity, on top of the shared
|
|
152
|
-
* curl-noise field (condensate already settles faster via `condensateSettleSpeed`). An order of
|
|
153
|
-
* magnitude below it so the gas reads as "barely noticeable" drift rather than visibly falling.
|
|
154
|
-
* ADDS NO DENSITY: on this periodic (`gl.REPEAT`) grid a uniform drift only ever translates the
|
|
155
|
-
* field and wraps it back in at the top — it cannot accumulate mass anywhere, the way a real
|
|
156
|
-
* floor would. It is a motion cue (which way is down), not a source of "denser at the bottom" —
|
|
157
|
-
* that reading comes entirely from `gravityBottomBoost` below. See
|
|
158
|
-
* `check-medium.mjs`'s vapor-drift gate, which checks DIRECTION over a short window rather than
|
|
159
|
-
* a density ratio, for exactly this reason. */
|
|
160
|
-
gravityVaporDrift: number;
|
|
161
|
-
/** Density boost at the very bottom of the frame, added on top of 1 — a COMPOSITING-only effect:
|
|
162
|
-
* it scales how the already-conserved vapor/condensate density is DISPLAYED, never the
|
|
163
|
-
* simulated buffers themselves, so it cannot threaten the water-conservation invariant by
|
|
164
|
-
* construction, and — unlike `gravityVaporDrift` above — this is the mechanism that actually
|
|
165
|
-
* produces "denser at the bottom": it is a steady-state property of the compositing math, true
|
|
166
|
-
* from the very first frame, independent of any warmup or mixing time (see
|
|
167
|
-
* `check-medium.mjs`'s boost gate, which measures it with zero simulated steps for exactly that
|
|
168
|
-
* reason). Large in absolute terms because `baseWeight` (0.9) dominates the Oklab mix wherever
|
|
169
|
-
* gas density is thin — a small boost gets diluted into an invisible change in the final color;
|
|
170
|
-
* measured this large to register as a real, visible band against that dilution. */
|
|
171
|
-
gravityBottomBoost: number;
|
|
172
|
-
/** Fraction of frame height (0 top, 1 bottom) where the bottom boost starts ramping in via
|
|
173
|
-
* `smoothstep`. The brief asks for a denser LAYER at the floor of the chamber, not a boost that
|
|
174
|
-
* reaches halfway up the frame — kept in the bottom quarter. */
|
|
175
|
-
gravityBottomBoostStart: number;
|
|
176
|
-
/** Static lights — the chamber's illumination, entirely separate from the gas (see
|
|
177
|
-
* `VireUIKitMediumLight`). Padded/truncated to `MEDIUM_MAX_LIGHTS` by the web runtime. */
|
|
178
|
-
lights: readonly VireUIKitMediumLight[];
|
|
179
|
-
/** How strongly the gas between a spotlight and a point dims it, per frame height of dense gas. */
|
|
180
|
-
shadowExtinction: number;
|
|
181
|
-
/** 0…1 — a track's minimum visibility regardless of local illumination, added to the light
|
|
182
|
-
* reaching it. Tracks are lit the same way as mist, but a fresh ionization trail is bright enough
|
|
183
|
-
* in a real chamber to read even where the ambient light is weak — this is that floor, not a
|
|
184
|
-
* second light source. */
|
|
185
|
-
trackLightFloor: number;
|
|
186
|
-
/** ≥0 — master strength of the crisp, screen-space track layer (`web/track-layer.ts`): a grid
|
|
187
|
-
* cell cannot carry a thin sharp line (see that module's own header), so the grid stamp this
|
|
188
|
-
* file's `decay`/`trackLightFloor` govern stays the soft, gas-carried residue, and THIS is the
|
|
189
|
-
* bright, sharp geometry drawn over it in content pixels. 0 disables it outright — the canary
|
|
190
|
-
* `check:medium` uses to prove its "sharp at birth" gate is actually sensitive to the layer,
|
|
191
|
-
* not to the residue underneath it. */
|
|
192
|
-
trackLayerAmount: number;
|
|
193
|
-
};
|
|
194
|
-
/**
|
|
195
|
-
* An edge strip along the chamber floor plus two spotlights above the frame, aimed down across it
|
|
196
|
-
* toward the source point. The lamps stay off screen, so a beam never shows its apex, and the two
|
|
197
|
-
* differ slightly in position, angle and strength: an exact mirror reads as staged.
|
|
198
|
-
*/
|
|
199
|
-
declare const MEDIUM_DEFAULT_LIGHTS: readonly VireUIKitMediumLight[];
|
|
200
|
-
declare const MEDIUM_DEFAULTS: VireUIKitMediumParams;
|
|
201
|
-
/**
|
|
202
|
-
* Resolves the far plane's fractional offset (`depthFarOffsetFrac`) into grid-px for a GIVEN grid
|
|
203
|
-
* size — pure and exported so the wrap-safety it exists for is directly testable (see
|
|
204
|
-
* `medium-depth-offset.test.ts`) without spinning up a WebGL2 context. Per-axis: `gridWidth` and
|
|
205
|
-
* `gridHeight` are independent, and a non-square grid (the README's own 128x72 example) shouldn't
|
|
206
|
-
* distort one axis relative to the other.
|
|
207
|
-
*/
|
|
208
|
-
declare function depthFarOffsetPx(offsetFrac: readonly [number, number], gridWidth: number, gridHeight: number): readonly [number, number];
|
|
209
|
-
/**
|
|
210
|
-
* How far a value lands from the nearest wrap boundary (0 or `period`) on a periodic axis of the
|
|
211
|
-
* given `period` — the quantity that actually matters for decorrelation, not the raw offset value
|
|
212
|
-
* itself (a raw offset near the period is effectively a tiny one once the field wraps). Exported
|
|
213
|
-
* for the same reason as `depthFarOffsetPx`: a plain number, testable without a GPU.
|
|
214
|
-
*/
|
|
215
|
-
declare function wrappedDistanceFromZero(value: number, period: number): number;
|
|
216
|
-
/** The material probe can't see texture finer than this: there is no gain in a denser simulation
|
|
217
|
-
* grid than the probe's own floor. */
|
|
218
|
-
declare const MEDIUM_PROBE_FLOOR_PX = 22;
|
|
219
|
-
/** Device-px per simulation grid cell by default — noticeably coarser than the probe floor;
|
|
220
|
-
* sharpening the detail visible right next to the glass is a later increment (emission and
|
|
221
|
-
* palette). */
|
|
222
|
-
declare const MEDIUM_DEFAULT_CELL_PX = 26;
|
|
223
|
-
/**
|
|
224
|
-
* The geometry of one track stamp (`emit-shader.ts`), in FRACTIONS of `min(gridW, gridH)` rather
|
|
225
|
-
* than pixels — so a preset doesn't depend on the simulation grid's resolution. Three presets, the
|
|
226
|
-
* reference's three visible kinds: `alpha` is a thick, short, straight ray — `createMediumDynamics`
|
|
227
|
-
* stamps a dozen or so of these at once per event, radiating from one point, so a single ray is
|
|
228
|
-
* short on purpose. `electron` is thin, long-ish and ragged (wiggly, granular). `muon` is long,
|
|
229
|
-
* straight and thin — a cosmic ray crossing the whole chamber, unrelated to any source.
|
|
230
|
-
*/
|
|
231
|
-
type VireUIKitMediumTrackPreset = {
|
|
232
|
-
lengthFrac: number;
|
|
233
|
-
headWidthFrac: number;
|
|
234
|
-
tailWidthFrac: number;
|
|
235
|
-
/** Amplitude of the path's sideways noise, as a fraction of `min(gridW, gridH)`; 0 = a straight thread. */
|
|
236
|
-
raggedFrac: number;
|
|
237
|
-
raggedFreq: number;
|
|
238
|
-
/** How far the tail has settled downward, as a fraction of `min(gridW, gridH)`. */
|
|
239
|
-
settleFrac: number;
|
|
240
|
-
/** How much dimmer the tail is than the head, 0…1. */
|
|
241
|
-
tailDim: number;
|
|
242
|
-
intensity: number;
|
|
243
|
-
};
|
|
244
|
-
declare const MEDIUM_TRACK_PRESETS: Readonly<Record<'alpha' | 'electron' | 'muon', VireUIKitMediumTrackPreset>>;
|
|
245
|
-
/** Turbulence at rest/paused/with no active track — the "slow drift" baseline shared by all three
|
|
246
|
-
* neutral states (they differ from each other in other ways, not in this number). */
|
|
247
|
-
declare const MEDIUM_DRIFT_TURBULENCE = 0.045;
|
|
248
|
-
/** Turbulence range during playback: the low end is a quiet stretch of the track, the high end is
|
|
249
|
-
* peak amplitude. */
|
|
250
|
-
declare const MEDIUM_PLAYING_TURBULENCE_RANGE: readonly [number, number];
|
|
251
|
-
/** Turbulence smoothing time constant, seconds: both ramping up on play and cooling down on pause
|
|
252
|
-
* go through this filter — smooth, never a jump. */
|
|
253
|
-
declare const MEDIUM_TURBULENCE_TAU = 2.5;
|
|
254
|
-
/** Emission cadence — once every this many beats, not on every beat: at 120–180 BPM that is
|
|
255
|
-
* 0.5–0.75 Hz, an order of magnitude below the WCAG 2.3.1 photosensitivity ceiling (3 Hz). */
|
|
256
|
-
declare const MEDIUM_EMISSION_BEATS = 4;
|
|
257
|
-
/** Fraction of the beats that actually get an emission — breaks up the exact periodicity (a
|
|
258
|
-
* metronome-perfect pulse reads as mechanical) without moving the average rate. */
|
|
259
|
-
declare const MEDIUM_EMISSION_PROBABILITY = 0.55;
|
|
260
|
-
/** Emergency floor between two emissions, seconds — a safeguard for the same WCAG 2.3.1
|
|
261
|
-
* requirement, independent of `MEDIUM_EMISSION_BEATS`/BPM: even a mistake in the other constants
|
|
262
|
-
* can't flash faster than this. */
|
|
263
|
-
declare const MEDIUM_MIN_EMISSION_INTERVAL = 1.2;
|
|
264
|
-
/** Average interval between solitary "background emission" tracks at rest, seconds, plus a random
|
|
265
|
-
* `MEDIUM_NATURAL_JITTER` on top — rare, with no discernible rhythm. */
|
|
266
|
-
declare const MEDIUM_NATURAL_INTERVAL = 8;
|
|
267
|
-
declare const MEDIUM_NATURAL_JITTER = 12;
|
|
268
|
-
/** The sensitive layer — fractions of height, top to bottom. Above it there isn't enough
|
|
269
|
-
* supersaturation for a track to appear at all, so background emission is only ever visible here. */
|
|
270
|
-
declare const MEDIUM_SENSITIVE_TOP = 0.55;
|
|
271
|
-
declare const MEDIUM_SENSITIVE_BOTTOM = 0.95;
|
|
272
|
-
/** How many alpha rays a single decay event stamps at once, radiating from the same source point —
|
|
273
|
-
* the reference's starburst, not a lone track (`MEDIUM_TRACK_PRESETS.alpha` is the shape of ONE
|
|
274
|
-
* ray). Randomized per event within this range. */
|
|
275
|
-
declare const MEDIUM_ALPHA_BURST_RAYS: readonly [number, number];
|
|
276
|
-
/** Per-ray length multiplier within a burst, so the rays read as an organic spray rather than a
|
|
277
|
-
* wheel of identical spokes — the reference's rays visibly differ in reach. */
|
|
278
|
-
declare const MEDIUM_ALPHA_RAY_LENGTH_SCALE: readonly [number, number];
|
|
279
|
-
/** Per-emission depth range applied to a track's width (`headWidthFrac`/`tailWidthFrac`), far…near.
|
|
280
|
-
* The same knob reads as both "thin" and "soft": a Gaussian stamp's edge steepness scales with its
|
|
281
|
-
* own width (`emit-shader.ts`'s only extent parameter), so shrinking it for a far track thins and
|
|
282
|
-
* softens it in the same stroke — there is no second knob to hang an independent softness number
|
|
283
|
-
* on. Floored at 0.55: below that a far `alpha` track's head narrows past what MacCormack's own
|
|
284
|
-
* numerical smoothing already blurs it to, and the depth cue disappears into that noise floor.
|
|
285
|
-
* The near end now runs past 1 (1.2, not 1): depth of field needs the NEAREST tracks a little
|
|
286
|
-
* LARGER than the base preset too, not just full-size — the reference shows near tracks blurring
|
|
287
|
-
* into big soft shapes rather than merely reading "as sharp as it gets". The same knob does both
|
|
288
|
-
* jobs again: a wider-than-base stamp is also a softer-edged one. */
|
|
289
|
-
declare const MEDIUM_TRACK_DEPTH_WIDTH_RANGE: readonly [number, number];
|
|
290
|
-
/** Per-emission depth range applied to a track's intensity, far…near — "dim". Floored at 0.4, not
|
|
291
|
-
* lower: a far track still has to clear `MEDIUM_DEFAULTS.condensationFloor`'s excess threshold
|
|
292
|
-
* often enough to read as a track, or depth would look like tracks randomly failing to spawn
|
|
293
|
-
* rather than fading into the distance. */
|
|
294
|
-
declare const MEDIUM_TRACK_DEPTH_INTENSITY_RANGE: readonly [number, number];
|
|
295
|
-
/**
|
|
296
|
-
* How long a live track stays in the crisp screen-space layer (`web/track-layer.ts`), seconds, by
|
|
297
|
-
* preset — tuned by eye against the reference's own "roughly one to two seconds"
|
|
298
|
-
* (`docs`/the brief's own reference frames): `alpha` is the shortest, thickest burst ray; `muon`,
|
|
299
|
-
* a cosmic ray crossing the whole chamber, lingers longest. Independent of `MEDIUM_DEFAULTS.decay`,
|
|
300
|
-
* which times the SOFT gas-carried residue left behind in the grid, not this layer.
|
|
301
|
-
*/
|
|
302
|
-
declare const MEDIUM_TRACK_LAYER_LIFE_SECONDS: Readonly<Record<keyof typeof MEDIUM_TRACK_PRESETS, number>>;
|
|
303
|
-
/** Oldest-out cap on the live-track list (`web/track-layer.ts`) — a burst of a dozen-plus alpha
|
|
304
|
-
* rays every few seconds would otherwise grow the instanced draw without bound over a long
|
|
305
|
-
* session; 64 is comfortably above what a few overlapping bursts plus background radiation ever
|
|
306
|
-
* need alive at once. */
|
|
307
|
-
declare const MEDIUM_TRACK_LAYER_MAX_TRACKS = 64;
|
|
308
|
-
/**
|
|
309
|
-
* How a track looks in the crisp layer, per kind. Lengths are fractions of
|
|
310
|
-
* `min(contentWidth, contentHeight)`: the grid presets' widths are sized for a 26 px cell and
|
|
311
|
-
* would be tens of pixels wide here.
|
|
312
|
-
*/
|
|
313
|
-
type VireUIKitTrackLayerLook = {
|
|
314
|
-
/** Core Gaussian sigma at birth, at the source end. */
|
|
315
|
-
sigmaFrac: number;
|
|
316
|
-
/** Sigma multiplier at the far end: an alpha thickens toward the end of its range. */
|
|
317
|
-
endSigmaMul: number;
|
|
318
|
-
/** Diffusion: sigma(age) = sigma * sqrt(1 + broaden * age). */
|
|
319
|
-
broaden: number;
|
|
320
|
-
/** Sideways wiggle amplitude, for kinds whose preset has a ragged path. */
|
|
321
|
-
wiggleFrac: number;
|
|
322
|
-
/** Period of the brightness beads along the track. */
|
|
323
|
-
beadFrac: number;
|
|
324
|
-
/** Mean spacing of stray droplets along the track, and the share of slots that hold one. */
|
|
325
|
-
dropletFrac: number;
|
|
326
|
-
dropletChance: number;
|
|
327
|
-
/** Gap between the source point and where the track starts. */
|
|
328
|
-
startFrac: number;
|
|
329
|
-
/** Brightness at birth, before depth and fade. */
|
|
330
|
-
gain: number;
|
|
331
|
-
};
|
|
332
|
-
declare const MEDIUM_TRACK_LAYER_LOOK: Readonly<Record<keyof typeof MEDIUM_TRACK_PRESETS, VireUIKitTrackLayerLook>>;
|
|
333
|
-
/** Seconds over which one alpha burst's rays are born: a strong source sprays rays one after
|
|
334
|
-
* another, not all at the same instant. The first `MEDIUM_TRACK_LAYER_BURST_ACCENT` rays land on
|
|
335
|
-
* the beat itself. */
|
|
336
|
-
declare const MEDIUM_TRACK_LAYER_BURST_SPREAD = 1.6;
|
|
337
|
-
declare const MEDIUM_TRACK_LAYER_BURST_ACCENT = 3;
|
|
338
|
-
/** Shapes the brightness-vs-age curve as `(1 - age/life) ** gamma`: reaches exactly 0 at removal
|
|
339
|
-
* (no pop when a track leaves the list) while staying close to full brightness for the first part
|
|
340
|
-
* of its life (>1 skews the fade toward the end rather than a flat linear ramp down). */
|
|
341
|
-
declare const MEDIUM_TRACK_LAYER_FADE_GAMMA = 1.6;
|
|
342
|
-
/** Downward drift, as a fraction of `min(contentWidth, contentHeight)` per second — droplets that
|
|
343
|
-
* formed along a track keep settling after the stamp itself, the same physical idea as
|
|
344
|
-
* `MEDIUM_DEFAULTS.condensateSettleSpeed` but for this layer's own screen-space geometry rather
|
|
345
|
-
* than the simulation grid. Small: over a track's longest life (muon, 2.2s) this alone moves it
|
|
346
|
-
* well under a tenth of the frame. */
|
|
347
|
-
declare const MEDIUM_TRACK_LAYER_GRAVITY_SAG = 0.018;
|
|
348
|
-
/** Scales the curl field's push on a live track (see `web/track-layer.ts`'s `curlVelocityJS`),
|
|
349
|
-
* units of `min(contentWidth, contentHeight)` per second per unit of curl velocity — small enough
|
|
350
|
-
* to read as "nudged", not carried the way the gas itself is by `MEDIUM_DEFAULTS.advectSpeed`. */
|
|
351
|
-
declare const MEDIUM_TRACK_LAYER_CURL_PUSH = 0.05;
|
|
352
|
-
|
|
353
|
-
type VireUIKitMediumPlaybackState = 'idle' | 'playing' | 'paused' | 'stopped';
|
|
354
|
-
type VireUIKitMediumTrackPresetName = keyof typeof MEDIUM_TRACK_PRESETS;
|
|
355
|
-
/** The fully resolved geometry of one track stamp — the platform layer (`web/medium.ts`)
|
|
356
|
-
* translates fractions into simulation-grid pixels and binds the uniforms, deciding nothing else:
|
|
357
|
-
* which preset, where, and how bright is entirely this model's call. Carries no color of its own
|
|
358
|
-
* (there is no `channel` field): a track is lit the same way as the mist around it
|
|
359
|
-
* (`MEDIUM_COMPOSITE_SHADER`), not tinted by which track it happens to be. */
|
|
360
|
-
type VireUIKitMediumEmission = VireUIKitMediumTrackPreset & {
|
|
361
|
-
/** 0…1, a fraction of the grid on both axes — the source point (cover art while playing;
|
|
362
|
-
* wherever it happens to land at rest). */
|
|
363
|
-
source: readonly [number, number];
|
|
364
|
-
/** Radians, direction from the source to the head. */
|
|
365
|
-
angle: number;
|
|
366
|
-
seed: number;
|
|
367
|
-
/** 0 (farthest) … 1 (nearest), random within the full range and deterministic from `seed` — which
|
|
368
|
-
* plane the track reads as living on. Already folded into this emission's own `headWidthFrac`/
|
|
369
|
-
* `tailWidthFrac`/`intensity` below (see `buildEmission`); carried here too so a caller inspecting
|
|
370
|
-
* an emission can see why. */
|
|
371
|
-
depth: number;
|
|
372
|
-
/** Which preset this emission was built from — `applyTrackDepth` already folds depth into the
|
|
373
|
-
* numeric fields above, but the crisp screen-space track layer (`web/track-layer.ts`) still needs
|
|
374
|
-
* the NAME: droplet density/size and per-kind lifetime are keyed off it, not off any numeric
|
|
375
|
-
* field here (a depth-scaled `headWidthFrac` alone can't tell an alpha from an electron). */
|
|
376
|
-
kind: VireUIKitMediumTrackPresetName;
|
|
377
|
-
};
|
|
378
|
-
type VireUIKitMediumDynamicsInput = {
|
|
379
|
-
state: VireUIKitMediumPlaybackState;
|
|
380
|
-
/** Beats per minute of the active track; unread in states with no track. */
|
|
381
|
-
bpm: number;
|
|
382
|
-
/** 0…1 — a continuous volume envelope (e.g. from precomputed waveform peaks), NOT the beat itself. */
|
|
383
|
-
amplitude: number;
|
|
384
|
-
/** Seconds, a deterministic playback position (not wall-clock time) — the emission cadence has
|
|
385
|
-
* to be derived from it rather than accumulating its own phase. */
|
|
386
|
-
positionSeconds: number;
|
|
387
|
-
/** 0…1 — the area of the active track's cover art that emission comes from while playing. */
|
|
388
|
-
sourcePoint: readonly [number, number];
|
|
389
|
-
dt: number;
|
|
390
|
-
};
|
|
391
|
-
type VireUIKitMediumDynamicsFrame = {
|
|
392
|
-
turbulence: number;
|
|
393
|
-
emissions: readonly VireUIKitMediumEmission[];
|
|
394
|
-
};
|
|
395
|
-
type VireUIKitMediumDynamics = {
|
|
396
|
-
step(input: VireUIKitMediumDynamicsInput): VireUIKitMediumDynamicsFrame;
|
|
397
|
-
};
|
|
398
|
-
/**
|
|
399
|
-
* Scales a track preset's width and intensity by depth (0 far … 1 near) — separated from
|
|
400
|
-
* `buildEmission` below and exported so depth's effect on a preset is directly testable with two
|
|
401
|
-
* plain numbers, independent of how a specific emission's depth got hashed from its seed. At
|
|
402
|
-
* depth=1 this returns the preset's OWN intensity unchanged but its width scaled by the width
|
|
403
|
-
* range's own near end (`MEDIUM_TRACK_DEPTH_WIDTH_RANGE[1]`, now slightly above 1 — the nearest
|
|
404
|
-
* tracks read a little larger and softer than the base preset, not merely "as sharp as it gets";
|
|
405
|
-
* see that constant's own comment).
|
|
406
|
-
*/
|
|
407
|
-
declare function applyTrackDepth(preset: VireUIKitMediumTrackPreset, depth: number): VireUIKitMediumTrackPreset;
|
|
408
|
-
/**
|
|
409
|
-
* Stateful "playback dynamics" model: turbulence and emission scheduling per frame. Platform
|
|
410
|
-
* neutral — the caller supplies the clock and the playback position (in a bench, that would be
|
|
411
|
-
* its own render loop); it never reads `performance.now()` or the DOM itself.
|
|
412
|
-
*/
|
|
413
|
-
declare function createMediumDynamics(): VireUIKitMediumDynamics;
|
|
414
|
-
|
|
415
|
-
export { MEDIUM_TRACK_PRESETS as A, MEDIUM_TURBULENCE_TAU as B, type VireUIKitMediumDynamics as C, type VireUIKitMediumDynamicsFrame as D, type VireUIKitMediumDynamicsInput as E, type VireUIKitMediumEmission as F, type VireUIKitMediumParams as G, type VireUIKitMediumPlaybackState as H, type VireUIKitMediumTrackPreset as I, type VireUIKitMediumTrackPresetName as J, type VireUIKitTrackLayerLook as K, applyTrackDepth as L, MEDIUM_ALPHA_BURST_RAYS as M, createMediumDynamics as N, depthFarOffsetPx as O, wrappedDistanceFromZero as P, type VireUIKitMediumChannel as V, type VireUIKitMediumLight as a, MEDIUM_ALPHA_RAY_LENGTH_SCALE as b, MEDIUM_DEFAULTS as c, MEDIUM_DEFAULT_CELL_PX as d, MEDIUM_DEFAULT_LIGHTS as e, MEDIUM_DRIFT_TURBULENCE as f, MEDIUM_EMISSION_BEATS as g, MEDIUM_EMISSION_PROBABILITY as h, MEDIUM_MAX_LIGHTS as i, MEDIUM_MIN_EMISSION_INTERVAL as j, MEDIUM_NATURAL_INTERVAL as k, MEDIUM_NATURAL_JITTER as l, MEDIUM_PLAYING_TURBULENCE_RANGE as m, MEDIUM_PROBE_FLOOR_PX as n, MEDIUM_SENSITIVE_BOTTOM as o, MEDIUM_SENSITIVE_TOP as p, MEDIUM_TRACK_DEPTH_INTENSITY_RANGE as q, MEDIUM_TRACK_DEPTH_WIDTH_RANGE as r, MEDIUM_TRACK_LAYER_BURST_ACCENT as s, MEDIUM_TRACK_LAYER_BURST_SPREAD as t, MEDIUM_TRACK_LAYER_CURL_PUSH as u, MEDIUM_TRACK_LAYER_FADE_GAMMA as v, MEDIUM_TRACK_LAYER_GRAVITY_SAG as w, MEDIUM_TRACK_LAYER_LIFE_SECONDS as x, MEDIUM_TRACK_LAYER_LOOK as y, MEDIUM_TRACK_LAYER_MAX_TRACKS as z };
|