@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.
Files changed (126) hide show
  1. package/LICENSE +22 -22
  2. package/README.md +132 -59
  3. package/dist/components/accordion/Accordion.css +158 -158
  4. package/dist/components/alert/Alert.css +116 -116
  5. package/dist/components/avatar/Avatar.css +124 -124
  6. package/dist/components/badge/Badge.css +164 -164
  7. package/dist/components/breadcrumbs/Breadcrumbs.css +63 -63
  8. package/dist/components/button/Button.css +194 -194
  9. package/dist/components/button-group/ButtonGroup.css +117 -117
  10. package/dist/components/calendar/Calendar.css +258 -258
  11. package/dist/components/card/Card.css +110 -110
  12. package/dist/components/chatbubble/ChatBubble.css +164 -164
  13. package/dist/components/checkbox/Checkbox.css +183 -183
  14. package/dist/components/checkbox-group/CheckboxGroup.css +10 -10
  15. package/dist/components/chip/Chip.css +197 -197
  16. package/dist/components/close-button/CloseButton.css +81 -81
  17. package/dist/components/color-area/ColorArea.css +54 -54
  18. package/dist/components/color-field/ColorField.css +88 -88
  19. package/dist/components/color-picker/ColorPicker.css +28 -28
  20. package/dist/components/color-slider/ColorSlider.css +57 -57
  21. package/dist/components/color-swatch/ColorSwatch.css +84 -84
  22. package/dist/components/color-swatch-picker/ColorSwatchPicker.css +12 -12
  23. package/dist/components/color-wheel-flower/ColorWheelFlower.css +147 -147
  24. package/dist/components/combo-box/ComboBox.css +344 -344
  25. package/dist/components/date-field/DateField.css +215 -215
  26. package/dist/components/date-picker/DatePicker.css +143 -143
  27. package/dist/components/date-range-picker/DateRangePicker.css +149 -149
  28. package/dist/components/description/Description.css +10 -10
  29. package/dist/components/disclosure/Disclosure.css +84 -84
  30. package/dist/components/disclosure-group/DisclosureGroup.css +9 -9
  31. package/dist/components/drawer/Drawer.css +463 -463
  32. package/dist/components/dropdown/Dropdown.css +211 -211
  33. package/dist/components/empty-state/EmptyState.css +39 -39
  34. package/dist/components/error-message/ErrorMessage.css +20 -20
  35. package/dist/components/field-error/FieldError.css +27 -27
  36. package/dist/components/fieldset/Fieldset.css +30 -30
  37. package/dist/components/flex/Flex.css +5 -5
  38. package/dist/components/floating-dock/FloatingDock.css +208 -208
  39. package/dist/components/footer/footer.css +51 -51
  40. package/dist/components/form/Form.css +5 -5
  41. package/dist/components/glass-panel/GlassPanel.css +359 -359
  42. package/dist/components/glow-card/GlowCard.css +100 -100
  43. package/dist/components/grid/Grid.css +5 -5
  44. package/dist/components/header/Header.css +13 -13
  45. package/dist/components/icon/Icon.css +10 -10
  46. package/dist/components/immersive-landing/ImmersiveLanding.css +565 -565
  47. package/dist/components/input/Input.css +155 -155
  48. package/dist/components/input-group/InputGroup.css +172 -172
  49. package/dist/components/input-otp/InputOTP.css +170 -170
  50. package/dist/components/kbd/Kbd.css +60 -60
  51. package/dist/components/label/Label.css +30 -30
  52. package/dist/components/language-switcher/LanguageSwitcher.css +56 -56
  53. package/dist/components/language-switcher/createI18n.d.ts +2 -1
  54. package/dist/components/link/Link.css +131 -131
  55. package/dist/components/list-box/ListBox.css +148 -148
  56. package/dist/components/live-chat/LiveChat.css +324 -324
  57. package/dist/components/menu/Menu.css +199 -199
  58. package/dist/components/metal-border/MetalBorder.classes.d.ts +26 -0
  59. package/dist/components/metal-border/MetalBorder.classes.js +27 -0
  60. package/dist/components/metal-border/MetalBorder.css +40 -0
  61. package/dist/components/metal-border/MetalBorder.d.ts +20 -0
  62. package/dist/components/metal-border/MetalBorder.js +322 -0
  63. package/dist/components/metal-border/engine/color.d.ts +4 -0
  64. package/dist/components/metal-border/engine/color.js +69 -0
  65. package/dist/components/metal-border/engine/glow/geometry.d.ts +35 -0
  66. package/dist/components/metal-border/engine/glow/geometry.js +176 -0
  67. package/dist/components/metal-border/engine/glow/glow.d.ts +38 -0
  68. package/dist/components/metal-border/engine/glow/glow.js +246 -0
  69. package/dist/components/metal-border/engine/index.d.ts +4 -0
  70. package/dist/components/metal-border/engine/index.js +2 -0
  71. package/dist/components/metal-border/engine/perfConfig.d.ts +9 -0
  72. package/dist/components/metal-border/engine/perfConfig.js +10 -0
  73. package/dist/components/metal-border/engine/presets.d.ts +57 -0
  74. package/dist/components/metal-border/engine/presets.js +214 -0
  75. package/dist/components/metal-border/engine/renderer/core.d.ts +69 -0
  76. package/dist/components/metal-border/engine/renderer/core.js +156 -0
  77. package/dist/components/metal-border/engine/renderer/loop.d.ts +30 -0
  78. package/dist/components/metal-border/engine/renderer/loop.js +248 -0
  79. package/dist/components/metal-border/engine/renderer/sampling.d.ts +14 -0
  80. package/dist/components/metal-border/engine/renderer/sampling.js +145 -0
  81. package/dist/components/metal-border/engine/shaders.d.ts +36 -0
  82. package/dist/components/metal-border/engine/shaders.js +215 -0
  83. package/dist/components/metal-border/engine/tween.d.ts +17 -0
  84. package/dist/components/metal-border/engine/tween.js +28 -0
  85. package/dist/components/metal-border/index.d.ts +2 -0
  86. package/dist/components/metal-border/index.js +1 -0
  87. package/dist/components/meter/Meter.css +89 -89
  88. package/dist/components/modal/Modal.css +320 -320
  89. package/dist/components/navbar/Navbar.css +110 -110
  90. package/dist/components/noise-background/NoiseBackground.css +66 -66
  91. package/dist/components/number-field/NumberField.css +198 -198
  92. package/dist/components/pagination/Pagination.css +121 -121
  93. package/dist/components/popover/Popover.css +117 -117
  94. package/dist/components/progress-bar/ProgressBar.css +104 -104
  95. package/dist/components/progress-circle/ProgressCircle.css +82 -82
  96. package/dist/components/radio/Radio.css +129 -129
  97. package/dist/components/radio-group/RadioGroup.css +58 -58
  98. package/dist/components/range-calendar/RangeCalendar.css +51 -51
  99. package/dist/components/scroll-shadow/ScrollShadow.css +93 -93
  100. package/dist/components/search-field/SearchField.css +183 -183
  101. package/dist/components/select/Select.css +284 -284
  102. package/dist/components/separator/Separator.css +35 -35
  103. package/dist/components/skeleton/Skeleton.css +95 -95
  104. package/dist/components/slider/Slider.css +122 -122
  105. package/dist/components/spinner/Spinner.css +131 -131
  106. package/dist/components/surface/Surface.css +37 -37
  107. package/dist/components/table/Table.css +426 -426
  108. package/dist/components/tabs/Tabs.css +203 -203
  109. package/dist/components/tag/Tag.css +121 -121
  110. package/dist/components/tag-group/TagGroup.css +22 -22
  111. package/dist/components/text/Text.css +66 -66
  112. package/dist/components/text-area/TextArea.css +95 -95
  113. package/dist/components/text-field/TextField.css +33 -33
  114. package/dist/components/time-field/TimeField.css +215 -215
  115. package/dist/components/toast/Toast.css +344 -344
  116. package/dist/components/toggle/Toggle.css +237 -237
  117. package/dist/components/toolbar/Toolbar.css +55 -55
  118. package/dist/components/tooltip/Tooltip.css +153 -153
  119. package/dist/index.css +74 -74
  120. package/dist/index.d.ts +2 -0
  121. package/dist/index.js +1 -0
  122. package/dist/purge-manifest.json +15836 -15583
  123. package/dist/styles/base/index.css +43 -43
  124. package/dist/styles/themes/dark.css +141 -141
  125. package/dist/styles/themes/light.css +143 -143
  126. 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,2 @@
1
+ export { createInstance, destroyInstance, registerGlowInstance, setGlowCallback, setInstanceVisible, unregisterGlowInstance, updateInstance } from "./renderer/loop.js";
2
+ export { injectGlow, resizeGlow, updateGlow } from "./glow/glow.js";
@@ -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;