@mkbabb/glass-ui 10.1.3 → 11.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/MIGRATION.md +1024 -1461
- package/README.md +2 -2
- package/dist/DialogContent-DG5kseRQ.js +159 -0
- package/dist/DropdownMenuTrigger-uhSXgEfK.js +76 -0
- package/dist/{Surface-1nPoabc3.js → Surface-C7wq2j0A.js} +3 -0
- package/dist/aurora.css +1 -0
- package/dist/aurora.js +246 -2472
- package/dist/auroraImageSource-xNLDUjcy.js +30 -0
- package/dist/axes.js +8 -8
- package/dist/blob.css +1 -0
- package/dist/blob.js +57 -54
- package/dist/budget-CJfhLIIV.js +13 -0
- package/dist/button-CAKhiOZy.js +113 -0
- package/dist/button.js +1 -1
- package/dist/{card-ByyqRBvK.js → card-D_uXphvL.js} +4 -1
- package/dist/card.js +1 -1
- package/dist/carousel.js +3 -2
- package/dist/{checkbox-B1qn65se.js → checkbox-COLnvULu.js} +1 -0
- package/dist/checkbox.css +1 -0
- package/dist/checkbox.js +1 -1
- package/dist/{collapsible-DFzK29Oh.js → collapsible-Bd4Et730.js} +1 -0
- package/dist/collapsible.css +1 -0
- package/dist/collapsible.js +1 -1
- package/dist/color-HkUaTAJj.js +270 -0
- package/dist/{color.glsl-DTJhdekG.js → color.glsl-bFJm8k5R.js} +4 -16
- package/dist/color.wgsl-B-qDJ_OM.js +4 -0
- package/dist/{command-CatrAsrl.js → command-BsFOGZwB.js} +3 -2
- package/dist/command.css +1 -0
- package/dist/command.js +1 -1
- package/dist/component-styles.css +0 -1
- package/dist/components/_shared/axes.d.ts +7 -0
- package/dist/components/_shared/feedback/dot-ring.css +1 -1
- package/dist/components/_shared/overlay/focus-return.d.ts +9 -0
- package/dist/components/_shared/overlay/index.d.ts +3 -0
- package/dist/components/_shared/overlay/root-scroll-lock.d.ts +4 -0
- package/dist/components/_shared/overlay/sheet-width.d.ts +2 -0
- package/dist/components/_shared/shape/useBarShape.d.ts +4 -0
- package/dist/components/aurora/composables/auroraFallbackGround.d.ts +12 -0
- package/dist/components/aurora/constants/presets.d.ts +21 -0
- package/dist/components/aurora/index.d.ts +2 -2
- package/dist/components/button/styles.css +1 -1
- package/dist/components/dark-mode-toggle/dark-mode-toggle.css +1 -1
- package/dist/components/data-table/composables/useDataTableResponsive.d.ts +2 -0
- package/dist/components/deck/styles/capture.css +1 -1
- package/dist/components/dialog/DialogContent.vue.d.ts +2 -2
- package/dist/components/dialog/ModalOverlay.vue.d.ts +2 -2
- package/dist/components/dialog/ModalScrim.vue.d.ts +26 -0
- package/dist/components/dialog/styles.css +1 -1
- package/dist/components/dock/GlassDock.vue.d.ts +4 -1
- package/dist/components/dock/composables/useDockClickIntegrity.d.ts +4 -0
- package/dist/components/dock/composables/useDockShellProps.d.ts +34 -2
- package/dist/components/dock/composables/useDockState.d.ts +5 -0
- package/dist/components/dock/index.d.ts +1 -2
- package/dist/components/dock/styles/controls/icon-button.css +1 -1
- package/dist/components/dock/styles/controls/tab-button.css +1 -1
- package/dist/components/dock/styles/morph.css +1 -1
- package/dist/components/dock/styles/run.css +1 -1
- package/dist/components/dock/trigger.d.ts +1 -0
- package/dist/components/expandable-container/ExpandableContainer.vue.d.ts +30 -29
- package/dist/components/menu/ContextMenu.vue.d.ts +27 -0
- package/dist/components/menu/DropdownMenu.vue.d.ts +5 -23
- package/dist/components/menu/context.d.ts +18 -5
- package/dist/components/menu/family-click.d.ts +2 -0
- package/dist/components/menu/family-context.d.ts +2 -0
- package/dist/components/menu/index.d.ts +1 -1
- package/dist/components/sheet/SheetContent.vue.d.ts +2 -2
- package/dist/components/sortable-list/styles.css +1 -0
- package/dist/components/surface/Surface.vue.d.ts +4 -1
- package/dist/components/tabs/composables/useTabDragMorph.d.ts +4 -7
- package/dist/components/tabs/styles/segmented.css +1 -1
- package/dist/components/tabs/types.d.ts +7 -8
- package/dist/composables/dom/useResizeObserver.d.ts +3 -1
- package/dist/composables/glass/fieldPaint.d.ts +4 -0
- package/dist/composables/glass/useGlassBackdropLuminance.d.ts +7 -6
- package/dist/composables/glass/webgpu/useGpuSubstrate.d.ts +8 -0
- package/dist/composables/motion/core/motionTempo.d.ts +2 -1
- package/dist/composables/motion/morph/useDragMorph.d.ts +2 -2
- package/dist/composables/motion/morph/useSelectionGroup.d.ts +6 -25
- package/dist/composables/motion/morph/useSelectionIndicator.d.ts +8 -54
- package/dist/composables/motion/spring/useLiquidFlex.d.ts +3 -5
- package/dist/composables/motion/spring/useSpringMount.d.ts +0 -9
- package/dist/{configurator-CPxIo3q2.js → configurator-C1ZKEf1b.js} +7 -5
- package/dist/configurator.css +1 -0
- package/dist/configurator.js +1 -1
- package/dist/constants-DfrO-IaH.js +8 -0
- package/dist/constellation.css +1 -0
- package/dist/constellation.js +2 -1
- package/dist/control.css +1 -0
- package/dist/{control.css_vue_type_style_index_0_src_true_lang-BIdufaDG.js → control.css_vue_type_style_index_0_src_true_lang-D2hdtjs4.js} +1 -0
- package/dist/{createCanvasLifecycle-hJHobVTn.js → createCanvasLifecycle-DS0vEs_G.js} +76 -75
- package/dist/dark-mode-toggle.js +1 -1
- package/dist/{data-table-Cs93-uY7.js → data-table-lDykVYuo.js} +113 -107
- package/dist/data-table.css +1 -0
- package/dist/data-table.js +1 -1
- package/dist/{deck-Cm_VmyNL.js → deck-Bc-2mEKE.js} +1 -0
- package/dist/deck.js +1 -1
- package/dist/dialog.js +1 -1
- package/dist/dock-trigger.d.ts +1 -0
- package/dist/dock-trigger.js +88 -0
- package/dist/dock.js +677 -689
- package/dist/dom.js +1 -1
- package/dist/easing.js +4 -4
- package/dist/expandable-container-wS1awXGd.js +135 -0
- package/dist/expandable-container.css +1 -0
- package/dist/expandable-container.js +1 -1
- package/dist/{fading-scroll-CTeW3KNS.js → fading-scroll-D3Y20ibL.js} +2 -2
- package/dist/fading-scroll.js +1 -1
- package/dist/fieldPaint-Ci77oajZ.js +7 -0
- package/dist/fourier-field.css +1 -0
- package/dist/fourier-field.js +15 -13
- package/dist/glSetup-DMaDgrEj.js +577 -0
- package/dist/glass-ui.js +67 -66
- package/dist/handmark.css +1 -0
- package/dist/handmark.js +82 -71
- package/dist/index.css +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/{input-eLZ_AU7l.js → input-BLF2pMHE.js} +1 -1
- package/dist/input.js +1 -1
- package/dist/{label-CE03H1KL.js → label-ryNPL7e6.js} +1 -0
- package/dist/label.css +1 -0
- package/dist/label.js +1 -1
- package/dist/labeled-field.css +1 -0
- package/dist/labeled-field.js +5 -4
- package/dist/{menu-DaYAZiVW.js → menu-C_l2Sslf.js} +162 -112
- package/dist/menu.js +3 -3
- package/dist/metric.js +1 -0
- package/dist/motion-core.js +138 -44
- package/dist/motion-lHDAQHEE.js +91 -0
- package/dist/motion.js +5 -5
- package/dist/motionTempo-DXdVbCWr.js +13 -0
- package/dist/music-staff.js +1 -0
- package/dist/{number-field-RP89046a.js → number-field-BXFUP49Z.js} +3 -2
- package/dist/number-field.css +1 -0
- package/dist/number-field.js +1 -1
- package/dist/pager-dots.css +1 -0
- package/dist/pager-dots.js +4 -3
- package/dist/participation-C5y5VZTN.js +52 -0
- package/dist/{popover-BdpoE4Ar.js → popover-DQUmwuAa.js} +3 -2
- package/dist/popover.js +1 -1
- package/dist/{progress-eVa-mc7J.js → progress-BUn0Bw7Z.js} +1 -0
- package/dist/progress.css +1 -0
- package/dist/progress.js +1 -1
- package/dist/{radio-group-B58Bz16F.js → radio-group-xdEy2tdi.js} +1 -0
- package/dist/radio-group.css +1 -0
- package/dist/radio-group.js +1 -1
- package/dist/root-scroll-lock-DJFrQhMa.js +22 -0
- package/dist/select-Dt5dXm87.js +309 -0
- package/dist/select.js +1 -1
- package/dist/{separator-D4EZM10u.js → separator-C4y9p_ky.js} +1 -0
- package/dist/separator.css +1 -0
- package/dist/separator.js +1 -1
- package/dist/sheet-DLqNUIZl.js +347 -0
- package/dist/sheet-width-DgXgJNa5.js +18 -0
- package/dist/sheet.js +2 -2
- package/dist/{slider-5uoY-cLG.js → slider-CZiKrWGg.js} +8 -8
- package/dist/slider.js +1 -1
- package/dist/sortable-list.js +2 -1
- package/dist/{status-dot-W4LFiJps.js → status-dot-BDZKcRxy.js} +2 -1
- package/dist/status-dot.css +1 -0
- package/dist/status-dot.js +1 -1
- package/dist/styles/components.css +1 -1
- package/dist/styles/glass/glass-capsule.css +1 -1
- package/dist/styles/glass/glass-chip.css +1 -1
- package/dist/styles/glass/mark.css +1 -1
- package/dist/styles/glass/overlay-plate.css +1 -1
- package/dist/styles/glass/surface-axis.css +1 -1
- package/dist/styles/index.css +1 -1
- package/dist/styles/theme/radius.css +1 -1
- package/dist/styles/tokens/color-radius.css +1 -1
- package/dist/styles/tokens/manifest.d.ts +1 -1
- package/dist/styles/tokens/scale-paper.css +1 -1
- package/dist/styles/utilities/base-misc.css +1 -1
- package/dist/surface.js +1 -1
- package/dist/{switch-BYUZ6g9G.js → switch-DLfGYU35.js} +1 -0
- package/dist/switch.css +1 -0
- package/dist/switch.js +1 -1
- package/dist/tabs-NgTRPGZx.js +229 -0
- package/dist/tabs.js +1 -1
- package/dist/textarea.js +1 -1
- package/dist/timeline.css +1 -0
- package/dist/timeline.js +4 -3
- package/dist/toggle-group-DgXcJGD6.js +129 -0
- package/dist/toggle-group.css +1 -0
- package/dist/toggle-group.js +1 -1
- package/dist/tokens.js +2 -0
- package/dist/{tooltip-CZVubnJf.js → tooltip-Do3qCw0r.js} +1 -1
- package/dist/tooltip.js +1 -1
- package/dist/typewriter.css +1 -0
- package/dist/typewriter.js +1 -0
- package/dist/uniformBridge-CJyy7NOn.js +150 -0
- package/dist/useBarShape-CmP35Z8o.js +24 -0
- package/dist/{useCanvas2D-CQRElMyE.js → useCanvas2D-Bhpwua98.js} +1 -1
- package/dist/{useDockCtaReceive-BSSgD6mu.js → useDockCtaReceive-Dn_-paqP.js} +1 -1
- package/dist/{useDragMorph-B363RUbF.js → useDragMorph-BEI74U0t.js} +51 -40
- package/dist/{color.wgsl-BTszLY39.js → useGpuSubstrate-Y5XAdU8d.js} +7 -7
- package/dist/{useLiquidPress-h1scrPtP.js → useLiquidPress-D5mjZC6U.js} +2 -2
- package/dist/{useResizeObserver-CdUlm2QZ.js → useResizeObserver-Bv3nN46q.js} +4 -7
- package/dist/useScrollChrome-DMP6kDI9.js +67 -0
- package/dist/useSelectionGroup-DAQv5Lb5.js +186 -0
- package/dist/{useSpring-9u2_shxV.js → useSpring-Aof0nTRt.js} +1 -1
- package/dist/useSpringMount-jgNkymRl.js +73 -0
- package/dist/wgpuSetup-CFuqd_RP.js +1278 -0
- package/package.json +8 -1
- package/dist/DialogContent-CwIBvou_.js +0 -157
- package/dist/DropdownMenuTrigger-CKRnhDSQ.js +0 -93
- package/dist/button-BOFTUPyU.js +0 -110
- package/dist/composables/motion/morph/eyeglass.d.ts +0 -141
- package/dist/expandable-container-CZUj9BzY.js +0 -142
- package/dist/glass-ui.css +0 -2
- package/dist/motion-BvV1_24p.js +0 -61
- package/dist/motionTempo-tscp92Nm.js +0 -7
- package/dist/participation-B7UFdgXB.js +0 -55
- package/dist/select-BiF0FCZf.js +0 -292
- package/dist/sheet-DmJxgAHc.js +0 -345
- package/dist/tabs-C5sC0fBE.js +0 -269
- package/dist/toggle-group-CC5b3o1R.js +0 -125
- package/dist/useScrollChrome-BJbWV32F.js +0 -162
- package/dist/useSelectionGroup-zsEwitF6.js +0 -291
- package/dist/useSpringMount-OA-0mTNv.js +0 -73
|
@@ -0,0 +1,1278 @@
|
|
|
1
|
+
import { h as e, m as t, n, v as r } from "./color-HkUaTAJj.js";
|
|
2
|
+
import { i, n as a, r as o, t as s } from "./color.wgsl-B-qDJ_OM.js";
|
|
3
|
+
import { a as c, n as l, r as u, s as d, t as f } from "./uniformBridge-CJyy7NOn.js";
|
|
4
|
+
//#endregion
|
|
5
|
+
//#region src/components/aurora/constants/shaders/aurora.wgsl.ts
|
|
6
|
+
var p = `
|
|
7
|
+
const MAX_NUCLEI: i32 = 8;
|
|
8
|
+
const MAX_STOPS: i32 = 8;
|
|
9
|
+
const PI: f32 = 3.141592653589793;
|
|
10
|
+
|
|
11
|
+
// ── Uniforms (the typed-struct source-of-truth — see aurora.wgsl.uniforms.ts) ──
|
|
12
|
+
// Scalars are packed into vec4 lanes to keep the std140/WGSL 16-byte struct alignment
|
|
13
|
+
// trivial. nuc0[i] = (pos.x, pos.y, radius, paletteBias); nuc1[i] = (valueBias,
|
|
14
|
+
// driftRadius, driftPhase, elong); nuc2[i] = (angle, _, _, _). palette[i].rgb is the
|
|
15
|
+
// CPU-baked linear-sRGB stop.
|
|
16
|
+
struct Uniforms {
|
|
17
|
+
// scalars0: (uTime, uSoftmaxBeta, uValueVariance, uWarpAmount)
|
|
18
|
+
scalars0: vec4<f32>,
|
|
19
|
+
// scalars1: (uWarpScale, uWarpDrift, uSaturation, uPaperGrain)
|
|
20
|
+
scalars1: vec4<f32>,
|
|
21
|
+
// scalars2: (uAlpha, uNucleiDrift, uPaletteDrift, uBreathDepth)
|
|
22
|
+
scalars2: vec4<f32>,
|
|
23
|
+
// scalars3: (uBreathPeriod, uCursorStrength, uCursorRadius, uVividness)
|
|
24
|
+
// The .w pad lane now carries the chroma-floor strength.
|
|
25
|
+
scalars3: vec4<f32>,
|
|
26
|
+
// cursor: (uCursor.x, uCursor.y, uMetalPolish, uMetalHeightScale)
|
|
27
|
+
// The two free pad lanes carry the metal-medium knobs (the
|
|
28
|
+
// metal light is cursor-synthesized so it reads in-struct on the WGSL primary too).
|
|
29
|
+
cursor: vec4<f32>,
|
|
30
|
+
// ints: (uStopCount, uNucleiCount, uWarpMode, uNoiseOctaves)
|
|
31
|
+
ints0: vec4<i32>,
|
|
32
|
+
// ints1: (uMedium, uHuePath, _, _)
|
|
33
|
+
ints1: vec4<i32>,
|
|
34
|
+
palette: array<vec4<f32>, 8>,
|
|
35
|
+
nuc0: array<vec4<f32>, 8>,
|
|
36
|
+
nuc1: array<vec4<f32>, 8>,
|
|
37
|
+
nuc2: array<vec4<f32>, 8>,
|
|
38
|
+
// The painterly-medium scalar lanes are appended after the
|
|
39
|
+
// arrays so EVERY existing offset (and the smooth-default parity capture) is
|
|
40
|
+
// byte-identical (these lanes are written 0 on a smooth config). scalars4:
|
|
41
|
+
// (uStrokeAmount, uStrokeScale, uStrokeAnisotropy, uCanvasGrain). scalars5:
|
|
42
|
+
// (uWetEdge, uGranulation, uBrokenColor, uKuwaharaQ). kuwahara: (uKuwaharaRadius,
|
|
43
|
+
// uKuwaharaSectors, _, _) — the Kuwahara radius/sectors/q in lockstep with
|
|
44
|
+
// packAuroraWGPUUniforms (the typed-struct discipline).
|
|
45
|
+
scalars4: vec4<f32>,
|
|
46
|
+
scalars5: vec4<f32>,
|
|
47
|
+
kuwahara: vec4<f32>,
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
@group(0) @binding(0) var<uniform> u: Uniforms;
|
|
51
|
+
|
|
52
|
+
// ── Authoring-scale → rad/sec lifts (byte-identical to aurora.frag.ts) ──
|
|
53
|
+
const K_NUCLEI: f32 = 14.0;
|
|
54
|
+
const K_PAL: f32 = 24.0;
|
|
55
|
+
const K_WARP: f32 = 5.0;
|
|
56
|
+
|
|
57
|
+
// ── Noise (Aurora-local hash21/vnoise/fbm, deliberately distinct) ──────────
|
|
58
|
+
fn hash21(p0: vec2<f32>) -> f32 {
|
|
59
|
+
var p = fract(p0 * vec2<f32>(123.34, 456.21));
|
|
60
|
+
p = p + dot(p, p + 45.32);
|
|
61
|
+
return fract(p.x * p.y);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
fn hash22(p0: vec2<f32>) -> vec2<f32> {
|
|
65
|
+
let p = vec2<f32>(dot(p0, vec2<f32>(127.1, 311.7)),
|
|
66
|
+
dot(p0, vec2<f32>(269.5, 183.3)));
|
|
67
|
+
return fract(sin(p) * 43758.5453);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
fn vnoise(p: vec2<f32>) -> f32 {
|
|
71
|
+
let i = floor(p);
|
|
72
|
+
let f = fract(p);
|
|
73
|
+
let uu = f * f * (3.0 - 2.0 * f);
|
|
74
|
+
let a = hash21(i);
|
|
75
|
+
let b = hash21(i + vec2<f32>(1.0, 0.0));
|
|
76
|
+
let c = hash21(i + vec2<f32>(0.0, 1.0));
|
|
77
|
+
let d = hash21(i + vec2<f32>(1.0, 1.0));
|
|
78
|
+
return mix(mix(a, b, uu.x), mix(c, d, uu.x), uu.y);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
${s}
|
|
82
|
+
|
|
83
|
+
fn fbm(p0: vec2<f32>) -> f32 {
|
|
84
|
+
var v = 0.0;
|
|
85
|
+
var a = 0.5;
|
|
86
|
+
var p = p0;
|
|
87
|
+
let octaves = u.ints0.w;
|
|
88
|
+
for (var i = 0; i < 5; i = i + 1) {
|
|
89
|
+
if (i >= octaves) { break; }
|
|
90
|
+
v = v + a * vnoise(p);
|
|
91
|
+
p = FBM_ROT * p * 2.02;
|
|
92
|
+
a = a * 0.5;
|
|
93
|
+
}
|
|
94
|
+
return v;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
fn potentialFBM(p: vec2f) -> f32 { return fbm(p); }
|
|
98
|
+
|
|
99
|
+
const CURL_EPS: f32 = 0.012;
|
|
100
|
+
|
|
101
|
+
// ∇×ψ in 2D — the divergence-free flow direction. Central finite differences of the
|
|
102
|
+
// scalar potential give the partials; the cross-pairing (∂y, −∂x) is the 2D curl.
|
|
103
|
+
fn curlFBM(p: vec2f) -> vec2f {
|
|
104
|
+
let dx = potentialFBM(p + vec2f(CURL_EPS, 0.0)) - potentialFBM(p - vec2f(CURL_EPS, 0.0));
|
|
105
|
+
let dy = potentialFBM(p + vec2f(0.0, CURL_EPS)) - potentialFBM(p - vec2f(0.0, CURL_EPS));
|
|
106
|
+
// ψ-gradient is (dx, dy)/(2·eps); the curl rotates it 90°: (∂ψ/∂y, −∂ψ/∂x).
|
|
107
|
+
let g = vec2f(dx, dy) / (2.0 * CURL_EPS);
|
|
108
|
+
return vec2f(g.y, -g.x);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
${a}
|
|
113
|
+
${o}
|
|
114
|
+
${i}
|
|
115
|
+
|
|
116
|
+
// Interleaved Gradient Noise (Jimenez) — display-space 1-LSB dither.
|
|
117
|
+
fn ign(p: vec2<f32>) -> f32 {
|
|
118
|
+
return fract(52.9829189 * fract(dot(p, vec2<f32>(0.06711056, 0.00583715))));
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Cellular, Worley f1.
|
|
122
|
+
fn cellular(p: vec2<f32>) -> f32 {
|
|
123
|
+
let i = floor(p);
|
|
124
|
+
let f = fract(p);
|
|
125
|
+
var m = 1e9;
|
|
126
|
+
for (var y = -1; y <= 1; y = y + 1) {
|
|
127
|
+
for (var x = -1; x <= 1; x = x + 1) {
|
|
128
|
+
let g = vec2<f32>(f32(x), f32(y));
|
|
129
|
+
let o = hash22(i + g);
|
|
130
|
+
let r = g + o - f;
|
|
131
|
+
m = min(m, dot(r, r));
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return sqrt(m);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// ── Warp (Quilez double warp + the four warp modes + the cursor swirl) ──
|
|
138
|
+
fn domainWarp(p: vec2<f32>, t: f32) -> vec2<f32> {
|
|
139
|
+
let warpScale = u.scalars1.x;
|
|
140
|
+
let warpDrift = u.scalars1.y;
|
|
141
|
+
let warpAmount = u.scalars0.w;
|
|
142
|
+
let warpMode = u.ints0.z;
|
|
143
|
+
let cursorStrength = u.scalars3.y;
|
|
144
|
+
let cursorRadius = u.scalars3.z;
|
|
145
|
+
let cursor = u.cursor.xy;
|
|
146
|
+
|
|
147
|
+
let q = vec2<f32>(fbm(p * warpScale + vec2<f32>(0.0, 0.0) + t * warpDrift * K_WARP),
|
|
148
|
+
fbm(p * warpScale + vec2<f32>(5.2, 1.3) + t * warpDrift * K_WARP));
|
|
149
|
+
let r = vec2<f32>(fbm(p * warpScale + 4.0 * q + vec2<f32>(1.7, 9.2)),
|
|
150
|
+
fbm(p * warpScale + 4.0 * q + vec2<f32>(8.3, 2.8)));
|
|
151
|
+
|
|
152
|
+
var warp = r;
|
|
153
|
+
if (warpMode == 1) {
|
|
154
|
+
// cellular — chunky territories
|
|
155
|
+
let c1 = cellular(p * warpScale * 1.5 + vec2<f32>(t * warpDrift * K_WARP * 2.0, 0.0));
|
|
156
|
+
let c2 = cellular(p * warpScale * 1.5 + vec2<f32>(11.0, 7.0 + t * warpDrift * K_WARP * 2.0));
|
|
157
|
+
warp = vec2<f32>(c1, c2);
|
|
158
|
+
} else if (warpMode == 2) {
|
|
159
|
+
// hybrid — fbm + cellular averaged
|
|
160
|
+
let c1 = cellular(p * warpScale * 1.2);
|
|
161
|
+
let c2 = cellular(p * warpScale * 1.2 + vec2<f32>(11.0, 7.0));
|
|
162
|
+
warp = mix(r, vec2<f32>(c1, c2), 0.5);
|
|
163
|
+
} else if (warpMode == 3) {
|
|
164
|
+
let fp = p * warpScale + vec2<f32>(t * warpDrift * K_WARP);
|
|
165
|
+
warp = curlFBM(fp);
|
|
166
|
+
}
|
|
167
|
+
var warped = p + warpAmount * warp;
|
|
168
|
+
|
|
169
|
+
// Cursor swirl — rotate p around the cursor with radial falloff.
|
|
170
|
+
if (cursorStrength > 0.001) {
|
|
171
|
+
let toP = p - cursor;
|
|
172
|
+
let d = length(toP);
|
|
173
|
+
let rr = max(cursorRadius, 0.01);
|
|
174
|
+
let w = exp(-(d * d) / (rr * rr * 0.45));
|
|
175
|
+
let ang = w * cursorStrength * 2.1;
|
|
176
|
+
let ca = cos(ang);
|
|
177
|
+
let sa = sin(ang);
|
|
178
|
+
var rotated = vec2<f32>(ca * toP.x - sa * toP.y, sa * toP.x + ca * toP.y) + cursor;
|
|
179
|
+
let pinch = w * cursorStrength * 0.08;
|
|
180
|
+
rotated = mix(rotated, cursor, pinch);
|
|
181
|
+
warped = mix(warped, rotated + warpAmount * warp * 0.7, w * cursorStrength);
|
|
182
|
+
}
|
|
183
|
+
return warped;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// ── Palette LUT ──
|
|
187
|
+
fn samplePalette(id0: f32) -> vec3<f32> {
|
|
188
|
+
let id = clamp(id0, 0.0, 1.0);
|
|
189
|
+
let stopCount = u.ints0.x;
|
|
190
|
+
let scaled = id * f32(stopCount - 1);
|
|
191
|
+
let i0 = i32(floor(scaled));
|
|
192
|
+
let i1 = min(i0 + 1, stopCount - 1);
|
|
193
|
+
let t = fract(scaled);
|
|
194
|
+
return samplePaletteRamp(u.palette[i0].rgb, u.palette[i1].rgb, t, u.ints1.y);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// ── Nuclei field (anisotropic Gaussian softmax + drift + palette drift) ──
|
|
198
|
+
struct NucleiResult { paletteId: f32, valueMod: f32 };
|
|
199
|
+
|
|
200
|
+
fn nucleiField(p: vec2<f32>, t: f32) -> NucleiResult {
|
|
201
|
+
let nucleiCount = u.ints0.y;
|
|
202
|
+
let nucleiDrift = u.scalars2.y;
|
|
203
|
+
let paletteDrift = u.scalars2.z;
|
|
204
|
+
let softmaxBeta = u.scalars0.y;
|
|
205
|
+
|
|
206
|
+
var accumBias = 0.0;
|
|
207
|
+
var accumValue = 0.0;
|
|
208
|
+
var accumW = 0.0;
|
|
209
|
+
for (var i = 0; i < MAX_NUCLEI; i = i + 1) {
|
|
210
|
+
if (i >= nucleiCount) { break; }
|
|
211
|
+
let n0 = u.nuc0[i]; // pos.x, pos.y, radius, paletteBias
|
|
212
|
+
let n1 = u.nuc1[i]; // valueBias, driftRadius, driftPhase, elong
|
|
213
|
+
let angle = u.nuc2[i].x;
|
|
214
|
+
let driftRadius = n1.y;
|
|
215
|
+
let driftPhase = n1.z;
|
|
216
|
+
let posI = n0.xy + driftRadius * vec2<f32>(
|
|
217
|
+
cos(t * nucleiDrift * K_NUCLEI + driftPhase),
|
|
218
|
+
sin(t * nucleiDrift * K_NUCLEI + driftPhase * 1.13)
|
|
219
|
+
);
|
|
220
|
+
let diff = p - posI;
|
|
221
|
+
let ca = cos(angle);
|
|
222
|
+
let sa = sin(angle);
|
|
223
|
+
let local = vec2<f32>(ca * diff.x + sa * diff.y, -sa * diff.x + ca * diff.y);
|
|
224
|
+
let along = local.x / max(n1.w, 0.01);
|
|
225
|
+
let across = local.y;
|
|
226
|
+
let d2 = along * along + across * across;
|
|
227
|
+
let r = max(n0.z, 0.01);
|
|
228
|
+
let w = exp(-softmaxBeta * d2 / (r * r));
|
|
229
|
+
accumBias = accumBias + w * n0.w;
|
|
230
|
+
accumValue = accumValue + w * n1.x;
|
|
231
|
+
accumW = accumW + w;
|
|
232
|
+
}
|
|
233
|
+
var paletteId = accumBias / max(accumW, 1e-4);
|
|
234
|
+
let valueMod = accumValue / max(accumW, 1e-4);
|
|
235
|
+
|
|
236
|
+
let palAmp = clamp(paletteDrift * 6.0, 0.0, 0.06);
|
|
237
|
+
paletteId = paletteId + palAmp * sin(t * paletteDrift * K_PAL);
|
|
238
|
+
paletteId = clamp(paletteId, 0.0, 1.0);
|
|
239
|
+
return NucleiResult(paletteId, valueMod);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// ── Color utils (OKLCh saturation) ──
|
|
243
|
+
fn linOklab(lin: vec3<f32>) -> vec3<f32> {
|
|
244
|
+
let lms = LINEAR_SRGB_TO_LMS * lin;
|
|
245
|
+
return LMS_TO_OKLAB * cbrt3(lms);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
fn saturate3(c: vec3<f32>, amt: f32) -> vec3<f32> {
|
|
249
|
+
var lch = oklabToOklch(linOklab(c));
|
|
250
|
+
lch.y = max(lch.y * amt, 0.0);
|
|
251
|
+
return max(oklabToLinearSrgb(oklchToOklab(lch)), vec3<f32>(0.0));
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// The chroma floor, the WGSL twin of the GLSL vividnessFloor.
|
|
255
|
+
// OKLab chroma lifted toward the floor, hue + L preserved; below VIVID_EPS the (a,b)
|
|
256
|
+
// direction is precision noise so the lift synthesizes along the WARM anchor (amber,
|
|
257
|
+
// both components positive) — never teal/navy. vividness (scalars3.w) == 0 is a no-op
|
|
258
|
+
// (the byte-identity opt-out). Mode factor lifts a dim field a touch (read through glass).
|
|
259
|
+
const VIVID_TARGET: f32 = 0.115;
|
|
260
|
+
const VIVID_EPS: f32 = 0.012;
|
|
261
|
+
const VIVID_WARM_ANCHOR: vec2<f32> = vec2<f32>(0.34202, 0.93969);
|
|
262
|
+
fn vividnessFloor(c: vec3<f32>, vividness: f32) -> vec3<f32> {
|
|
263
|
+
if (vividness <= 0.0001) { return c; }
|
|
264
|
+
var lab = linOklab(c);
|
|
265
|
+
let C = length(lab.yz);
|
|
266
|
+
let modeLift = mix(1.18, 1.0, clamp(lab.x * 1.4, 0.0, 1.0));
|
|
267
|
+
let Cmin = vividness * VIVID_TARGET * modeLift;
|
|
268
|
+
var hueDir = VIVID_WARM_ANCHOR;
|
|
269
|
+
if (C > VIVID_EPS) { hueDir = lab.yz / C; }
|
|
270
|
+
let yz = hueDir * max(C, Cmin);
|
|
271
|
+
lab = vec3<f32>(lab.x, yz.x, yz.y);
|
|
272
|
+
return max(oklabToLinearSrgb(lab), vec3<f32>(0.0));
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// ── PBR-Neutral tonemap (named aces() in the GLSL — the tonemap slot) ──
|
|
276
|
+
fn aces(color0: vec3<f32>) -> vec3<f32> {
|
|
277
|
+
let startCompression = 0.8 - 0.04;
|
|
278
|
+
let desaturation = 0.15;
|
|
279
|
+
var color = color0;
|
|
280
|
+
let x = min(color.r, min(color.g, color.b));
|
|
281
|
+
var offset = 0.04;
|
|
282
|
+
if (x < 0.08) { offset = x - 6.25 * x * x; }
|
|
283
|
+
color = color - offset;
|
|
284
|
+
let peak = max(color.r, max(color.g, color.b));
|
|
285
|
+
if (peak < startCompression) { return clamp(color, vec3<f32>(0.0), vec3<f32>(1.0)); }
|
|
286
|
+
let d = 1.0 - startCompression;
|
|
287
|
+
let newPeak = 1.0 - d * d / (peak + d - startCompression);
|
|
288
|
+
color = color * (newPeak / peak);
|
|
289
|
+
let g = 1.0 - 1.0 / (desaturation * (peak - newPeak) + 1.0);
|
|
290
|
+
return clamp(mix(color, newPeak * vec3<f32>(1.0), g), vec3<f32>(0.0), vec3<f32>(1.0));
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// ── Painterly-medium bodies (the keystone WGSL port) ───────────────────────
|
|
294
|
+
// Spliced HERE, after every helper the mediums consume is defined (domainWarp,
|
|
295
|
+
// nucleiField, samplePalette, linOklab, saturate3, oklabToOklch/oklchToOklab,
|
|
296
|
+
// hash21/vnoise/fbm) and before the vertex/fragment stages. applyMedium(col,p,t)
|
|
297
|
+
// is the dispatch the fragment stage calls.
|
|
298
|
+
|
|
299
|
+
// ── Painterly luma + medium scalar accessors ───────────────────────────────
|
|
300
|
+
const W_LUMA: vec3<f32> = vec3<f32>(0.2126, 0.7152, 0.0722);
|
|
301
|
+
|
|
302
|
+
fn mStrokeAmount() -> f32 { return u.scalars4.x; }
|
|
303
|
+
fn mStrokeScale() -> f32 { return u.scalars4.y; }
|
|
304
|
+
fn mStrokeAnisotropy() -> f32 { return u.scalars4.z; }
|
|
305
|
+
fn mCanvasGrain() -> f32 { return u.scalars4.w; }
|
|
306
|
+
fn mWetEdge() -> f32 { return u.scalars5.x; }
|
|
307
|
+
fn mGranulation() -> f32 { return u.scalars5.y; }
|
|
308
|
+
fn mBrokenColor() -> f32 { return u.scalars5.z; }
|
|
309
|
+
fn mKuwaharaQ() -> f32 { return u.scalars5.w; }
|
|
310
|
+
fn mKuwaharaRadius() -> f32 { return u.kuwahara.x; }
|
|
311
|
+
// The metal-medium knobs ride the free cursor.z/.w pad lanes
|
|
312
|
+
// (uniformBridgeWGPU packs them; written 0 on a non-metal config → no-op). These read
|
|
313
|
+
// the IN-STRUCT cursor — the metal light is cursor-synthesized so it crosses to WGSL
|
|
314
|
+
// (a phantom uLightDir read would be flat on the primary; uLightDir is fragment-only).
|
|
315
|
+
fn mMetalPolish() -> f32 { return u.cursor.z; }
|
|
316
|
+
fn mMetalHeightScale() -> f32 { return u.cursor.w; }
|
|
317
|
+
|
|
318
|
+
// ── Gradient pack (the WGSL twin) ──────────────────────────────────────────
|
|
319
|
+
// structureTensorField re-plumbs its already-computed luma gradient (Gx,Gy) out
|
|
320
|
+
// through the return value's .w lane so the metal medium pays ZERO extra taps. 12 bits per
|
|
321
|
+
// bounded component ([-4,4]) fit into one f32; the crayon/kuwahara callers read only .xy/.z.
|
|
322
|
+
fn packGrad(gx: f32, gy: f32) -> f32 {
|
|
323
|
+
let qx = floor(clamp(gx * 0.125 + 0.5, 0.0, 1.0) * 4095.0);
|
|
324
|
+
let qy = floor(clamp(gy * 0.125 + 0.5, 0.0, 1.0) * 4095.0);
|
|
325
|
+
return qx + qy * 4096.0;
|
|
326
|
+
}
|
|
327
|
+
fn unpackGrad(packed: f32) -> vec2<f32> {
|
|
328
|
+
let qy = floor(packed * (1.0 / 4096.0));
|
|
329
|
+
let qx = packed - qy * 4096.0;
|
|
330
|
+
return (vec2<f32>(qx, qy) * (1.0 / 4095.0) - 0.5) * 8.0;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// ── Base color re-sample (the edge-mask operator the mediums Sobel/sector-sample) ──
|
|
334
|
+
// The WGSL twin of mediums.glsl.ts sampleBase: warp -> nuclei field -> palette -> value.
|
|
335
|
+
fn sampleBase(p: vec2<f32>, t: f32) -> vec3<f32> {
|
|
336
|
+
let pw = domainWarp(p, t);
|
|
337
|
+
let nf = nucleiField(pw, t);
|
|
338
|
+
var c = samplePalette(nf.paletteId);
|
|
339
|
+
c = c * (1.0 + u.scalars0.z * nf.valueMod);
|
|
340
|
+
return c;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// ── Broken color (hue + chroma jitter at constant OKLCh L) ──────────────────
|
|
344
|
+
fn brokenColorJitter(c: vec3<f32>, hueSeed: f32, valueSeed: f32, strength: f32) -> vec3<f32> {
|
|
345
|
+
let amt = clamp(mBrokenColor() * strength, 0.0, 1.0);
|
|
346
|
+
if (amt <= 0.001) { return c; }
|
|
347
|
+
var lch = oklabToOklch(linOklab(c));
|
|
348
|
+
lch.z = lch.z + (hueSeed - 0.5) * (32.0 * PI / 180.0) * amt;
|
|
349
|
+
lch.y = max(lch.y * (1.0 + (valueSeed - 0.5) * 0.28 * amt), 0.0);
|
|
350
|
+
return max(oklabToLinearSrgb(oklchToOklab(lch)), vec3<f32>(0.0));
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// ── Structure tensor / edge-tangent flow (the WGSL twin) ───────────────────
|
|
354
|
+
// Returns vec4(tangent.x, tangent.y, A, packGrad(Gx,Gy)) — the minor-eigenvector
|
|
355
|
+
// edge-tangent + coherence + the metal medium's packed gradient. The .xy/.z
|
|
356
|
+
// crayon/kuwahara callers are byte-unchanged.
|
|
357
|
+
fn structureTensorField(p: vec2<f32>, t: f32, fallbackDir: vec2<f32>) -> vec4<f32> {
|
|
358
|
+
let e = 0.0035;
|
|
359
|
+
let l00 = dot(sampleBase(p + vec2<f32>(-e, -e), t), W_LUMA);
|
|
360
|
+
let l10 = dot(sampleBase(p + vec2<f32>(0.0, -e), t), W_LUMA);
|
|
361
|
+
let l20 = dot(sampleBase(p + vec2<f32>( e, -e), t), W_LUMA);
|
|
362
|
+
let l01 = dot(sampleBase(p + vec2<f32>(-e, 0.0), t), W_LUMA);
|
|
363
|
+
let l21 = dot(sampleBase(p + vec2<f32>( e, 0.0), t), W_LUMA);
|
|
364
|
+
let l02 = dot(sampleBase(p + vec2<f32>(-e, e), t), W_LUMA);
|
|
365
|
+
let l12 = dot(sampleBase(p + vec2<f32>(0.0, e), t), W_LUMA);
|
|
366
|
+
let l22 = dot(sampleBase(p + vec2<f32>( e, e), t), W_LUMA);
|
|
367
|
+
let Gx = (l20 + 2.0 * l21 + l22) - (l00 + 2.0 * l01 + l02);
|
|
368
|
+
let Gy = (l02 + 2.0 * l12 + l22) - (l00 + 2.0 * l10 + l20);
|
|
369
|
+
let Jxx = Gx * Gx;
|
|
370
|
+
let Jyy = Gy * Gy;
|
|
371
|
+
let Jxy = Gx * Gy;
|
|
372
|
+
let tr = Jxx + Jyy;
|
|
373
|
+
let disc = sqrt(max((Jxx - Jyy) * (Jxx - Jyy) + 4.0 * Jxy * Jxy, 0.0));
|
|
374
|
+
let lambdaMaj = 0.5 * (tr + disc);
|
|
375
|
+
let lambdaMin = 0.5 * (tr - disc);
|
|
376
|
+
var tangent: vec2<f32>;
|
|
377
|
+
if (disc < 1e-7) {
|
|
378
|
+
tangent = fallbackDir;
|
|
379
|
+
} else {
|
|
380
|
+
let theta = 0.5 * atan2(2.0 * Jxy, Jxx - Jyy);
|
|
381
|
+
tangent = vec2<f32>(-sin(theta), cos(theta));
|
|
382
|
+
}
|
|
383
|
+
var A = (lambdaMaj - lambdaMin) / (lambdaMaj + lambdaMin + 1e-6);
|
|
384
|
+
A = clamp(A, 0.0, 1.0);
|
|
385
|
+
if (dot(tangent, fallbackDir) < 0.0) { tangent = -tangent; }
|
|
386
|
+
let blendW = pow(A, 0.28);
|
|
387
|
+
let dir = normalize(mix(fallbackDir, tangent, blendW) + vec2<f32>(1e-6, 1e-6));
|
|
388
|
+
return vec4<f32>(dir, A, packGrad(Gx, Gy));
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// ── Flow field (the WGSL twin — the simple flow seed the medium fallback dirs use) ──
|
|
392
|
+
fn flowField(p: vec2<f32>, t: f32) -> vec2<f32> {
|
|
393
|
+
// Curl-noise-driven swirl (the medium-default dir; the full radial/swirl/diagonal
|
|
394
|
+
// dispatch rides uniforms the WGSL struct does not carry — the procedural mediums
|
|
395
|
+
// use this multi/curl seed as the fallback the structure tensor relaxes toward).
|
|
396
|
+
let n = fbm(p * 2.0 + vec2<f32>(t * 0.02, t * 0.02));
|
|
397
|
+
let a = n * 6.2831853;
|
|
398
|
+
var dir = vec2<f32>(cos(a), sin(a));
|
|
399
|
+
// Cursor swirl bias (matches the GLSL flow cursor term — the steady attraction).
|
|
400
|
+
let cursorStrength = u.scalars3.y;
|
|
401
|
+
let cursorRadius = u.scalars3.z;
|
|
402
|
+
let cursor = u.cursor.xy;
|
|
403
|
+
if (cursorStrength > 0.001) {
|
|
404
|
+
let toCur = cursor - p;
|
|
405
|
+
let d = length(toCur);
|
|
406
|
+
let r = max(cursorRadius, 0.01);
|
|
407
|
+
let w = exp(-(d * d) / (r * r * 0.5));
|
|
408
|
+
let tangent = vec2<f32>(-toCur.y, toCur.x) / max(d, 1e-4);
|
|
409
|
+
let a0 = atan2(dir.y, dir.x);
|
|
410
|
+
let a1 = atan2(tangent.y, tangent.x);
|
|
411
|
+
var da = a1 - a0;
|
|
412
|
+
da = atan2(sin(da), cos(da));
|
|
413
|
+
let aa = a0 + da * w * cursorStrength;
|
|
414
|
+
dir = vec2<f32>(cos(aa), sin(aa));
|
|
415
|
+
}
|
|
416
|
+
return dir;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// ── Watercolor — wet-edge cauliflowers + granulation + wash banding ─────────
|
|
420
|
+
fn mediumWatercolor(col0: vec3<f32>, p: vec2<f32>, t: f32) -> vec3<f32> {
|
|
421
|
+
var col = col0;
|
|
422
|
+
let eps = 0.004;
|
|
423
|
+
let cx1 = sampleBase(p + vec2<f32>(eps, 0.0), t);
|
|
424
|
+
let cx2 = sampleBase(p - vec2<f32>(eps, 0.0), t);
|
|
425
|
+
let cy1 = sampleBase(p + vec2<f32>(0.0, eps), t);
|
|
426
|
+
let cy2 = sampleBase(p - vec2<f32>(0.0, eps), t);
|
|
427
|
+
let gx = dot(cx1 - cx2, W_LUMA);
|
|
428
|
+
let gy = dot(cy1 - cy2, W_LUMA);
|
|
429
|
+
let edge = sqrt(gx * gx + gy * gy) / (2.0 * eps);
|
|
430
|
+
let mask = smoothstep(0.0, 2.5, edge);
|
|
431
|
+
col = col * mix(1.0, 0.78, mask * mWetEdge());
|
|
432
|
+
|
|
433
|
+
let paper = 0.5 * vnoise(p * 160.0) + 0.5 * vnoise(p * 360.0);
|
|
434
|
+
let pigLoad = 1.0 - dot(col, W_LUMA);
|
|
435
|
+
col = col * (1.0 - mGranulation() * pigLoad * (paper - 0.5));
|
|
436
|
+
|
|
437
|
+
let band = fbm(vec2<f32>(p.x * 1.5, p.y * 0.4));
|
|
438
|
+
col = col * (1.0 + 0.04 * (band - 0.5));
|
|
439
|
+
return col;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
// ── Pastel — anisotropic stroke noise along the flow + tooth grain ──────────
|
|
443
|
+
fn mediumPastel(col0: vec3<f32>, p: vec2<f32>, t: f32) -> vec3<f32> {
|
|
444
|
+
var col = col0;
|
|
445
|
+
let flow = flowField(p, t);
|
|
446
|
+
let perp = vec2<f32>(-flow.y, flow.x);
|
|
447
|
+
let strokeScale = mStrokeScale();
|
|
448
|
+
let along = dot(p, flow) * strokeScale;
|
|
449
|
+
var across = dot(p, perp) * strokeScale;
|
|
450
|
+
across = across + 0.03 * (vnoise(p * 260.0) - 0.5);
|
|
451
|
+
|
|
452
|
+
let aniso = mix(1.0, 0.18, mStrokeAnisotropy());
|
|
453
|
+
let stroke = fbm(vec2<f32>(along * aniso, across));
|
|
454
|
+
col = col * mix(1.0, 0.82 + 0.32 * stroke, mStrokeAmount());
|
|
455
|
+
|
|
456
|
+
let tooth = vnoise(p * 800.0);
|
|
457
|
+
col = col * (1.0 - 0.08 * mStrokeAmount() * (tooth - 0.5));
|
|
458
|
+
return col;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// ── Crayon — DRY wax pigment on paper tooth (the tooth-multiply + scumble) ──
|
|
462
|
+
fn mediumCrayon(col0: vec3<f32>, p: vec2<f32>, t: f32) -> vec3<f32> {
|
|
463
|
+
let flow = structureTensorField(p, t, flowField(p, t)).xy;
|
|
464
|
+
let ang = atan2(flow.y, flow.x);
|
|
465
|
+
let ca = cos(-ang);
|
|
466
|
+
let sa = sin(-ang);
|
|
467
|
+
let pr = vec2<f32>(p.x * ca - p.y * sa, p.x * sa + p.y * ca);
|
|
468
|
+
|
|
469
|
+
let aniso = mix(0.45, 0.95, mStrokeAnisotropy());
|
|
470
|
+
let scale = max(mStrokeScale() * 1.6, 180.0);
|
|
471
|
+
|
|
472
|
+
let t1 = vnoise(vec2<f32>(pr.x * scale * aniso, pr.y * scale));
|
|
473
|
+
let t2 = vnoise(vec2<f32>(pr.x * scale * aniso * 0.4, pr.y * scale * 0.4) + vec2<f32>(11.0, 11.0));
|
|
474
|
+
let t3 = vnoise(vec2<f32>(pr.x * scale * aniso * 2.1, pr.y * scale * 2.1) + vec2<f32>(23.0, 23.0));
|
|
475
|
+
let tooth = 0.55 * t1 + 0.30 * t2 + 0.15 * t3;
|
|
476
|
+
|
|
477
|
+
let pressure = clamp(mStrokeAmount(), 0.0, 1.0);
|
|
478
|
+
let bite = mix(0.18, 0.46, pressure);
|
|
479
|
+
var result = col0 * (1.0 - bite * (0.5 - tooth));
|
|
480
|
+
|
|
481
|
+
let scumbleMask = smoothstep(0.42, 0.78, vnoise(vec2<f32>(pr.x * scale * 0.55, pr.y * scale * 0.22) + vec2<f32>(7.0, 7.0)));
|
|
482
|
+
let scumbleCoverage = scumbleMask * pressure * 0.7;
|
|
483
|
+
let paper = col0 * mix(0.80, 0.94, pressure);
|
|
484
|
+
result = mix(paper, result, scumbleCoverage);
|
|
485
|
+
|
|
486
|
+
let pigmentCell = floor(pr * max(scale * 0.18, 32.0));
|
|
487
|
+
let pigmentMask = smoothstep(0.28, 0.82, vnoise(pr * scale * 0.21 + vec2<f32>(19.0, 19.0)));
|
|
488
|
+
result = brokenColorJitter(
|
|
489
|
+
result,
|
|
490
|
+
hash21(pigmentCell + vec2<f32>(17.0, 17.0)),
|
|
491
|
+
hash21(pigmentCell * 2.1 + vec2<f32>(31.0, 31.0)),
|
|
492
|
+
0.45 + 0.55 * pigmentMask
|
|
493
|
+
);
|
|
494
|
+
|
|
495
|
+
result = saturate3(result, 1.08);
|
|
496
|
+
return result;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
// ── Kuwahara — the SOFT anisotropic generalized Kuwahara painterly finish ────
|
|
500
|
+
// THE KEYSTONE (Kyprianidis 2010). Aurora is a PROCEDURAL field (no input texture) so the
|
|
501
|
+
// operator runs over sampleBase directly: an elliptical kernel oriented along the structure
|
|
502
|
+
// tensor (elongated along the edge-tangent, narrowed across by the anisotropy), 8 OVERLAPPING
|
|
503
|
+
// sectors via SMOOTH gaussian-angular weights, blended by 1/(1+var^q) (the SOFT criterion →
|
|
504
|
+
// no 8-spoke pinwheel by construction). 4 rings × 8 angular taps = 32 procedural samples.
|
|
505
|
+
fn mediumKuwahara(col0: vec3<f32>, p: vec2<f32>, t: f32) -> vec3<f32> {
|
|
506
|
+
let stf = structureTensorField(p, t, flowField(p, t));
|
|
507
|
+
let tangent = stf.xy;
|
|
508
|
+
let A = stf.z;
|
|
509
|
+
// The studio knob drives the patch radius; clamp into the procedural patch band.
|
|
510
|
+
let radius = clamp(mKuwaharaRadius() + mStrokeScale() * 0.00018, 0.006, 0.024);
|
|
511
|
+
let aniso = mix(1.0, 0.34, clamp(A, 0.0, 1.0));
|
|
512
|
+
let ax = tangent;
|
|
513
|
+
let ay = vec2<f32>(-tangent.y, tangent.x);
|
|
514
|
+
|
|
515
|
+
// Per-sector weighted sums (8 sectors). WGSL has no runtime-indexed local arrays of
|
|
516
|
+
// vectors as cleanly as GLSL, so unroll the sector accumulators explicitly.
|
|
517
|
+
var mSum: array<vec3<f32>, 8>;
|
|
518
|
+
var sSum: array<vec3<f32>, 8>;
|
|
519
|
+
var wSum: array<f32, 8>;
|
|
520
|
+
for (var i = 0; i < 8; i = i + 1) {
|
|
521
|
+
mSum[i] = vec3<f32>(0.0);
|
|
522
|
+
sSum[i] = vec3<f32>(0.0);
|
|
523
|
+
wSum[i] = 0.0;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
let RINGS = 4;
|
|
527
|
+
let TAPS = 8;
|
|
528
|
+
for (var r = 1; r <= RINGS; r = r + 1) {
|
|
529
|
+
let rr = f32(r) / f32(RINGS);
|
|
530
|
+
let radial = 1.0 - 0.6 * rr;
|
|
531
|
+
for (var a = 0; a < TAPS; a = a + 1) {
|
|
532
|
+
let ang = 6.2831853 * f32(a) / f32(TAPS);
|
|
533
|
+
let dirE = ax * cos(ang) + ay * (sin(ang) * aniso);
|
|
534
|
+
let off = dirE * (radius * rr);
|
|
535
|
+
let c = sampleBase(p + off, t);
|
|
536
|
+
for (var k = 0; k < 8; k = k + 1) {
|
|
537
|
+
let sectorAng = 6.2831853 * f32(k) / 8.0;
|
|
538
|
+
var d = ang - sectorAng;
|
|
539
|
+
d = atan2(sin(d), cos(d));
|
|
540
|
+
let sw = exp(-d * d * 2.2) * radial;
|
|
541
|
+
mSum[k] = mSum[k] + c * sw;
|
|
542
|
+
sSum[k] = sSum[k] + c * c * sw;
|
|
543
|
+
wSum[k] = wSum[k] + sw;
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
let q = max(mKuwaharaQ(), 1.0);
|
|
549
|
+
var accum = vec3<f32>(0.0);
|
|
550
|
+
var accumW = 0.0;
|
|
551
|
+
for (var k = 0; k < 8; k = k + 1) {
|
|
552
|
+
let wk = max(wSum[k], 1e-4);
|
|
553
|
+
let mean = mSum[k] / wk;
|
|
554
|
+
let var3 = max(sSum[k] / wk - mean * mean, vec3<f32>(0.0));
|
|
555
|
+
let variance = dot(var3, W_LUMA);
|
|
556
|
+
let sectorW = 1.0 / (1.0 + pow(variance * 320.0, q));
|
|
557
|
+
accum = accum + mean * sectorW;
|
|
558
|
+
accumW = accumW + sectorW;
|
|
559
|
+
}
|
|
560
|
+
var result = accum / max(accumW, 1e-4);
|
|
561
|
+
|
|
562
|
+
// Anchor in near-flat zones so the smoothing only bites at edges.
|
|
563
|
+
let center = sampleBase(p, t);
|
|
564
|
+
result = mix(center, result, clamp(0.35 + 0.65 * A, 0.0, 1.0));
|
|
565
|
+
|
|
566
|
+
// Faint canvas tooth + pigment-saturation so the flattened patches read as oil paint.
|
|
567
|
+
let tooth = vnoise(p * 300.0) - 0.5;
|
|
568
|
+
result = result * (1.0 + tooth * 0.06 * mCanvasGrain());
|
|
569
|
+
result = saturate3(result, 1.04);
|
|
570
|
+
|
|
571
|
+
return mix(col0, result, clamp(mStrokeAmount(), 0.0, 1.0));
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
// ── Metal — the two-term anisotropic BRDF (uMedium==8/9; the WGSL twin) ──────
|
|
575
|
+
// The field re-lights as warm folded metal: the luma HEIGHT field (the packed
|
|
576
|
+
// structure-tensor gradient → the surface normal) catches an anisotropic Blinn streak
|
|
577
|
+
// (brushed metal, running ALONG the coherent edge-tangent) plus a sharp crest, both
|
|
578
|
+
// raked by the IN-STRUCT cursor-synth light (crosses to WGSL — never uLightDir). The
|
|
579
|
+
// catch is the achromatic-warm anchor (never a cold chrome-blue). ZERO extra taps —
|
|
580
|
+
// the gradient is unpacked from the tensor's .w lane the caller already computed.
|
|
581
|
+
const METAL_CATCH_WARM: vec3<f32> = vec3<f32>(1.0, 0.97, 0.90);
|
|
582
|
+
const METAL_HEIGHT_SCALE: f32 = 2.2;
|
|
583
|
+
const METAL_LIGHT_Z: f32 = 0.55;
|
|
584
|
+
const METAL_IDLE_RAKE: vec2<f32> = vec2<f32>(0.32, 0.34);
|
|
585
|
+
const METAL_SHININESS_ANISO: f32 = 6.0;
|
|
586
|
+
const METAL_SHININESS_CREST: f32 = 40.0;
|
|
587
|
+
const METAL_COHERENCE_FLOOR: f32 = 0.22;
|
|
588
|
+
const METAL_BODY_FLOOR: f32 = 0.42;
|
|
589
|
+
const METAL_GRADIENT_FLATTEN: f32 = 0.55;
|
|
590
|
+
const METAL_SPARKLE_DENSITY: f32 = 240.0;
|
|
591
|
+
const METAL_SPARKLE_THRESH: f32 = 0.72;
|
|
592
|
+
const METAL_SPARKLE_AMP: f32 = 0.6;
|
|
593
|
+
|
|
594
|
+
fn metalShade(baseCol: vec3<f32>, p: vec2<f32>, stf: vec4<f32>) -> vec3<f32> {
|
|
595
|
+
let tangent = stf.xy;
|
|
596
|
+
let A = stf.z;
|
|
597
|
+
let grad = unpackGrad(stf.w);
|
|
598
|
+
let N = normalize(vec3<f32>(grad * (METAL_HEIGHT_SCALE * mMetalHeightScale()), 1.0));
|
|
599
|
+
let V = vec3<f32>(0.0, 0.0, 1.0);
|
|
600
|
+
// Cursor-synth rake light (u.cursor is in-struct — crosses to WGSL).
|
|
601
|
+
let L = normalize(vec3<f32>((u.cursor.xy - p) + METAL_IDLE_RAKE, METAL_LIGHT_Z));
|
|
602
|
+
let H = normalize(L + V);
|
|
603
|
+
// Anisotropic streak — brushed metal along the edge-tangent.
|
|
604
|
+
let tH = dot(normalize(tangent), H.xy);
|
|
605
|
+
let sinTH = sqrt(clamp(1.0 - tH * tH, 0.0, 1.0));
|
|
606
|
+
let streak = pow(clamp(sinTH, 0.0, 1.0), METAL_SHININESS_ANISO);
|
|
607
|
+
let crest = pow(clamp(dot(N, H), 0.0, 1.0), METAL_SHININESS_CREST);
|
|
608
|
+
var spec = streak * crest;
|
|
609
|
+
spec = spec * smoothstep(0.0, METAL_COHERENCE_FLOOR, A);
|
|
610
|
+
// Technicolor valley base — the body keeps the FIELD hue; luma rides the relief.
|
|
611
|
+
let diff = clamp(dot(N, L), 0.0, 1.0);
|
|
612
|
+
let body = baseCol * (METAL_BODY_FLOOR + (1.0 - METAL_BODY_FLOOR) * diff);
|
|
613
|
+
return body + METAL_CATCH_WARM * (spec * clamp(mMetalPolish(), 0.0, 4.0));
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
fn mediumMetal(col: vec3<f32>, p: vec2<f32>, t: f32) -> vec3<f32> {
|
|
617
|
+
let stf = structureTensorField(p, t, flowField(p, t));
|
|
618
|
+
return metalShade(col, p, stf);
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
// metal-gradient (uMedium==9) — the SAME BRDF over a pre-flattened base + the
|
|
622
|
+
// twinkle-in-place flake sparkle (position FIXED per cell, phase-animated, facing-gated).
|
|
623
|
+
fn mediumMetalGradient(col: vec3<f32>, p: vec2<f32>, t: f32) -> vec3<f32> {
|
|
624
|
+
let stf = structureTensorField(p, t, flowField(p, t));
|
|
625
|
+
let flat = mix(col, vec3<f32>(dot(col, W_LUMA)), METAL_GRADIENT_FLATTEN);
|
|
626
|
+
var metal = metalShade(flat, p, stf);
|
|
627
|
+
let grad = unpackGrad(stf.w);
|
|
628
|
+
let facing = normalize(vec3<f32>(grad * (METAL_HEIGHT_SCALE * mMetalHeightScale()), 1.0)).z;
|
|
629
|
+
let cell = floor(p * METAL_SPARKLE_DENSITY);
|
|
630
|
+
let seed = hash21(cell);
|
|
631
|
+
let tw = pow(clamp(sin(t + seed * 6.2831853), 0.0, 1.0), 40.0);
|
|
632
|
+
let flakeGate = step(METAL_SPARKLE_THRESH, seed);
|
|
633
|
+
metal = metal + METAL_CATCH_WARM * (tw * flakeGate * clamp(facing, 0.0, 1.0) * METAL_SPARKLE_AMP);
|
|
634
|
+
return metal;
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
// ── Medium dispatch (the WGSL twin of the GLSL main() if-ladder) ────────────
|
|
638
|
+
// uMedium: 0 smooth · 1 pastel · 2 watercolor · 3 oil · 4 crayon · 5 vangogh ·
|
|
639
|
+
// 6 oil-pastel · 7 kuwahara · 8 metal · 9 metal-gradient. The cheap peer mediums
|
|
640
|
+
// (pastel/watercolor/crayon) + kuwahara + metal port their own bodies; the
|
|
641
|
+
// oil/vangogh/oil-pastel STROKE cascade renders the anisotropic-Kuwahara PAINTERLY
|
|
642
|
+
// finish here (a real oil-paint read, never the smooth core — the "NO FALLBACKS on
|
|
643
|
+
// Safari" mandate; the full per-dab Starry-Night stroke WGSL remains a separate
|
|
644
|
+
// full-fidelity port).
|
|
645
|
+
fn applyMedium(col: vec3<f32>, p: vec2<f32>, t: f32) -> vec3<f32> {
|
|
646
|
+
let medium = u.ints1.x;
|
|
647
|
+
if (medium == 1) { return mediumPastel(col, p, t); }
|
|
648
|
+
if (medium == 2) { return mediumWatercolor(col, p, t); }
|
|
649
|
+
if (medium == 4) { return mediumCrayon(col, p, t); }
|
|
650
|
+
// Metal uses both renderer paths; a fragment-only implementation is invisible on the
|
|
651
|
+
// WGSL primary. IDs 8 and 9 select metal and metal-gradient respectively.
|
|
652
|
+
if (medium == 8) { return mediumMetal(col, p, t); }
|
|
653
|
+
if (medium == 9) { return mediumMetalGradient(col, p, t); }
|
|
654
|
+
// oil(3), vangogh(5), oil-pastel(6), kuwahara(7) all render the painterly
|
|
655
|
+
// anisotropic-Kuwahara finish on the WGSL primary (the WebGL2 fallback carries the
|
|
656
|
+
// full per-dab stroke cascade for oil/vangogh/oil-pastel).
|
|
657
|
+
if (medium == 3 || medium == 5 || medium == 6 || medium == 7) {
|
|
658
|
+
return mediumKuwahara(col, p, t);
|
|
659
|
+
}
|
|
660
|
+
return col;
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
|
|
664
|
+
// ── Full-screen triangle vertex stage (the pilot idiom — no vertex buffer) ──
|
|
665
|
+
struct VSOut {
|
|
666
|
+
@builtin(position) pos: vec4<f32>,
|
|
667
|
+
@location(0) uv: vec2<f32>,
|
|
668
|
+
};
|
|
669
|
+
|
|
670
|
+
@vertex
|
|
671
|
+
fn vs_main(@builtin(vertex_index) vi: u32) -> VSOut {
|
|
672
|
+
// NDC corners of the covering triangle (-1,-1), (3,-1), (-1,3).
|
|
673
|
+
var p = vec2<f32>(-1.0, -1.0);
|
|
674
|
+
if (vi == 1u) { p = vec2<f32>(3.0, -1.0); }
|
|
675
|
+
else if (vi == 2u) { p = vec2<f32>(-1.0, 3.0); }
|
|
676
|
+
var out: VSOut;
|
|
677
|
+
out.pos = vec4<f32>(p, 0.0, 1.0);
|
|
678
|
+
// vUv = aPos * 0.5 + 0.5 (the aurora.vert convention).
|
|
679
|
+
out.uv = p * 0.5 + 0.5;
|
|
680
|
+
return out;
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
// ── Fragment stage (the main() transcription) ──
|
|
684
|
+
@fragment
|
|
685
|
+
fn fs_main(in: VSOut) -> @location(0) vec4<f32> {
|
|
686
|
+
let t = u.scalars0.x;
|
|
687
|
+
let valueVariance = u.scalars0.z;
|
|
688
|
+
let breathDepth = u.scalars2.w;
|
|
689
|
+
let breathPeriod = u.scalars3.x;
|
|
690
|
+
let saturation = u.scalars1.z;
|
|
691
|
+
let paperGrain = u.scalars1.w;
|
|
692
|
+
let alpha = u.scalars2.x;
|
|
693
|
+
let vividness = u.scalars3.w;
|
|
694
|
+
|
|
695
|
+
let uv = in.uv;
|
|
696
|
+
let pN = uv;
|
|
697
|
+
|
|
698
|
+
let p_warp = domainWarp(pN, t);
|
|
699
|
+
|
|
700
|
+
let nf = nucleiField(p_warp, t);
|
|
701
|
+
var col = samplePalette(nf.paletteId);
|
|
702
|
+
col = col * (1.0 + valueVariance * nf.valueMod);
|
|
703
|
+
|
|
704
|
+
// Breath — slow global luminance wobble.
|
|
705
|
+
let breath = sin(t * 6.2831 / max(breathPeriod, 1.0));
|
|
706
|
+
col = col * (1.0 + breathDepth * breath * 0.5);
|
|
707
|
+
|
|
708
|
+
// Painterly-medium dispatch. uMedium 0 (smooth) is a
|
|
709
|
+
// no-op pass-through so the DEFAULT smooth config renders unchanged
|
|
710
|
+
// (the parity capture); uMedium 1-7 render the painterly
|
|
711
|
+
// bodies (pastel/watercolor/crayon/kuwahara) or the anisotropic-Kuwahara finish
|
|
712
|
+
// (oil/vangogh/oil-pastel) — never a silent smooth degrade on Safari 26.
|
|
713
|
+
col = applyMedium(col, pN, t);
|
|
714
|
+
|
|
715
|
+
// Cursor-local luminance lean, byte-parallel with the GLSL path.
|
|
716
|
+
let cursorDelta = pN - u.cursor.xy;
|
|
717
|
+
let cursorRadius = max(u.scalars3.z, 0.01);
|
|
718
|
+
let cursorLean = exp(-dot(cursorDelta, cursorDelta) / (cursorRadius * cursorRadius * 0.5));
|
|
719
|
+
col = col * (1.0 + 0.12 * cursorLean * u.scalars3.y);
|
|
720
|
+
|
|
721
|
+
// Saturation trim.
|
|
722
|
+
col = saturate3(col, saturation);
|
|
723
|
+
|
|
724
|
+
// The chroma floor is warm-anchored and hue-preserving. The WGSL
|
|
725
|
+
// twin of the GLSL call; vividness:0 is a no-op so the smooth/pale default stays gated.
|
|
726
|
+
col = vividnessFloor(col, vividness);
|
|
727
|
+
|
|
728
|
+
// Tonemap + film grain.
|
|
729
|
+
col = aces(col);
|
|
730
|
+
// gl_FragCoord.xy → the device-pixel position (the WGSL @builtin(position)).
|
|
731
|
+
let fragCoord = in.pos.xy;
|
|
732
|
+
let grain = hash21(fragCoord + t * 17.0);
|
|
733
|
+
col = col + (grain - 0.5) * paperGrain;
|
|
734
|
+
|
|
735
|
+
col = clamp(col * 0.985 + 0.008, vec3<f32>(0.0), vec3<f32>(1.0));
|
|
736
|
+
|
|
737
|
+
// MANDATORY OETF — closes the seam (the whole pipeline above runs in LINEAR).
|
|
738
|
+
col = linearToSrgb(col);
|
|
739
|
+
|
|
740
|
+
// 1-LSB triangular IGN dither in DISPLAY space, AFTER the OETF.
|
|
741
|
+
col = col + (1.0 / 255.0) * (ign(fragCoord) - 0.5);
|
|
742
|
+
|
|
743
|
+
// Premultiply on DISPLAY-space color (matches the WebGL2 path: OETF, then premul).
|
|
744
|
+
return vec4<f32>(col * alpha, alpha);
|
|
745
|
+
}
|
|
746
|
+
`, m = `
|
|
747
|
+
const MAX_NUCLEI: i32 = 8;
|
|
748
|
+
const PI: f32 = 3.141592653589793;
|
|
749
|
+
const BLUR_RINGS: i32 = 3;
|
|
750
|
+
const BLUR_SECTORS: i32 = 8;
|
|
751
|
+
|
|
752
|
+
// The image program's OWN uniform struct (packed vec4 lanes — trivial std140/WGSL
|
|
753
|
+
// alignment). DISTINCT from the palette program's 672-byte struct (a separate program).
|
|
754
|
+
struct ImageUniforms {
|
|
755
|
+
// scalars0: (uTime, uWarpAmount, uWarpScale, uWarpDrift)
|
|
756
|
+
scalars0: vec4<f32>,
|
|
757
|
+
// scalars1: (uSoftmaxBeta, uNucleiDrift, uCursorStrength, uCursorRadius)
|
|
758
|
+
scalars1: vec4<f32>,
|
|
759
|
+
// scalars2: (uSaturation, uPaperGrain, uAlpha, uVividness)
|
|
760
|
+
scalars2: vec4<f32>,
|
|
761
|
+
// image: (uBlurMin, uBlurMax, uImageAspect, _)
|
|
762
|
+
image: vec4<f32>,
|
|
763
|
+
// cursor: (uCursor.x, uCursor.y, _, _)
|
|
764
|
+
cursor: vec4<f32>,
|
|
765
|
+
// ints: (uNucleiCount, uNoiseOctaves, _, _)
|
|
766
|
+
ints: vec4<i32>,
|
|
767
|
+
// nuc0[i] = (pos.x, pos.y, radius, valueBias); nuc1[i] = (driftRadius, driftPhase, elong, angle)
|
|
768
|
+
nuc0: array<vec4<f32>, 8>,
|
|
769
|
+
nuc1: array<vec4<f32>, 8>,
|
|
770
|
+
};
|
|
771
|
+
|
|
772
|
+
@group(0) @binding(0) var<uniform> u: ImageUniforms;
|
|
773
|
+
@group(0) @binding(1) var imgTex: texture_2d<f32>;
|
|
774
|
+
@group(0) @binding(2) var imgSampler: sampler;
|
|
775
|
+
|
|
776
|
+
const K_NUCLEI: f32 = 14.0;
|
|
777
|
+
const K_WARP: f32 = 5.0;
|
|
778
|
+
|
|
779
|
+
// ── Noise (aurora-local hash21/vnoise/fbm — the same compact foundation) ──
|
|
780
|
+
fn hash21(p0: vec2<f32>) -> f32 {
|
|
781
|
+
var p = fract(p0 * vec2<f32>(123.34, 456.21));
|
|
782
|
+
p = p + dot(p, p + 45.32);
|
|
783
|
+
return fract(p.x * p.y);
|
|
784
|
+
}
|
|
785
|
+
fn vnoise(p: vec2<f32>) -> f32 {
|
|
786
|
+
let i = floor(p);
|
|
787
|
+
let f = fract(p);
|
|
788
|
+
let uu = f * f * (3.0 - 2.0 * f);
|
|
789
|
+
let a = hash21(i);
|
|
790
|
+
let b = hash21(i + vec2<f32>(1.0, 0.0));
|
|
791
|
+
let c = hash21(i + vec2<f32>(0.0, 1.0));
|
|
792
|
+
let d = hash21(i + vec2<f32>(1.0, 1.0));
|
|
793
|
+
return mix(mix(a, b, uu.x), mix(c, d, uu.x), uu.y);
|
|
794
|
+
}
|
|
795
|
+
${s}
|
|
796
|
+
fn fbm(p0: vec2<f32>) -> f32 {
|
|
797
|
+
var v = 0.0;
|
|
798
|
+
var a = 0.5;
|
|
799
|
+
var p = p0;
|
|
800
|
+
let octaves = u.ints.y;
|
|
801
|
+
for (var i = 0; i < 5; i = i + 1) {
|
|
802
|
+
if (i >= octaves) { break; }
|
|
803
|
+
v = v + a * vnoise(p);
|
|
804
|
+
p = FBM_ROT * p * 2.02;
|
|
805
|
+
a = a * 0.5;
|
|
806
|
+
}
|
|
807
|
+
return v;
|
|
808
|
+
}
|
|
809
|
+
fn ign(p: vec2<f32>) -> f32 {
|
|
810
|
+
return fract(52.9829189 * fract(dot(p, vec2<f32>(0.06711056, 0.00583715))));
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
${a}
|
|
814
|
+
${o}
|
|
815
|
+
|
|
816
|
+
fn linOklab(lin: vec3<f32>) -> vec3<f32> {
|
|
817
|
+
let lms = LINEAR_SRGB_TO_LMS * lin;
|
|
818
|
+
return LMS_TO_OKLAB * cbrt3(lms);
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
// The Quilez double-warp (fbm) + the cursor swirl — the drift that moves the blur zone.
|
|
822
|
+
fn domainWarp(p: vec2<f32>, t: f32) -> vec2<f32> {
|
|
823
|
+
let warpAmount = u.scalars0.y;
|
|
824
|
+
let warpScale = u.scalars0.z;
|
|
825
|
+
let warpDrift = u.scalars0.w;
|
|
826
|
+
let cursorStrength = u.scalars1.z;
|
|
827
|
+
let cursorRadius = u.scalars1.w;
|
|
828
|
+
let cursor = u.cursor.xy;
|
|
829
|
+
let q = vec2<f32>(fbm(p * warpScale + vec2<f32>(0.0, 0.0) + t * warpDrift * K_WARP),
|
|
830
|
+
fbm(p * warpScale + vec2<f32>(5.2, 1.3) + t * warpDrift * K_WARP));
|
|
831
|
+
let r = vec2<f32>(fbm(p * warpScale + 4.0 * q + vec2<f32>(1.7, 9.2)),
|
|
832
|
+
fbm(p * warpScale + 4.0 * q + vec2<f32>(8.3, 2.8)));
|
|
833
|
+
var warped = p + warpAmount * r;
|
|
834
|
+
if (cursorStrength > 0.001) {
|
|
835
|
+
let toP = p - cursor;
|
|
836
|
+
let d = length(toP);
|
|
837
|
+
let rr = max(cursorRadius, 0.01);
|
|
838
|
+
let w = exp(-(d * d) / (rr * rr * 0.45));
|
|
839
|
+
let ang = w * cursorStrength * 2.1;
|
|
840
|
+
let ca = cos(ang);
|
|
841
|
+
let sa = sin(ang);
|
|
842
|
+
let rotated = vec2<f32>(ca * toP.x - sa * toP.y, sa * toP.x + ca * toP.y) + cursor;
|
|
843
|
+
warped = mix(warped, rotated + warpAmount * r * 0.7, w * cursorStrength);
|
|
844
|
+
}
|
|
845
|
+
return warped;
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
// The drifting BLUR ZONE — the anisotropic-Gaussian nuclei softmax (the SAME field the
|
|
849
|
+
// palette program reads), drift-coupled.
|
|
850
|
+
fn zoneField(p: vec2<f32>, t: f32) -> f32 {
|
|
851
|
+
let nucleiCount = u.ints.x;
|
|
852
|
+
let nucleiDrift = u.scalars1.y;
|
|
853
|
+
let softmaxBeta = u.scalars1.x;
|
|
854
|
+
var accum = 0.0;
|
|
855
|
+
var accumW = 0.0;
|
|
856
|
+
for (var i = 0; i < MAX_NUCLEI; i = i + 1) {
|
|
857
|
+
if (i >= nucleiCount) { break; }
|
|
858
|
+
let n0 = u.nuc0[i]; // pos.x, pos.y, radius, valueBias
|
|
859
|
+
let n1 = u.nuc1[i]; // driftRadius, driftPhase, elong, angle
|
|
860
|
+
let posI = n0.xy + n1.x * vec2<f32>(
|
|
861
|
+
cos(t * nucleiDrift * K_NUCLEI + n1.y),
|
|
862
|
+
sin(t * nucleiDrift * K_NUCLEI + n1.y * 1.13));
|
|
863
|
+
let diff = p - posI;
|
|
864
|
+
let ca = cos(n1.w);
|
|
865
|
+
let sa = sin(n1.w);
|
|
866
|
+
let local = vec2<f32>(ca * diff.x + sa * diff.y, -sa * diff.x + ca * diff.y);
|
|
867
|
+
let along = local.x / max(n1.z, 0.01);
|
|
868
|
+
let d2 = along * along + local.y * local.y;
|
|
869
|
+
let rad = max(n0.z, 0.01);
|
|
870
|
+
let w = exp(-softmaxBeta * d2 / (rad * rad));
|
|
871
|
+
accum = accum + w * (0.5 + 0.5 * n0.w);
|
|
872
|
+
accumW = accumW + w;
|
|
873
|
+
}
|
|
874
|
+
return clamp(accum / max(accumW, 1e-4), 0.0, 1.0);
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
fn coverUv(uv: vec2<f32>) -> vec2<f32> {
|
|
878
|
+
let aspect = max(u.image.z, 0.0001);
|
|
879
|
+
var c = uv - vec2<f32>(0.5);
|
|
880
|
+
c.x = c.x * aspect;
|
|
881
|
+
let s = 1.0 / max(aspect, 1.0);
|
|
882
|
+
return c * s + vec2<f32>(0.5);
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
// The bounded 24-tap zone blur — a FIXED 3-ring × 8-sector stratified kernel, radius
|
|
886
|
+
// per-fragment, sampled in LINEAR light. textureSampleLevel (explicit LOD 0) — WGSL has
|
|
887
|
+
// no implicit derivative in a varying-radius loop.
|
|
888
|
+
fn zoneBlur(uv: vec2<f32>, radius: f32) -> vec3<f32> {
|
|
889
|
+
let aspect = max(u.image.z, 0.0001);
|
|
890
|
+
var sum = srgbToLinear(textureSampleLevel(imgTex, imgSampler, coverUv(uv), 0.0).rgb);
|
|
891
|
+
var wsum = 1.0;
|
|
892
|
+
for (var ring = 1; ring <= BLUR_RINGS; ring = ring + 1) {
|
|
893
|
+
let rr = radius * (f32(ring) / f32(BLUR_RINGS));
|
|
894
|
+
for (var s = 0; s < BLUR_SECTORS; s = s + 1) {
|
|
895
|
+
let a = (f32(s) + 0.5 * f32(ring)) / f32(BLUR_SECTORS) * 2.0 * PI;
|
|
896
|
+
let off = vec2<f32>(cos(a) / aspect, sin(a)) * rr;
|
|
897
|
+
sum = sum + srgbToLinear(textureSampleLevel(imgTex, imgSampler, coverUv(uv + off), 0.0).rgb);
|
|
898
|
+
wsum = wsum + 1.0;
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
return sum / wsum;
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
const VIVID_TARGET: f32 = 0.115;
|
|
905
|
+
const VIVID_EPS: f32 = 0.012;
|
|
906
|
+
const VIVID_WARM_ANCHOR: vec2<f32> = vec2<f32>(0.34202, 0.93969);
|
|
907
|
+
fn vividnessFloor(c: vec3<f32>, vividness: f32) -> vec3<f32> {
|
|
908
|
+
if (vividness <= 0.0001) { return c; }
|
|
909
|
+
var lab = linOklab(c);
|
|
910
|
+
let C = length(lab.yz);
|
|
911
|
+
let modeLift = mix(1.18, 1.0, clamp(lab.x * 1.4, 0.0, 1.0));
|
|
912
|
+
let Cmin = vividness * VIVID_TARGET * modeLift;
|
|
913
|
+
var hueDir = VIVID_WARM_ANCHOR;
|
|
914
|
+
if (C > VIVID_EPS) { hueDir = lab.yz / C; }
|
|
915
|
+
let yz = hueDir * max(C, Cmin);
|
|
916
|
+
lab = vec3<f32>(lab.x, yz.x, yz.y);
|
|
917
|
+
return max(oklabToLinearSrgb(lab), vec3<f32>(0.0));
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
fn saturate3(c: vec3<f32>, amt: f32) -> vec3<f32> {
|
|
921
|
+
var lch = oklabToOklch(linOklab(c));
|
|
922
|
+
lch.y = max(lch.y * amt, 0.0);
|
|
923
|
+
return max(oklabToLinearSrgb(oklchToOklab(lch)), vec3<f32>(0.0));
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
fn aces(color0: vec3<f32>) -> vec3<f32> {
|
|
927
|
+
let startCompression = 0.8 - 0.04;
|
|
928
|
+
let desaturation = 0.15;
|
|
929
|
+
var color = color0;
|
|
930
|
+
let x = min(color.r, min(color.g, color.b));
|
|
931
|
+
var offset = 0.04;
|
|
932
|
+
if (x < 0.08) { offset = x - 6.25 * x * x; }
|
|
933
|
+
color = color - offset;
|
|
934
|
+
let peak = max(color.r, max(color.g, color.b));
|
|
935
|
+
if (peak < startCompression) { return clamp(color, vec3<f32>(0.0), vec3<f32>(1.0)); }
|
|
936
|
+
let d = 1.0 - startCompression;
|
|
937
|
+
let newPeak = 1.0 - d * d / (peak + d - startCompression);
|
|
938
|
+
color = color * (newPeak / peak);
|
|
939
|
+
let g = 1.0 - 1.0 / (desaturation * (peak - newPeak) + 1.0);
|
|
940
|
+
return clamp(mix(color, newPeak * vec3<f32>(1.0), g), vec3<f32>(0.0), vec3<f32>(1.0));
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
struct VSOut {
|
|
944
|
+
@builtin(position) pos: vec4<f32>,
|
|
945
|
+
@location(0) uv: vec2<f32>,
|
|
946
|
+
};
|
|
947
|
+
|
|
948
|
+
@vertex
|
|
949
|
+
fn vs_main(@builtin(vertex_index) vi: u32) -> VSOut {
|
|
950
|
+
var p = vec2<f32>(-1.0, -1.0);
|
|
951
|
+
if (vi == 1u) { p = vec2<f32>(3.0, -1.0); }
|
|
952
|
+
else if (vi == 2u) { p = vec2<f32>(-1.0, 3.0); }
|
|
953
|
+
var out: VSOut;
|
|
954
|
+
out.pos = vec4<f32>(p, 0.0, 1.0);
|
|
955
|
+
out.uv = p * 0.5 + 0.5;
|
|
956
|
+
return out;
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
@fragment
|
|
960
|
+
fn fs_main(in: VSOut) -> @location(0) vec4<f32> {
|
|
961
|
+
let t = u.scalars0.x;
|
|
962
|
+
let saturation = u.scalars2.x;
|
|
963
|
+
let paperGrain = u.scalars2.y;
|
|
964
|
+
let alpha = u.scalars2.z;
|
|
965
|
+
let vividness = u.scalars2.w;
|
|
966
|
+
let blurMin = u.image.x;
|
|
967
|
+
let blurMax = u.image.y;
|
|
968
|
+
|
|
969
|
+
let uv = in.uv;
|
|
970
|
+
let p_warp = domainWarp(uv, t);
|
|
971
|
+
let zone = zoneField(p_warp, t);
|
|
972
|
+
|
|
973
|
+
let radius = mix(blurMin, blurMax, zone);
|
|
974
|
+
var col = zoneBlur(uv, radius);
|
|
975
|
+
|
|
976
|
+
let cursorDelta = uv - u.cursor.xy;
|
|
977
|
+
let cursorRadius = max(u.scalars1.w, 0.01);
|
|
978
|
+
let cursorLean = exp(-dot(cursorDelta, cursorDelta) / (cursorRadius * cursorRadius * 0.5));
|
|
979
|
+
col = col * (1.0 + 0.12 * cursorLean * u.scalars1.z);
|
|
980
|
+
|
|
981
|
+
col = saturate3(col, saturation);
|
|
982
|
+
col = vividnessFloor(col, vividness);
|
|
983
|
+
|
|
984
|
+
col = aces(col);
|
|
985
|
+
let fragCoord = in.pos.xy;
|
|
986
|
+
let grain = hash21(fragCoord + t * 17.0);
|
|
987
|
+
col = col + (grain - 0.5) * paperGrain;
|
|
988
|
+
col = clamp(col * 0.985 + 0.008, vec3<f32>(0.0), vec3<f32>(1.0));
|
|
989
|
+
|
|
990
|
+
col = linearToSrgb(col);
|
|
991
|
+
col = col + (1.0 / 255.0) * (ign(fragCoord) - 0.5);
|
|
992
|
+
|
|
993
|
+
return vec4<f32>(col * alpha, alpha);
|
|
994
|
+
}
|
|
995
|
+
`, h = {
|
|
996
|
+
scalars0: 0,
|
|
997
|
+
scalars1: 4,
|
|
998
|
+
scalars2: 8,
|
|
999
|
+
scalars3: 12,
|
|
1000
|
+
cursor: 16,
|
|
1001
|
+
ints0: 20,
|
|
1002
|
+
ints1: 24,
|
|
1003
|
+
palette: 28,
|
|
1004
|
+
nuc0: 60,
|
|
1005
|
+
nuc1: 92,
|
|
1006
|
+
nuc2: 124,
|
|
1007
|
+
scalars4: 156,
|
|
1008
|
+
scalars5: 160,
|
|
1009
|
+
kuwahara: 164
|
|
1010
|
+
}, g = .01, _ = 8, v = 4, y = (e) => 1 - e;
|
|
1011
|
+
function b() {
|
|
1012
|
+
let e = /* @__PURE__ */ new ArrayBuffer(672);
|
|
1013
|
+
return {
|
|
1014
|
+
buffer: e,
|
|
1015
|
+
f32: new Float32Array(e),
|
|
1016
|
+
i32: new Int32Array(e),
|
|
1017
|
+
paletteScratch: /* @__PURE__ */ new Float32Array(24)
|
|
1018
|
+
};
|
|
1019
|
+
}
|
|
1020
|
+
function x(e, t, r, i, a = t.alpha) {
|
|
1021
|
+
let { f32: o, i32: s, paletteScratch: c } = e;
|
|
1022
|
+
o[h.scalars0 + 0] = i, o[h.scalars0 + 1] = t.softmaxBeta, o[h.scalars0 + 2] = t.valueVariance, o[h.scalars0 + 3] = t.warpAmount, o[h.scalars1 + 0] = t.warpScale, o[h.scalars1 + 1] = t.warpDrift, o[h.scalars1 + 2] = t.saturation, o[h.scalars1 + 3] = t.paperGrain, o[h.scalars2 + 0] = a, o[h.scalars2 + 1] = t.nucleiDrift, o[h.scalars2 + 2] = t.paletteDrift, o[h.scalars2 + 3] = t.breathDepth, o[h.scalars3 + 0] = t.breathPeriod, o[h.scalars3 + 1] = r.strength, o[h.scalars3 + 2] = r.radius, o[h.scalars3 + 3] = t.vividness ?? 1, o[h.cursor + 0] = r.x, o[h.cursor + 1] = y(r.y), o[h.cursor + 2] = t.metalPolish ?? 1, o[h.cursor + 3] = t.metalHeightScale ?? 1, s[h.ints0 + 0] = Math.min(t.palette.length, 8);
|
|
1023
|
+
let d = Math.min(t.nuclei.length, 8);
|
|
1024
|
+
s[h.ints0 + 1] = d, s[h.ints0 + 2] = u[t.warpMode], s[h.ints0 + 3] = t.noiseOctaves, s[h.ints1 + 0] = l[t.medium], s[h.ints1 + 1] = f[t.huePath ?? "shorter"], s[h.ints1 + 2] = 0, s[h.ints1 + 3] = 0, n(t.palette, 8, c);
|
|
1025
|
+
for (let e = 0; e < 8; e++) {
|
|
1026
|
+
let t = h.palette + e * 4;
|
|
1027
|
+
o[t + 0] = c[e * 3 + 0], o[t + 1] = c[e * 3 + 1], o[t + 2] = c[e * 3 + 2], o[t + 3] = 0;
|
|
1028
|
+
}
|
|
1029
|
+
for (let e = 0; e < 8; e++) {
|
|
1030
|
+
let n = h.nuc0 + e * 4, r = h.nuc1 + e * 4, i = h.nuc2 + e * 4;
|
|
1031
|
+
if (e < d) {
|
|
1032
|
+
let a = t.nuclei[e];
|
|
1033
|
+
o[n + 0] = a.x, o[n + 1] = y(a.y), o[n + 2] = a.radius, o[n + 3] = a.paletteBias, o[r + 0] = a.valueBias, o[r + 1] = a.driftRadius, o[r + 2] = a.driftPhase, o[r + 3] = a.elongation ?? 1, o[i + 0] = -(a.angle ?? 0) * Math.PI / 180, o[i + 1] = 0, o[i + 2] = 0, o[i + 3] = 0;
|
|
1034
|
+
} else o[n + 0] = 0, o[n + 1] = 0, o[n + 2] = 0, o[n + 3] = 0, o[r + 0] = 0, o[r + 1] = 0, o[r + 2] = 0, o[r + 3] = 1, o[i + 0] = 0, o[i + 1] = 0, o[i + 2] = 0, o[i + 3] = 0;
|
|
1035
|
+
}
|
|
1036
|
+
return o[h.scalars4 + 0] = t.strokeAmount, o[h.scalars4 + 1] = t.strokeScale, o[h.scalars4 + 2] = t.strokeAnisotropy, o[h.scalars4 + 3] = t.canvasGrain, o[h.scalars5 + 0] = t.wetEdge, o[h.scalars5 + 1] = t.granulation, o[h.scalars5 + 2] = t.brokenColor, o[h.scalars5 + 3] = t.kuwaharaQ ?? v, o[h.kuwahara + 0] = t.kuwaharaRadius ?? g, o[h.kuwahara + 1] = _, o[h.kuwahara + 2] = 0, o[h.kuwahara + 3] = 0, e;
|
|
1037
|
+
}
|
|
1038
|
+
var S = {
|
|
1039
|
+
scalars0: 0,
|
|
1040
|
+
scalars1: 4,
|
|
1041
|
+
scalars2: 8,
|
|
1042
|
+
image: 12,
|
|
1043
|
+
cursor: 16,
|
|
1044
|
+
ints: 20,
|
|
1045
|
+
nuc0: 24,
|
|
1046
|
+
nuc1: 56
|
|
1047
|
+
}, C = (e) => 1 - e;
|
|
1048
|
+
function w() {
|
|
1049
|
+
let e = /* @__PURE__ */ new ArrayBuffer(352);
|
|
1050
|
+
return {
|
|
1051
|
+
buffer: e,
|
|
1052
|
+
f32: new Float32Array(e),
|
|
1053
|
+
i32: new Int32Array(e)
|
|
1054
|
+
};
|
|
1055
|
+
}
|
|
1056
|
+
function T(e, t, n, r, i, a = t.alpha) {
|
|
1057
|
+
let { f32: o, i32: s } = e;
|
|
1058
|
+
o[S.scalars0 + 0] = r, o[S.scalars0 + 1] = t.warpAmount, o[S.scalars0 + 2] = t.warpScale, o[S.scalars0 + 3] = t.warpDrift, o[S.scalars1 + 0] = t.softmaxBeta, o[S.scalars1 + 1] = t.nucleiDrift, o[S.scalars1 + 2] = n.strength, o[S.scalars1 + 3] = n.radius, o[S.scalars2 + 0] = t.saturation, o[S.scalars2 + 1] = t.paperGrain, o[S.scalars2 + 2] = a, o[S.scalars2 + 3] = t.vividness ?? 1, o[S.image + 0] = t.imageBlur?.min ?? .004, o[S.image + 1] = t.imageBlur?.max ?? .06, o[S.image + 2] = i, o[S.image + 3] = 0, o[S.cursor + 0] = n.x, o[S.cursor + 1] = C(n.y), o[S.cursor + 2] = 0, o[S.cursor + 3] = 0;
|
|
1059
|
+
let c = Math.min(t.nuclei.length, 8);
|
|
1060
|
+
s[S.ints + 0] = c, s[S.ints + 1] = t.noiseOctaves, s[S.ints + 2] = 0, s[S.ints + 3] = 0;
|
|
1061
|
+
for (let e = 0; e < 8; e++) {
|
|
1062
|
+
let n = S.nuc0 + e * 4, r = S.nuc1 + e * 4;
|
|
1063
|
+
if (e < c) {
|
|
1064
|
+
let i = t.nuclei[e];
|
|
1065
|
+
o[n + 0] = i.x, o[n + 1] = C(i.y), o[n + 2] = i.radius, o[n + 3] = i.valueBias, o[r + 0] = i.driftRadius, o[r + 1] = i.driftPhase, o[r + 2] = i.elongation ?? 1, o[r + 3] = -(i.angle ?? 0) * Math.PI / 180;
|
|
1066
|
+
} else o[n + 0] = 0, o[n + 1] = 0, o[n + 2] = 0, o[n + 3] = 0, o[r + 0] = 0, o[r + 1] = 0, o[r + 2] = 1, o[r + 3] = 0;
|
|
1067
|
+
}
|
|
1068
|
+
return e;
|
|
1069
|
+
}
|
|
1070
|
+
//#endregion
|
|
1071
|
+
//#region src/components/aurora/composables/wgpuSetup.ts
|
|
1072
|
+
var E = 2, D = {
|
|
1073
|
+
color: {
|
|
1074
|
+
srcFactor: "one",
|
|
1075
|
+
dstFactor: "one-minus-src-alpha",
|
|
1076
|
+
operation: "add"
|
|
1077
|
+
},
|
|
1078
|
+
alpha: {
|
|
1079
|
+
srcFactor: "one",
|
|
1080
|
+
dstFactor: "one-minus-src-alpha",
|
|
1081
|
+
operation: "add"
|
|
1082
|
+
}
|
|
1083
|
+
};
|
|
1084
|
+
function O(e) {
|
|
1085
|
+
let { canvas: n, opaquePresentation: r, getCursorScalars: i, getConfig: a, getReducedMotion: o, getRenderTime: s, pointerField: l, getDecodedImage: u, registerImageUploader: f } = e, m = null;
|
|
1086
|
+
return function(e, h, g) {
|
|
1087
|
+
if (a().source === "image") return k(e, h, g, {
|
|
1088
|
+
canvas: n,
|
|
1089
|
+
opaquePresentation: r,
|
|
1090
|
+
getCursorScalars: i,
|
|
1091
|
+
getConfig: a,
|
|
1092
|
+
getReducedMotion: o,
|
|
1093
|
+
getRenderTime: s,
|
|
1094
|
+
pointerField: l,
|
|
1095
|
+
getDecodedImage: u,
|
|
1096
|
+
registerImageUploader: f
|
|
1097
|
+
});
|
|
1098
|
+
let _ = e.createShaderModule({
|
|
1099
|
+
label: "[Aurora] aurora.wgsl",
|
|
1100
|
+
code: p
|
|
1101
|
+
}), v = e.createBuffer({
|
|
1102
|
+
label: "[Aurora] uniforms",
|
|
1103
|
+
size: 672,
|
|
1104
|
+
usage: 72
|
|
1105
|
+
}), y = e.createBindGroupLayout({
|
|
1106
|
+
label: "[Aurora] bind-group-0",
|
|
1107
|
+
entries: [{
|
|
1108
|
+
binding: 0,
|
|
1109
|
+
visibility: E,
|
|
1110
|
+
buffer: { type: "uniform" }
|
|
1111
|
+
}]
|
|
1112
|
+
}), S = e.createRenderPipeline({
|
|
1113
|
+
label: "[Aurora] pipeline",
|
|
1114
|
+
layout: e.createPipelineLayout({ bindGroupLayouts: [y] }),
|
|
1115
|
+
vertex: {
|
|
1116
|
+
module: _,
|
|
1117
|
+
entryPoint: "vs_main"
|
|
1118
|
+
},
|
|
1119
|
+
fragment: {
|
|
1120
|
+
module: _,
|
|
1121
|
+
entryPoint: "fs_main",
|
|
1122
|
+
targets: [{
|
|
1123
|
+
format: g,
|
|
1124
|
+
blend: r ? void 0 : D
|
|
1125
|
+
}]
|
|
1126
|
+
},
|
|
1127
|
+
primitive: { topology: "triangle-list" }
|
|
1128
|
+
}), C = e.createBindGroup({
|
|
1129
|
+
label: "[Aurora] bind-group",
|
|
1130
|
+
layout: y,
|
|
1131
|
+
entries: [{
|
|
1132
|
+
binding: 0,
|
|
1133
|
+
resource: { buffer: v }
|
|
1134
|
+
}]
|
|
1135
|
+
}), w = b();
|
|
1136
|
+
function T(e) {}
|
|
1137
|
+
function O(t) {
|
|
1138
|
+
let n = +!o(), c = m === null ? 0 : Math.max(0, (t - m) * 1e3);
|
|
1139
|
+
m = t, l.tick(n === 0 ? 0 : c);
|
|
1140
|
+
let u = d(l, i(), n), f = a();
|
|
1141
|
+
x(w, f, u, s(t), r ? 1 : f.alpha), e.queue.writeBuffer(v, 0, w.buffer);
|
|
1142
|
+
let p = h.getCurrentTexture().createView(), g = e.createCommandEncoder({ label: "[Aurora] frame" }), _ = g.beginRenderPass({ colorAttachments: [{
|
|
1143
|
+
view: p,
|
|
1144
|
+
clearValue: {
|
|
1145
|
+
r: 0,
|
|
1146
|
+
g: 0,
|
|
1147
|
+
b: 0,
|
|
1148
|
+
a: +!!r
|
|
1149
|
+
},
|
|
1150
|
+
loadOp: "clear",
|
|
1151
|
+
storeOp: "store"
|
|
1152
|
+
}] });
|
|
1153
|
+
_.setPipeline(S), _.setBindGroup(0, C), _.draw(3, 1, 0, 0), _.end(), e.queue.submit([g.finish()]);
|
|
1154
|
+
}
|
|
1155
|
+
function A() {
|
|
1156
|
+
return o() ? !1 : t(a()) ? !0 : c(l);
|
|
1157
|
+
}
|
|
1158
|
+
return {
|
|
1159
|
+
frame: O,
|
|
1160
|
+
shouldContinue: A,
|
|
1161
|
+
resize: T,
|
|
1162
|
+
teardown: () => {
|
|
1163
|
+
v.destroy();
|
|
1164
|
+
}
|
|
1165
|
+
};
|
|
1166
|
+
};
|
|
1167
|
+
}
|
|
1168
|
+
function k(n, i, a, o) {
|
|
1169
|
+
let { canvas: s, opaquePresentation: l, getCursorScalars: u, getConfig: f, getReducedMotion: p, getRenderTime: h, pointerField: g, getDecodedImage: _, registerImageUploader: v } = o, y = null, b = n.createShaderModule({
|
|
1170
|
+
label: "[Aurora] aurora-image.wgsl",
|
|
1171
|
+
code: m
|
|
1172
|
+
}), x = n.createBuffer({
|
|
1173
|
+
label: "[Aurora] image uniforms",
|
|
1174
|
+
size: 352,
|
|
1175
|
+
usage: 72
|
|
1176
|
+
}), S = n.createSampler({
|
|
1177
|
+
label: "[Aurora] image sampler",
|
|
1178
|
+
magFilter: "linear",
|
|
1179
|
+
minFilter: "linear",
|
|
1180
|
+
addressModeU: "clamp-to-edge",
|
|
1181
|
+
addressModeV: "clamp-to-edge"
|
|
1182
|
+
}), C = n.createBindGroupLayout({
|
|
1183
|
+
label: "[Aurora] image bind-group-0",
|
|
1184
|
+
entries: [
|
|
1185
|
+
{
|
|
1186
|
+
binding: 0,
|
|
1187
|
+
visibility: E,
|
|
1188
|
+
buffer: { type: "uniform" }
|
|
1189
|
+
},
|
|
1190
|
+
{
|
|
1191
|
+
binding: 1,
|
|
1192
|
+
visibility: E,
|
|
1193
|
+
texture: {
|
|
1194
|
+
sampleType: "float",
|
|
1195
|
+
viewDimension: "2d"
|
|
1196
|
+
}
|
|
1197
|
+
},
|
|
1198
|
+
{
|
|
1199
|
+
binding: 2,
|
|
1200
|
+
visibility: E,
|
|
1201
|
+
sampler: { type: "filtering" }
|
|
1202
|
+
}
|
|
1203
|
+
]
|
|
1204
|
+
}), O = n.createRenderPipeline({
|
|
1205
|
+
label: "[Aurora] image pipeline",
|
|
1206
|
+
layout: n.createPipelineLayout({ bindGroupLayouts: [C] }),
|
|
1207
|
+
vertex: {
|
|
1208
|
+
module: b,
|
|
1209
|
+
entryPoint: "vs_main"
|
|
1210
|
+
},
|
|
1211
|
+
fragment: {
|
|
1212
|
+
module: b,
|
|
1213
|
+
entryPoint: "fs_main",
|
|
1214
|
+
targets: [{
|
|
1215
|
+
format: a,
|
|
1216
|
+
blend: l ? void 0 : D
|
|
1217
|
+
}]
|
|
1218
|
+
},
|
|
1219
|
+
primitive: { topology: "triangle-list" }
|
|
1220
|
+
}), k = r(n, _() ?? e()).texture;
|
|
1221
|
+
function A() {
|
|
1222
|
+
return n.createBindGroup({
|
|
1223
|
+
label: "[Aurora] image bind-group",
|
|
1224
|
+
layout: C,
|
|
1225
|
+
entries: [
|
|
1226
|
+
{
|
|
1227
|
+
binding: 0,
|
|
1228
|
+
resource: { buffer: x }
|
|
1229
|
+
},
|
|
1230
|
+
{
|
|
1231
|
+
binding: 1,
|
|
1232
|
+
resource: k.createView()
|
|
1233
|
+
},
|
|
1234
|
+
{
|
|
1235
|
+
binding: 2,
|
|
1236
|
+
resource: S
|
|
1237
|
+
}
|
|
1238
|
+
]
|
|
1239
|
+
});
|
|
1240
|
+
}
|
|
1241
|
+
let j = A();
|
|
1242
|
+
v((e) => {
|
|
1243
|
+
k.destroy(), k = r(n, e).texture, j = A();
|
|
1244
|
+
});
|
|
1245
|
+
let M = w();
|
|
1246
|
+
function N(e) {}
|
|
1247
|
+
function P(e) {
|
|
1248
|
+
let t = +!p(), r = y === null ? 0 : Math.max(0, (e - y) * 1e3);
|
|
1249
|
+
y = e, g.tick(t === 0 ? 0 : r);
|
|
1250
|
+
let a = d(g, u(), t), o = s.height > 0 ? s.width / s.height : 1, c = f();
|
|
1251
|
+
T(M, c, a, h(e), o, l ? 1 : c.alpha), n.queue.writeBuffer(x, 0, M.buffer);
|
|
1252
|
+
let m = i.getCurrentTexture().createView(), _ = n.createCommandEncoder({ label: "[Aurora] image frame" }), v = _.beginRenderPass({ colorAttachments: [{
|
|
1253
|
+
view: m,
|
|
1254
|
+
clearValue: {
|
|
1255
|
+
r: 0,
|
|
1256
|
+
g: 0,
|
|
1257
|
+
b: 0,
|
|
1258
|
+
a: +!!l
|
|
1259
|
+
},
|
|
1260
|
+
loadOp: "clear",
|
|
1261
|
+
storeOp: "store"
|
|
1262
|
+
}] });
|
|
1263
|
+
v.setPipeline(O), v.setBindGroup(0, j), v.draw(3, 1, 0, 0), v.end(), n.queue.submit([_.finish()]);
|
|
1264
|
+
}
|
|
1265
|
+
function F() {
|
|
1266
|
+
return p() ? !1 : t(f()) ? !0 : c(g);
|
|
1267
|
+
}
|
|
1268
|
+
return {
|
|
1269
|
+
frame: P,
|
|
1270
|
+
shouldContinue: F,
|
|
1271
|
+
resize: N,
|
|
1272
|
+
teardown: () => {
|
|
1273
|
+
v(null), k.destroy(), x.destroy();
|
|
1274
|
+
}
|
|
1275
|
+
};
|
|
1276
|
+
}
|
|
1277
|
+
//#endregion
|
|
1278
|
+
export { O as createAuroraWGPUSetup };
|