@pathscale/ui 1.2.10 → 1.3.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/LICENSE +22 -22
- package/README.md +132 -59
- package/dist/components/accordion/Accordion.css +158 -158
- package/dist/components/alert/Alert.css +116 -116
- package/dist/components/avatar/Avatar.css +124 -124
- package/dist/components/badge/Badge.css +164 -164
- package/dist/components/breadcrumbs/Breadcrumbs.css +63 -63
- package/dist/components/button/Button.css +194 -194
- package/dist/components/button-group/ButtonGroup.css +117 -117
- package/dist/components/calendar/Calendar.css +258 -258
- package/dist/components/card/Card.css +110 -110
- package/dist/components/chatbubble/ChatBubble.css +164 -164
- package/dist/components/checkbox/Checkbox.css +183 -183
- package/dist/components/checkbox-group/CheckboxGroup.css +10 -10
- package/dist/components/chip/Chip.css +197 -197
- package/dist/components/close-button/CloseButton.css +81 -81
- package/dist/components/color-area/ColorArea.css +54 -54
- package/dist/components/color-field/ColorField.css +88 -88
- package/dist/components/color-picker/ColorPicker.css +28 -28
- package/dist/components/color-slider/ColorSlider.css +57 -57
- package/dist/components/color-swatch/ColorSwatch.css +84 -84
- package/dist/components/color-swatch-picker/ColorSwatchPicker.css +12 -12
- package/dist/components/color-wheel-flower/ColorWheelFlower.css +147 -147
- package/dist/components/combo-box/ComboBox.css +344 -344
- package/dist/components/date-field/DateField.css +215 -215
- package/dist/components/date-picker/DatePicker.css +143 -143
- package/dist/components/date-range-picker/DateRangePicker.css +149 -149
- package/dist/components/description/Description.css +10 -10
- package/dist/components/disclosure/Disclosure.css +84 -84
- package/dist/components/disclosure-group/DisclosureGroup.css +9 -9
- package/dist/components/drawer/Drawer.css +463 -463
- package/dist/components/dropdown/Dropdown.css +211 -211
- package/dist/components/empty-state/EmptyState.css +39 -39
- package/dist/components/error-message/ErrorMessage.css +20 -20
- package/dist/components/field-error/FieldError.css +27 -27
- package/dist/components/fieldset/Fieldset.css +30 -30
- package/dist/components/flex/Flex.css +5 -5
- package/dist/components/floating-dock/FloatingDock.css +208 -208
- package/dist/components/footer/footer.css +51 -51
- package/dist/components/form/Form.css +5 -5
- package/dist/components/glass-panel/GlassPanel.css +359 -359
- package/dist/components/glow-card/GlowCard.css +100 -100
- package/dist/components/grid/Grid.css +5 -5
- package/dist/components/header/Header.css +13 -13
- package/dist/components/icon/Icon.css +10 -10
- package/dist/components/immersive-landing/ImmersiveLanding.css +565 -565
- package/dist/components/input/Input.css +155 -155
- package/dist/components/input-group/InputGroup.css +172 -172
- package/dist/components/input-otp/InputOTP.css +170 -170
- package/dist/components/kbd/Kbd.css +60 -60
- package/dist/components/label/Label.css +30 -30
- package/dist/components/language-switcher/LanguageSwitcher.css +56 -56
- package/dist/components/language-switcher/createI18n.d.ts +2 -1
- package/dist/components/link/Link.css +131 -131
- package/dist/components/list-box/ListBox.css +148 -148
- package/dist/components/live-chat/LiveChat.css +324 -324
- package/dist/components/menu/Menu.css +199 -199
- package/dist/components/metal-border/MetalBorder.classes.d.ts +26 -0
- package/dist/components/metal-border/MetalBorder.classes.js +27 -0
- package/dist/components/metal-border/MetalBorder.css +40 -0
- package/dist/components/metal-border/MetalBorder.d.ts +20 -0
- package/dist/components/metal-border/MetalBorder.js +322 -0
- package/dist/components/metal-border/engine/color.d.ts +4 -0
- package/dist/components/metal-border/engine/color.js +69 -0
- package/dist/components/metal-border/engine/glow/geometry.d.ts +35 -0
- package/dist/components/metal-border/engine/glow/geometry.js +176 -0
- package/dist/components/metal-border/engine/glow/glow.d.ts +38 -0
- package/dist/components/metal-border/engine/glow/glow.js +246 -0
- package/dist/components/metal-border/engine/index.d.ts +4 -0
- package/dist/components/metal-border/engine/index.js +2 -0
- package/dist/components/metal-border/engine/perfConfig.d.ts +9 -0
- package/dist/components/metal-border/engine/perfConfig.js +10 -0
- package/dist/components/metal-border/engine/presets.d.ts +57 -0
- package/dist/components/metal-border/engine/presets.js +214 -0
- package/dist/components/metal-border/engine/renderer/core.d.ts +69 -0
- package/dist/components/metal-border/engine/renderer/core.js +156 -0
- package/dist/components/metal-border/engine/renderer/loop.d.ts +30 -0
- package/dist/components/metal-border/engine/renderer/loop.js +248 -0
- package/dist/components/metal-border/engine/renderer/sampling.d.ts +14 -0
- package/dist/components/metal-border/engine/renderer/sampling.js +145 -0
- package/dist/components/metal-border/engine/shaders.d.ts +36 -0
- package/dist/components/metal-border/engine/shaders.js +215 -0
- package/dist/components/metal-border/engine/tween.d.ts +17 -0
- package/dist/components/metal-border/engine/tween.js +28 -0
- package/dist/components/metal-border/index.d.ts +2 -0
- package/dist/components/metal-border/index.js +1 -0
- package/dist/components/meter/Meter.css +89 -89
- package/dist/components/modal/Modal.css +320 -320
- package/dist/components/navbar/Navbar.css +110 -110
- package/dist/components/noise-background/NoiseBackground.css +66 -66
- package/dist/components/number-field/NumberField.css +198 -198
- package/dist/components/pagination/Pagination.css +121 -121
- package/dist/components/popover/Popover.css +117 -117
- package/dist/components/progress-bar/ProgressBar.css +104 -104
- package/dist/components/progress-circle/ProgressCircle.css +82 -82
- package/dist/components/radio/Radio.css +129 -129
- package/dist/components/radio-group/RadioGroup.css +58 -58
- package/dist/components/range-calendar/RangeCalendar.css +51 -51
- package/dist/components/scroll-shadow/ScrollShadow.css +93 -93
- package/dist/components/search-field/SearchField.css +183 -183
- package/dist/components/select/Select.css +284 -284
- package/dist/components/separator/Separator.css +35 -35
- package/dist/components/skeleton/Skeleton.css +95 -95
- package/dist/components/slider/Slider.css +122 -122
- package/dist/components/spinner/Spinner.css +131 -131
- package/dist/components/surface/Surface.css +37 -37
- package/dist/components/table/Table.css +426 -426
- package/dist/components/tabs/Tabs.css +203 -203
- package/dist/components/tag/Tag.css +121 -121
- package/dist/components/tag-group/TagGroup.css +22 -22
- package/dist/components/text/Text.css +66 -66
- package/dist/components/text-area/TextArea.css +95 -95
- package/dist/components/text-field/TextField.css +33 -33
- package/dist/components/time-field/TimeField.css +215 -215
- package/dist/components/toast/Toast.css +344 -344
- package/dist/components/toggle/Toggle.css +237 -237
- package/dist/components/toolbar/Toolbar.css +55 -55
- package/dist/components/tooltip/Tooltip.css +153 -153
- package/dist/index.css +74 -74
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/purge-manifest.json +15836 -15583
- package/dist/styles/base/index.css +43 -43
- package/dist/styles/themes/dark.css +141 -141
- package/dist/styles/themes/light.css +143 -143
- package/package.json +17 -8
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import { EXTRA_SEGMENTS, HALO_SEGMENTS } from "../perfConfig.js";
|
|
2
|
+
import { sampleShaderLumAt, sampleShaderRGBAt, sampleShaderRGBChromatic } from "../renderer/sampling.js";
|
|
3
|
+
import { ease, tween, tweenStart, tweenTick } from "../tween.js";
|
|
4
|
+
import { hsvToRgb, rgbToHsv } from "../color.js";
|
|
5
|
+
import { buildPerimTable, buildStaticBlobPath, buildSvgMarkup, rrPerim, sampleAtArc, shapePerim, smoothstep, tangentAngleAtArc } from "./geometry.js";
|
|
6
|
+
const FADE_RATE = 0.00875;
|
|
7
|
+
const LO = 0.08, HI = 0.32;
|
|
8
|
+
const RELOCATE_DELTA = 0.05;
|
|
9
|
+
const MIN_DWELL_MS = 3000;
|
|
10
|
+
const PEAK_OP = 0.85, BASE_OP = 0.34;
|
|
11
|
+
const RELOC_FADE_MS = 1500;
|
|
12
|
+
const WANDER_RANGE = 15, WANDER_LERP = 0.0075, WANDER_RETARGET = 120;
|
|
13
|
+
const INSET = 1.5;
|
|
14
|
+
const HALO_HALFLEN = 7.8;
|
|
15
|
+
const EXTRA_HALFLEN = 9.13952, EXTRA_OUTWARD = 1.0;
|
|
16
|
+
const EXTRA_SCALE = 1 / 3;
|
|
17
|
+
const HALO_OP_MUL = 0.8;
|
|
18
|
+
const EXTRA_INTENSITY = 3.51;
|
|
19
|
+
const TINT_HOLD_MS = 2000, TINT_FADE_MS = 400;
|
|
20
|
+
const LT_SAT_BOOST = 2.625, LT_VAL_MULT = 1.008, LT_MIN_VAL = 0.31;
|
|
21
|
+
const REF_W = 140, REF_H = 40, REF_R = 20;
|
|
22
|
+
let glowIdSeq = 0;
|
|
23
|
+
const _pt = {
|
|
24
|
+
x: 0,
|
|
25
|
+
y: 0
|
|
26
|
+
};
|
|
27
|
+
function injectGlow(container, opts) {
|
|
28
|
+
const p = `mfxg_${++glowIdSeq}`;
|
|
29
|
+
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
|
30
|
+
svg.setAttribute('class', 'metal-fx-glow-svg');
|
|
31
|
+
svg.setAttribute('preserveAspectRatio', 'none');
|
|
32
|
+
svg.setAttribute('viewBox', `0 0 ${opts.width} ${opts.height}`);
|
|
33
|
+
svg.innerHTML = buildSvgMarkup(opts, p);
|
|
34
|
+
container.appendChild(svg);
|
|
35
|
+
const q = (id)=>svg.querySelector(`#${p}_${id}`);
|
|
36
|
+
const haloGroup = q('h');
|
|
37
|
+
const haloInner = q('hI');
|
|
38
|
+
const extraGroup = q('e');
|
|
39
|
+
const extraInner = q('eI');
|
|
40
|
+
const fadeCircle = q('fc');
|
|
41
|
+
const ratio = shapePerim(opts.width, opts.height, opts.cornerRadius, opts.kind) / rrPerim(REF_W, REF_H, REF_R);
|
|
42
|
+
const haloHL = Math.max(1, HALO_HALFLEN * ratio);
|
|
43
|
+
const extraHL = Math.max(0.6, EXTRA_HALFLEN * EXTRA_SCALE * ratio);
|
|
44
|
+
const haloD = buildStaticBlobPath(haloHL, HALO_SEGMENTS);
|
|
45
|
+
const extraD = buildStaticBlobPath(extraHL, EXTRA_SEGMENTS);
|
|
46
|
+
const haloPaths = [
|
|
47
|
+
q('pXl'),
|
|
48
|
+
q('pLg'),
|
|
49
|
+
q('pMd'),
|
|
50
|
+
q('pSm')
|
|
51
|
+
];
|
|
52
|
+
const extraPaths = [
|
|
53
|
+
q('eO'),
|
|
54
|
+
q('eC')
|
|
55
|
+
];
|
|
56
|
+
for (const path of haloPaths)path.setAttribute('d', haloD);
|
|
57
|
+
for (const path of extraPaths)path.setAttribute('d', extraD);
|
|
58
|
+
haloInner.style.transformOrigin = '0 0';
|
|
59
|
+
extraInner.style.transformOrigin = '0 0';
|
|
60
|
+
haloInner.style.willChange = 'transform';
|
|
61
|
+
extraInner.style.willChange = 'transform';
|
|
62
|
+
haloInner.style.transition = 'transform 100ms linear';
|
|
63
|
+
extraInner.style.transition = 'transform 100ms linear';
|
|
64
|
+
haloGroup.style.willChange = 'opacity';
|
|
65
|
+
extraGroup.style.willChange = 'opacity';
|
|
66
|
+
haloGroup.style.transition = 'opacity 100ms linear';
|
|
67
|
+
extraGroup.style.transition = 'opacity 100ms linear';
|
|
68
|
+
fadeCircle.style.willChange = 'transform';
|
|
69
|
+
return {
|
|
70
|
+
svg,
|
|
71
|
+
haloGroup,
|
|
72
|
+
haloInner,
|
|
73
|
+
extraGroup,
|
|
74
|
+
extraInner,
|
|
75
|
+
fadeCircle,
|
|
76
|
+
width: opts.width,
|
|
77
|
+
height: opts.height,
|
|
78
|
+
cornerRadius: opts.cornerRadius,
|
|
79
|
+
kind: opts.kind,
|
|
80
|
+
scale: opts.scale ?? 1,
|
|
81
|
+
perim: buildPerimTable(opts),
|
|
82
|
+
currentIdx: 0,
|
|
83
|
+
appearedAt: 0,
|
|
84
|
+
glowOpacity: 0,
|
|
85
|
+
relocTween: null,
|
|
86
|
+
relocNextIdx: -1,
|
|
87
|
+
wanderS: 0,
|
|
88
|
+
wanderTargetS: 0,
|
|
89
|
+
wanderFrames: 0,
|
|
90
|
+
tintFrom: {
|
|
91
|
+
r: 255,
|
|
92
|
+
g: 255,
|
|
93
|
+
b: 255
|
|
94
|
+
},
|
|
95
|
+
tintTarget: {
|
|
96
|
+
r: 255,
|
|
97
|
+
g: 255,
|
|
98
|
+
b: 255
|
|
99
|
+
},
|
|
100
|
+
tintTween: null,
|
|
101
|
+
tintHoldUntil: 0,
|
|
102
|
+
lastHaloStroke: '',
|
|
103
|
+
lastExtraStroke: ''
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
function updateGlow(h, inst, nowMs, strengthMul, theme = 'dark') {
|
|
107
|
+
const { width: W, height: H, cornerRadius: R, perim } = h;
|
|
108
|
+
if (0 === perim.length) return;
|
|
109
|
+
const halfWin = 2;
|
|
110
|
+
let maxLum = -1, maxIdx = h.currentIdx, curLum = 0;
|
|
111
|
+
for(let i = 0; i < perim.length; i++){
|
|
112
|
+
const pt = perim[i];
|
|
113
|
+
const lum = sampleShaderLumAt(inst, pt.x, pt.y, halfWin);
|
|
114
|
+
if (lum > maxLum) {
|
|
115
|
+
maxLum = lum;
|
|
116
|
+
maxIdx = i;
|
|
117
|
+
}
|
|
118
|
+
if (i === h.currentIdx) curLum = lum;
|
|
119
|
+
}
|
|
120
|
+
const dwellActive = h.appearedAt > 0 && nowMs - h.appearedAt < MIN_DWELL_MS;
|
|
121
|
+
const targetOp = BASE_OP + (PEAK_OP - BASE_OP) * smoothstep(LO, HI, curLum);
|
|
122
|
+
const rivalDominates = !dwellActive && maxLum - curLum > RELOCATE_DELTA;
|
|
123
|
+
if (!h.relocTween || h.relocTween.done) if (0 === h.appearedAt) {
|
|
124
|
+
h.currentIdx = maxIdx;
|
|
125
|
+
h.appearedAt = nowMs;
|
|
126
|
+
h.wanderS = 0;
|
|
127
|
+
h.wanderTargetS = 0;
|
|
128
|
+
h.wanderFrames = 0;
|
|
129
|
+
h.relocTween = tween(0, targetOp, RELOC_FADE_MS, ease.smoothstep);
|
|
130
|
+
tweenStart(h.relocTween, nowMs);
|
|
131
|
+
} else if (h.relocTween?.done && 0 === h.relocTween.to) {
|
|
132
|
+
h.currentIdx = h.relocNextIdx;
|
|
133
|
+
h.appearedAt = nowMs;
|
|
134
|
+
h.wanderS = 0;
|
|
135
|
+
h.wanderTargetS = 0;
|
|
136
|
+
h.wanderFrames = 0;
|
|
137
|
+
const np = perim[h.currentIdx];
|
|
138
|
+
const nl = sampleShaderLumAt(inst, np.x, np.y, halfWin);
|
|
139
|
+
const fadeInTarget = BASE_OP + (PEAK_OP - BASE_OP) * smoothstep(LO, HI, nl);
|
|
140
|
+
h.relocTween = tween(0, fadeInTarget, RELOC_FADE_MS, ease.smoothstep);
|
|
141
|
+
tweenStart(h.relocTween, nowMs);
|
|
142
|
+
} else if (rivalDominates) {
|
|
143
|
+
h.relocNextIdx = maxIdx;
|
|
144
|
+
h.relocTween = tween(h.glowOpacity, 0, RELOC_FADE_MS, ease.smoothstep);
|
|
145
|
+
tweenStart(h.relocTween, nowMs);
|
|
146
|
+
} else h.glowOpacity += (targetOp - h.glowOpacity) * FADE_RATE;
|
|
147
|
+
if (h.relocTween) h.glowOpacity = tweenTick(h.relocTween, nowMs);
|
|
148
|
+
h.glowOpacity = Math.max(0, Math.min(1, h.glowOpacity));
|
|
149
|
+
const ratio = shapePerim(W, H, R, h.kind) / rrPerim(REF_W, REF_H, REF_R);
|
|
150
|
+
const wanderRange = WANDER_RANGE * ratio;
|
|
151
|
+
if (h.wanderFrames++ >= WANDER_RETARGET) {
|
|
152
|
+
h.wanderTargetS = (2 * Math.random() - 1) * wanderRange;
|
|
153
|
+
h.wanderFrames = 0;
|
|
154
|
+
}
|
|
155
|
+
h.wanderS += (h.wanderTargetS - h.wanderS) * WANDER_LERP;
|
|
156
|
+
const blobArc = perim[h.currentIdx].arc + h.wanderS;
|
|
157
|
+
const insetS = INSET * h.scale;
|
|
158
|
+
sampleAtArc(blobArc, W, H, R, insetS, 0, h.kind, _pt);
|
|
159
|
+
const blobX = _pt.x, blobY = _pt.y;
|
|
160
|
+
const tangent = tangentAngleAtArc(blobArc, W, H, R, insetS, h.kind);
|
|
161
|
+
const tx = `translate(${blobX.toFixed(3)}px,${blobY.toFixed(3)}px) rotate(${tangent.toFixed(4)}rad)`;
|
|
162
|
+
h.haloInner.style.transform = tx;
|
|
163
|
+
const extraOut = EXTRA_OUTWARD * ratio * h.scale;
|
|
164
|
+
sampleAtArc(blobArc, W, H, R, insetS, extraOut, h.kind, _pt);
|
|
165
|
+
h.extraInner.style.transform = `translate(${_pt.x.toFixed(3)}px,${_pt.y.toFixed(3)}px) rotate(${tangent.toFixed(4)}rad)`;
|
|
166
|
+
h.fadeCircle.style.transform = `translate(${_pt.x.toFixed(3)}px,${_pt.y.toFixed(3)}px)`;
|
|
167
|
+
const light = 'light' === theme;
|
|
168
|
+
const samp = light ? sampleShaderRGBChromatic(inst, blobX, blobY, halfWin) : sampleShaderRGBAt(inst, blobX, blobY, halfWin);
|
|
169
|
+
if (h.tintTween) {
|
|
170
|
+
if (h.tintTween.done) {
|
|
171
|
+
if (light) {
|
|
172
|
+
h.tintFrom = {
|
|
173
|
+
r: h.tintFrom.r + (h.tintTarget.r - h.tintFrom.r) * h.tintTween.val,
|
|
174
|
+
g: h.tintFrom.g + (h.tintTarget.g - h.tintFrom.g) * h.tintTween.val,
|
|
175
|
+
b: h.tintFrom.b + (h.tintTarget.b - h.tintFrom.b) * h.tintTween.val
|
|
176
|
+
};
|
|
177
|
+
h.tintTarget = {
|
|
178
|
+
...samp
|
|
179
|
+
};
|
|
180
|
+
h.tintTween = tween(0, 1, TINT_FADE_MS);
|
|
181
|
+
tweenStart(h.tintTween, nowMs);
|
|
182
|
+
} else if (nowMs >= h.tintHoldUntil) {
|
|
183
|
+
h.tintFrom = {
|
|
184
|
+
...h.tintTarget
|
|
185
|
+
};
|
|
186
|
+
h.tintTarget = {
|
|
187
|
+
...samp
|
|
188
|
+
};
|
|
189
|
+
h.tintTween = tween(0, 1, TINT_FADE_MS);
|
|
190
|
+
tweenStart(h.tintTween, nowMs);
|
|
191
|
+
h.tintHoldUntil = nowMs + TINT_HOLD_MS;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
} else {
|
|
195
|
+
h.tintFrom = {
|
|
196
|
+
...samp
|
|
197
|
+
};
|
|
198
|
+
h.tintTarget = {
|
|
199
|
+
...samp
|
|
200
|
+
};
|
|
201
|
+
h.tintTween = tween(0, 1, TINT_FADE_MS);
|
|
202
|
+
tweenStart(h.tintTween, nowMs);
|
|
203
|
+
h.tintHoldUntil = light ? 0 : nowMs + TINT_HOLD_MS;
|
|
204
|
+
}
|
|
205
|
+
tweenTick(h.tintTween, nowMs);
|
|
206
|
+
const ft = h.tintTween.val;
|
|
207
|
+
let tR, tG, tB;
|
|
208
|
+
if (light) {
|
|
209
|
+
tR = Math.round(h.tintFrom.r + (h.tintTarget.r - h.tintFrom.r) * ft);
|
|
210
|
+
tG = Math.round(h.tintFrom.g + (h.tintTarget.g - h.tintFrom.g) * ft);
|
|
211
|
+
tB = Math.round(h.tintFrom.b + (h.tintTarget.b - h.tintFrom.b) * ft);
|
|
212
|
+
} else {
|
|
213
|
+
const hR = h.tintFrom.r + (h.tintTarget.r - h.tintFrom.r) * ft;
|
|
214
|
+
const hG = h.tintFrom.g + (h.tintTarget.g - h.tintFrom.g) * ft;
|
|
215
|
+
const hB = h.tintFrom.b + (h.tintTarget.b - h.tintFrom.b) * ft;
|
|
216
|
+
const peak = Math.max(hR, hG, hB) || 1;
|
|
217
|
+
tR = Math.round(hR / peak * 255);
|
|
218
|
+
tG = Math.round(hG / peak * 255);
|
|
219
|
+
tB = Math.round(hB / peak * 255);
|
|
220
|
+
}
|
|
221
|
+
const tinted = `rgb(${tR},${tG},${tB})`;
|
|
222
|
+
if (tinted !== h.lastHaloStroke) {
|
|
223
|
+
h.lastHaloStroke = tinted;
|
|
224
|
+
h.haloInner.style.stroke = tinted;
|
|
225
|
+
}
|
|
226
|
+
if (light) {
|
|
227
|
+
const hsv = rgbToHsv(tR, tG, tB);
|
|
228
|
+
const [er, eg, eb] = hsvToRgb(hsv[0], Math.min(1, hsv[1] * LT_SAT_BOOST), Math.max(LT_MIN_VAL, hsv[2] * LT_VAL_MULT));
|
|
229
|
+
const extraTinted = `rgb(${er},${eg},${eb})`;
|
|
230
|
+
if (extraTinted !== h.lastExtraStroke) {
|
|
231
|
+
h.lastExtraStroke = extraTinted;
|
|
232
|
+
h.extraInner.style.stroke = extraTinted;
|
|
233
|
+
}
|
|
234
|
+
} else if ('#ffffff' !== h.lastExtraStroke) {
|
|
235
|
+
h.lastExtraStroke = '#ffffff';
|
|
236
|
+
h.extraInner.style.stroke = '#ffffff';
|
|
237
|
+
}
|
|
238
|
+
const m = Math.max(0, Math.min(1, strengthMul));
|
|
239
|
+
h.haloGroup.style.opacity = (h.glowOpacity * HALO_OP_MUL * m).toFixed(3);
|
|
240
|
+
h.extraGroup.style.opacity = Math.min(1, h.glowOpacity * EXTRA_INTENSITY * m).toFixed(3);
|
|
241
|
+
}
|
|
242
|
+
function resizeGlow(handles, container, opts) {
|
|
243
|
+
for (const svg of Array.from(container.querySelectorAll('.metal-fx-glow-svg')))if (svg.parentNode === container) container.removeChild(svg);
|
|
244
|
+
return injectGlow(container, opts);
|
|
245
|
+
}
|
|
246
|
+
export { injectGlow, resizeGlow, updateGlow };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { createInstance, destroyInstance, updateInstance, setInstanceVisible, registerGlowInstance, unregisterGlowInstance, setGlowCallback, } from "./renderer/loop";
|
|
2
|
+
export { injectGlow, updateGlow, resizeGlow, type GlowHandles, } from "./glow/glow";
|
|
3
|
+
export type { MetalFxInstance } from "./renderer/core";
|
|
4
|
+
export type { PresetName, PresetTheme } from "./presets";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const FRAME_INTERVAL_MS = 66;
|
|
2
|
+
export declare const REFLECTION_INTERVAL_MS = 66;
|
|
3
|
+
export declare const GLOW_READBACK_INTERVAL_MS = 1500;
|
|
4
|
+
export declare const GLOW_SKIP_FRAMES = 1;
|
|
5
|
+
export declare const PERIM_SAMPLES = 16;
|
|
6
|
+
export declare const HALO_SEGMENTS = 16;
|
|
7
|
+
export declare const EXTRA_SEGMENTS = 8;
|
|
8
|
+
export declare const CANONICAL_GL_SIZE = 96;
|
|
9
|
+
export declare const GL_DPR_CAP = 2;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
const FRAME_INTERVAL_MS = 66;
|
|
2
|
+
const REFLECTION_INTERVAL_MS = 66;
|
|
3
|
+
const GLOW_READBACK_INTERVAL_MS = 1500;
|
|
4
|
+
const GLOW_SKIP_FRAMES = 1;
|
|
5
|
+
const PERIM_SAMPLES = 16;
|
|
6
|
+
const HALO_SEGMENTS = 16;
|
|
7
|
+
const EXTRA_SEGMENTS = 8;
|
|
8
|
+
const CANONICAL_GL_SIZE = 96;
|
|
9
|
+
const GL_DPR_CAP = 2;
|
|
10
|
+
export { CANONICAL_GL_SIZE, EXTRA_SEGMENTS, FRAME_INTERVAL_MS, GLOW_READBACK_INTERVAL_MS, GLOW_SKIP_FRAMES, GL_DPR_CAP, HALO_SEGMENTS, PERIM_SAMPLES, REFLECTION_INTERVAL_MS };
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bundled preset configurations for the metal effect.
|
|
3
|
+
*
|
|
4
|
+
* Direct ports of the three JSON files shipped alongside the canonical demo:
|
|
5
|
+
* • preset-chromatic-both-modes.json
|
|
6
|
+
* • preset-silver-both-modes.json
|
|
7
|
+
* • preset-gold-both-modes.json
|
|
8
|
+
*
|
|
9
|
+
* Each preset carries a `dark` and `light` mode block. Values are reproduced
|
|
10
|
+
* byte-for-byte (including the `chromatic.dark.scale = 1.6` quirk that gives
|
|
11
|
+
* the dark chromatic preset its noticeably chunkier features compared with
|
|
12
|
+
* the other dark-mode entries).
|
|
13
|
+
*
|
|
14
|
+
* The fragment shader only consumes uniforms 1..5 of `palette`/`alphas` for
|
|
15
|
+
* the Plasma effect, but the JSON ships 7 colors / alphas to stay
|
|
16
|
+
* forward-compatible with effect 24 (Noise Flow Wide). We keep the full 7 so
|
|
17
|
+
* a future variant could opt into other effects without re-importing the
|
|
18
|
+
* preset definitions.
|
|
19
|
+
*/
|
|
20
|
+
export type PresetName = 'chromatic' | 'silver' | 'gold';
|
|
21
|
+
export type PresetTheme = 'dark' | 'light';
|
|
22
|
+
export interface PresetMode {
|
|
23
|
+
/** 7-stop palette, indexed against `u_color1..u_color7`. */
|
|
24
|
+
colors: [string, string, string, string, string, string, string];
|
|
25
|
+
/** Per-stop alpha weights (0..1). */
|
|
26
|
+
alphas: [number, number, number, number, number, number, number];
|
|
27
|
+
/** Drift angle (degrees). Multiplied by π/180 before upload. */
|
|
28
|
+
direction: number;
|
|
29
|
+
/** Time multiplier applied JS-side before passing into the shader. */
|
|
30
|
+
speed: number;
|
|
31
|
+
/** Plasma intensity (wave-field amplitude). */
|
|
32
|
+
intensity: number;
|
|
33
|
+
/** Noise zoom — smaller = chunkier features. */
|
|
34
|
+
scale: number;
|
|
35
|
+
/** Edge softness (effect 1 ignores; carried for parity). */
|
|
36
|
+
softness: number;
|
|
37
|
+
/** Warp strength on the field (0..1). */
|
|
38
|
+
distortion: number;
|
|
39
|
+
/** FBM octave / frequency multiplier. */
|
|
40
|
+
complexity: number;
|
|
41
|
+
/** Reserved (effect 1 ignores). */
|
|
42
|
+
shape: number;
|
|
43
|
+
/** 9-tap blur sample radius (0 = single tap). */
|
|
44
|
+
blur: number;
|
|
45
|
+
/** Vignette range (0..1). */
|
|
46
|
+
vignette: number;
|
|
47
|
+
/** Vignette darkening strength (0..1). */
|
|
48
|
+
vigOpacity: number;
|
|
49
|
+
/** Final alpha multiplier in the fragment shader (0..1). */
|
|
50
|
+
shaderOpacity: number;
|
|
51
|
+
}
|
|
52
|
+
export interface Preset {
|
|
53
|
+
name: PresetName;
|
|
54
|
+
modes: Record<PresetTheme, PresetMode>;
|
|
55
|
+
}
|
|
56
|
+
export declare const PRESETS: Record<PresetName, Preset>;
|
|
57
|
+
export { hexToRgb } from './color';
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
const CHROMATIC = {
|
|
2
|
+
name: 'chromatic',
|
|
3
|
+
modes: {
|
|
4
|
+
dark: {
|
|
5
|
+
colors: [
|
|
6
|
+
'#000000',
|
|
7
|
+
'#aae8ff',
|
|
8
|
+
'#c5fe9e',
|
|
9
|
+
'#f7888d',
|
|
10
|
+
'#0d0d0d',
|
|
11
|
+
'#fffdc3',
|
|
12
|
+
'#007cff'
|
|
13
|
+
],
|
|
14
|
+
alphas: [
|
|
15
|
+
1,
|
|
16
|
+
1,
|
|
17
|
+
1,
|
|
18
|
+
1,
|
|
19
|
+
1,
|
|
20
|
+
1,
|
|
21
|
+
1
|
|
22
|
+
],
|
|
23
|
+
direction: 80,
|
|
24
|
+
speed: 1.2,
|
|
25
|
+
intensity: 2,
|
|
26
|
+
scale: 1.6,
|
|
27
|
+
softness: 0.18,
|
|
28
|
+
distortion: 0.3,
|
|
29
|
+
complexity: 0.68,
|
|
30
|
+
shape: 1,
|
|
31
|
+
blur: 1,
|
|
32
|
+
vignette: 0.26,
|
|
33
|
+
vigOpacity: 0.6,
|
|
34
|
+
shaderOpacity: 1
|
|
35
|
+
},
|
|
36
|
+
light: {
|
|
37
|
+
colors: [
|
|
38
|
+
'#ffffff',
|
|
39
|
+
'#ffffff',
|
|
40
|
+
'#ffffff',
|
|
41
|
+
'#ffb3b3',
|
|
42
|
+
'#adadad',
|
|
43
|
+
'#f5ff70',
|
|
44
|
+
'#007cff'
|
|
45
|
+
],
|
|
46
|
+
alphas: [
|
|
47
|
+
1,
|
|
48
|
+
1,
|
|
49
|
+
1,
|
|
50
|
+
1,
|
|
51
|
+
1,
|
|
52
|
+
1,
|
|
53
|
+
1
|
|
54
|
+
],
|
|
55
|
+
direction: 80,
|
|
56
|
+
speed: 1.2,
|
|
57
|
+
intensity: 2,
|
|
58
|
+
scale: 2.5,
|
|
59
|
+
softness: 0.18,
|
|
60
|
+
distortion: 0.3,
|
|
61
|
+
complexity: 0.68,
|
|
62
|
+
shape: 1,
|
|
63
|
+
blur: 1,
|
|
64
|
+
vignette: 0.24,
|
|
65
|
+
vigOpacity: 0.16,
|
|
66
|
+
shaderOpacity: 1
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
const SILVER = {
|
|
71
|
+
name: 'silver',
|
|
72
|
+
modes: {
|
|
73
|
+
dark: {
|
|
74
|
+
colors: [
|
|
75
|
+
'#000000',
|
|
76
|
+
'#dedede',
|
|
77
|
+
'#747270',
|
|
78
|
+
'#e5e5e5',
|
|
79
|
+
'#0d0d0d',
|
|
80
|
+
'#ffffff',
|
|
81
|
+
'#e6e6e6'
|
|
82
|
+
],
|
|
83
|
+
alphas: [
|
|
84
|
+
1,
|
|
85
|
+
1,
|
|
86
|
+
1,
|
|
87
|
+
1,
|
|
88
|
+
1,
|
|
89
|
+
1,
|
|
90
|
+
1
|
|
91
|
+
],
|
|
92
|
+
direction: 80,
|
|
93
|
+
speed: 1.2,
|
|
94
|
+
intensity: 2,
|
|
95
|
+
scale: 2.5,
|
|
96
|
+
softness: 0.18,
|
|
97
|
+
distortion: 0.3,
|
|
98
|
+
complexity: 0.68,
|
|
99
|
+
shape: 1,
|
|
100
|
+
blur: 1,
|
|
101
|
+
vignette: 0.26,
|
|
102
|
+
vigOpacity: 0.6,
|
|
103
|
+
shaderOpacity: 0.88
|
|
104
|
+
},
|
|
105
|
+
light: {
|
|
106
|
+
colors: [
|
|
107
|
+
'#f6f6f6',
|
|
108
|
+
'#ffffff',
|
|
109
|
+
'#ffffff',
|
|
110
|
+
'#f7f7f7',
|
|
111
|
+
'#c9c9c9',
|
|
112
|
+
'#d0d0d0',
|
|
113
|
+
'#d1d1d1'
|
|
114
|
+
],
|
|
115
|
+
alphas: [
|
|
116
|
+
1,
|
|
117
|
+
1,
|
|
118
|
+
1,
|
|
119
|
+
1,
|
|
120
|
+
1,
|
|
121
|
+
1,
|
|
122
|
+
1
|
|
123
|
+
],
|
|
124
|
+
direction: 80,
|
|
125
|
+
speed: 1.2,
|
|
126
|
+
intensity: 2,
|
|
127
|
+
scale: 2.5,
|
|
128
|
+
softness: 0.18,
|
|
129
|
+
distortion: 0.3,
|
|
130
|
+
complexity: 0.68,
|
|
131
|
+
shape: 1,
|
|
132
|
+
blur: 1,
|
|
133
|
+
vignette: 0.2,
|
|
134
|
+
vigOpacity: 0.26,
|
|
135
|
+
shaderOpacity: 1
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
const GOLD = {
|
|
140
|
+
name: 'gold',
|
|
141
|
+
modes: {
|
|
142
|
+
dark: {
|
|
143
|
+
colors: [
|
|
144
|
+
'#000000',
|
|
145
|
+
'#ffffff',
|
|
146
|
+
'#ffffff',
|
|
147
|
+
'#f7d488',
|
|
148
|
+
'#0d0d0d',
|
|
149
|
+
'#fffdc3',
|
|
150
|
+
'#ffffff'
|
|
151
|
+
],
|
|
152
|
+
alphas: [
|
|
153
|
+
1,
|
|
154
|
+
1,
|
|
155
|
+
1,
|
|
156
|
+
1,
|
|
157
|
+
1,
|
|
158
|
+
1,
|
|
159
|
+
1
|
|
160
|
+
],
|
|
161
|
+
direction: 80,
|
|
162
|
+
speed: 1.0,
|
|
163
|
+
intensity: 2,
|
|
164
|
+
scale: 2.5,
|
|
165
|
+
softness: 0.18,
|
|
166
|
+
distortion: 0.3,
|
|
167
|
+
complexity: 0.68,
|
|
168
|
+
shape: 1,
|
|
169
|
+
blur: 1,
|
|
170
|
+
vignette: 0.26,
|
|
171
|
+
vigOpacity: 0.6,
|
|
172
|
+
shaderOpacity: 0.92
|
|
173
|
+
},
|
|
174
|
+
light: {
|
|
175
|
+
colors: [
|
|
176
|
+
'#fff8e1',
|
|
177
|
+
'#fffbe0',
|
|
178
|
+
'#ffffff',
|
|
179
|
+
'#fff6d6',
|
|
180
|
+
'#d2c7a7',
|
|
181
|
+
'#dcd2bc',
|
|
182
|
+
'#f9f7e5'
|
|
183
|
+
],
|
|
184
|
+
alphas: [
|
|
185
|
+
1,
|
|
186
|
+
1,
|
|
187
|
+
1,
|
|
188
|
+
1,
|
|
189
|
+
1,
|
|
190
|
+
1,
|
|
191
|
+
1
|
|
192
|
+
],
|
|
193
|
+
direction: 80,
|
|
194
|
+
speed: 1.2,
|
|
195
|
+
intensity: 2,
|
|
196
|
+
scale: 2.5,
|
|
197
|
+
softness: 0.18,
|
|
198
|
+
distortion: 0.3,
|
|
199
|
+
complexity: 0.68,
|
|
200
|
+
shape: 1,
|
|
201
|
+
blur: 1,
|
|
202
|
+
vignette: 0.22,
|
|
203
|
+
vigOpacity: 0.24,
|
|
204
|
+
shaderOpacity: 1
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
const PRESETS = {
|
|
209
|
+
chromatic: CHROMATIC,
|
|
210
|
+
silver: SILVER,
|
|
211
|
+
gold: GOLD
|
|
212
|
+
};
|
|
213
|
+
export { hexToRgb } from "./color.js";
|
|
214
|
+
export { PRESETS };
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { type PresetMode, type PresetName, type PresetTheme } from "../presets";
|
|
2
|
+
export declare const CANONICAL_PILL_W = 140;
|
|
3
|
+
export declare const CANONICAL_PILL_H = 40;
|
|
4
|
+
export declare const PILL_SHADER_SCALE = 1.6;
|
|
5
|
+
export declare const CIRCLE_SHADER_SCALE = 1.3;
|
|
6
|
+
export interface ShaderRGB {
|
|
7
|
+
r: number;
|
|
8
|
+
g: number;
|
|
9
|
+
b: number;
|
|
10
|
+
}
|
|
11
|
+
export interface MetalFxInstance {
|
|
12
|
+
canvas: HTMLCanvasElement;
|
|
13
|
+
ctx: CanvasRenderingContext2D;
|
|
14
|
+
cssWidth: number;
|
|
15
|
+
cssHeight: number;
|
|
16
|
+
cornerRadius: number;
|
|
17
|
+
kind: 'pill' | 'circle';
|
|
18
|
+
ringCssPx: number;
|
|
19
|
+
shaderScale: number;
|
|
20
|
+
opacityMul: number;
|
|
21
|
+
visible: boolean;
|
|
22
|
+
/** Per-instance freeze flag. When true the instance's 2D canvas keeps the
|
|
23
|
+
* last copied frame; the shared GL loop continues for any other unpaused
|
|
24
|
+
* instance. */
|
|
25
|
+
paused: boolean;
|
|
26
|
+
/** Set to true after the first successful copyShaderToInstance — so an
|
|
27
|
+
* instance that mounts already paused still gets one frame painted before
|
|
28
|
+
* it freezes (otherwise it would render a blank canvas). */
|
|
29
|
+
everCopied: boolean;
|
|
30
|
+
dpr: number;
|
|
31
|
+
presetName: PresetName;
|
|
32
|
+
presetTheme: PresetTheme;
|
|
33
|
+
glowEnabled: boolean;
|
|
34
|
+
/** Master scale multiplier for absolute-pixel internals (glow stroke
|
|
35
|
+
* widths/blurs, reflection stroke band, etc.). 1 is the baseline. Set to
|
|
36
|
+
* 2 for a CSS-zoomed 2× hero so glow + reflection grow with the layout. */
|
|
37
|
+
scale: number;
|
|
38
|
+
onAfterFrame?: () => void;
|
|
39
|
+
/** One-shot callback fired after the very first copyShaderToInstance.
|
|
40
|
+
* Auto-cleared by the loop so it never fires twice. */
|
|
41
|
+
onFirstCopy?: () => void;
|
|
42
|
+
}
|
|
43
|
+
export interface SharedRenderer {
|
|
44
|
+
glCanvas: HTMLCanvasElement | OffscreenCanvas;
|
|
45
|
+
gl: WebGLRenderingContext;
|
|
46
|
+
program: WebGLProgram;
|
|
47
|
+
buffer: WebGLBuffer;
|
|
48
|
+
uniforms: Record<string, WebGLUniformLocation | null>;
|
|
49
|
+
preset: PresetMode;
|
|
50
|
+
presetName: PresetName;
|
|
51
|
+
presetTheme: PresetTheme;
|
|
52
|
+
presetDirty: boolean;
|
|
53
|
+
contextLost: boolean;
|
|
54
|
+
useOffscreen: boolean;
|
|
55
|
+
startMs: number;
|
|
56
|
+
pausedMs: number;
|
|
57
|
+
pausedAtMs: number | null;
|
|
58
|
+
rafId: number;
|
|
59
|
+
dpr: number;
|
|
60
|
+
instances: Set<MetalFxInstance>;
|
|
61
|
+
frameCount: number;
|
|
62
|
+
glowPixels: Uint8Array;
|
|
63
|
+
glowPixelsW: number;
|
|
64
|
+
glowPixelsH: number;
|
|
65
|
+
}
|
|
66
|
+
export declare let SHARED: SharedRenderer | null;
|
|
67
|
+
export declare function setContextRestoredCallback(cb: (() => void) | null): void;
|
|
68
|
+
export declare function ensureSharedRenderer(): SharedRenderer;
|
|
69
|
+
export declare function teardownSharedRenderer(): void;
|