@pathscale/ui 1.2.9 → 1.2.11

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 (125) hide show
  1. package/LICENSE +22 -22
  2. package/README.md +59 -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/link/Link.css +131 -131
  54. package/dist/components/list-box/ListBox.css +148 -148
  55. package/dist/components/live-chat/LiveChat.css +324 -324
  56. package/dist/components/menu/Menu.css +199 -199
  57. package/dist/components/metal-border/MetalBorder.classes.d.ts +26 -0
  58. package/dist/components/metal-border/MetalBorder.classes.js +27 -0
  59. package/dist/components/metal-border/MetalBorder.css +40 -0
  60. package/dist/components/metal-border/MetalBorder.d.ts +20 -0
  61. package/dist/components/metal-border/MetalBorder.js +322 -0
  62. package/dist/components/metal-border/engine/color.d.ts +4 -0
  63. package/dist/components/metal-border/engine/color.js +69 -0
  64. package/dist/components/metal-border/engine/glow/geometry.d.ts +35 -0
  65. package/dist/components/metal-border/engine/glow/geometry.js +176 -0
  66. package/dist/components/metal-border/engine/glow/glow.d.ts +38 -0
  67. package/dist/components/metal-border/engine/glow/glow.js +246 -0
  68. package/dist/components/metal-border/engine/index.d.ts +4 -0
  69. package/dist/components/metal-border/engine/index.js +2 -0
  70. package/dist/components/metal-border/engine/perfConfig.d.ts +9 -0
  71. package/dist/components/metal-border/engine/perfConfig.js +10 -0
  72. package/dist/components/metal-border/engine/presets.d.ts +57 -0
  73. package/dist/components/metal-border/engine/presets.js +214 -0
  74. package/dist/components/metal-border/engine/renderer/core.d.ts +69 -0
  75. package/dist/components/metal-border/engine/renderer/core.js +156 -0
  76. package/dist/components/metal-border/engine/renderer/loop.d.ts +30 -0
  77. package/dist/components/metal-border/engine/renderer/loop.js +248 -0
  78. package/dist/components/metal-border/engine/renderer/sampling.d.ts +14 -0
  79. package/dist/components/metal-border/engine/renderer/sampling.js +145 -0
  80. package/dist/components/metal-border/engine/shaders.d.ts +36 -0
  81. package/dist/components/metal-border/engine/shaders.js +215 -0
  82. package/dist/components/metal-border/engine/tween.d.ts +17 -0
  83. package/dist/components/metal-border/engine/tween.js +28 -0
  84. package/dist/components/metal-border/index.d.ts +2 -0
  85. package/dist/components/metal-border/index.js +1 -0
  86. package/dist/components/meter/Meter.css +89 -89
  87. package/dist/components/modal/Modal.css +320 -320
  88. package/dist/components/navbar/Navbar.css +110 -110
  89. package/dist/components/noise-background/NoiseBackground.css +66 -66
  90. package/dist/components/number-field/NumberField.css +198 -198
  91. package/dist/components/pagination/Pagination.css +121 -121
  92. package/dist/components/popover/Popover.css +117 -117
  93. package/dist/components/progress-bar/ProgressBar.css +104 -104
  94. package/dist/components/progress-circle/ProgressCircle.css +82 -82
  95. package/dist/components/radio/Radio.css +129 -129
  96. package/dist/components/radio-group/RadioGroup.css +58 -58
  97. package/dist/components/range-calendar/RangeCalendar.css +51 -51
  98. package/dist/components/scroll-shadow/ScrollShadow.css +93 -93
  99. package/dist/components/search-field/SearchField.css +183 -183
  100. package/dist/components/select/Select.css +284 -284
  101. package/dist/components/separator/Separator.css +35 -35
  102. package/dist/components/skeleton/Skeleton.css +95 -95
  103. package/dist/components/slider/Slider.css +122 -122
  104. package/dist/components/spinner/Spinner.css +131 -131
  105. package/dist/components/surface/Surface.css +37 -37
  106. package/dist/components/table/Table.css +426 -426
  107. package/dist/components/tabs/Tabs.css +203 -203
  108. package/dist/components/tag/Tag.css +121 -121
  109. package/dist/components/tag-group/TagGroup.css +22 -22
  110. package/dist/components/text/Text.css +66 -66
  111. package/dist/components/text-area/TextArea.css +95 -95
  112. package/dist/components/text-field/TextField.css +33 -33
  113. package/dist/components/time-field/TimeField.css +215 -215
  114. package/dist/components/toast/Toast.css +344 -344
  115. package/dist/components/toggle/Toggle.css +237 -237
  116. package/dist/components/toolbar/Toolbar.css +55 -55
  117. package/dist/components/tooltip/Tooltip.css +153 -153
  118. package/dist/index.css +74 -74
  119. package/dist/index.d.ts +2 -0
  120. package/dist/index.js +1 -0
  121. package/dist/purge-manifest.json +15100 -14847
  122. package/dist/styles/base/index.css +43 -43
  123. package/dist/styles/themes/dark.css +141 -141
  124. package/dist/styles/themes/light.css +143 -143
  125. package/package.json +3 -3
@@ -0,0 +1,156 @@
1
+ import { CANONICAL_GL_SIZE, GL_DPR_CAP } from "../perfConfig.js";
2
+ import { PRESETS } from "../presets.js";
3
+ import { FRAG_SHADER_SRC, VERT_SHADER_SRC, compileShader, linkProgram } from "../shaders.js";
4
+ const CANONICAL_PILL_W = 140;
5
+ const CANONICAL_PILL_H = 40;
6
+ const PILL_SHADER_SCALE = 1.6;
7
+ const CIRCLE_SHADER_SCALE = 1.3;
8
+ let SHARED = null;
9
+ let _onContextRestored = null;
10
+ function setContextRestoredCallback(cb) {
11
+ _onContextRestored = cb;
12
+ }
13
+ const UNIFORM_NAMES = [
14
+ "u_resolution",
15
+ "u_time",
16
+ "u_color1",
17
+ "u_color2",
18
+ "u_color3",
19
+ "u_color4",
20
+ "u_color5",
21
+ "u_color6",
22
+ "u_color7",
23
+ "u_alpha1",
24
+ "u_alpha2",
25
+ "u_alpha3",
26
+ "u_alpha4",
27
+ "u_alpha5",
28
+ "u_alpha6",
29
+ "u_alpha7",
30
+ "u_intensity",
31
+ "u_scale",
32
+ "u_direction",
33
+ "u_softness",
34
+ "u_distortion",
35
+ "u_complexity",
36
+ "u_shape",
37
+ "u_vignette",
38
+ "u_vigOpacity",
39
+ "u_blur",
40
+ "u_shaderOpacity"
41
+ ];
42
+ function buildGLPipeline(gl) {
43
+ gl.enable(gl.BLEND);
44
+ gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
45
+ const vert = compileShader(gl, gl.VERTEX_SHADER, VERT_SHADER_SRC);
46
+ const frag = compileShader(gl, gl.FRAGMENT_SHADER, FRAG_SHADER_SRC);
47
+ const program = linkProgram(gl, vert, frag);
48
+ gl.useProgram(program);
49
+ const buffer = gl.createBuffer();
50
+ if (!buffer) throw new Error("metal-fx: gl.createBuffer returned null");
51
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
52
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
53
+ -1,
54
+ -1,
55
+ 1,
56
+ -1,
57
+ -1,
58
+ 1,
59
+ -1,
60
+ 1,
61
+ 1,
62
+ -1,
63
+ 1,
64
+ 1
65
+ ]), gl.STATIC_DRAW);
66
+ const posLoc = gl.getAttribLocation(program, "a_position");
67
+ gl.enableVertexAttribArray(posLoc);
68
+ gl.vertexAttribPointer(posLoc, 2, gl.FLOAT, false, 0, 0);
69
+ const uniforms = {};
70
+ for (const n of UNIFORM_NAMES)uniforms[n] = gl.getUniformLocation(program, n);
71
+ return {
72
+ program,
73
+ buffer,
74
+ uniforms
75
+ };
76
+ }
77
+ function ensureSharedRenderer() {
78
+ if (SHARED) return SHARED;
79
+ const dpr = Math.min(GL_DPR_CAP, "u" > typeof window ? window.devicePixelRatio || 1 : 1);
80
+ const size = Math.round(CANONICAL_GL_SIZE * dpr);
81
+ const useOffscreen = "u" > typeof OffscreenCanvas;
82
+ let glCanvas;
83
+ let gl;
84
+ if (useOffscreen) {
85
+ glCanvas = new OffscreenCanvas(size, size);
86
+ gl = glCanvas.getContext("webgl", {
87
+ alpha: true,
88
+ premultipliedAlpha: false,
89
+ antialias: false
90
+ });
91
+ } else {
92
+ const htmlCanvas = document.createElement("canvas");
93
+ htmlCanvas.width = size;
94
+ htmlCanvas.height = size;
95
+ gl = htmlCanvas.getContext("webgl", {
96
+ alpha: true,
97
+ premultipliedAlpha: false,
98
+ antialias: false,
99
+ preserveDrawingBuffer: true
100
+ }) ?? htmlCanvas.getContext("experimental-webgl");
101
+ glCanvas = htmlCanvas;
102
+ }
103
+ if (!gl) throw new Error("metal-fx: WebGL not supported");
104
+ const { program, buffer, uniforms } = buildGLPipeline(gl);
105
+ const onContextLost = (e)=>{
106
+ e.preventDefault();
107
+ if (SHARED) SHARED.contextLost = true;
108
+ };
109
+ const onContextRestored = ()=>{
110
+ if (!SHARED) return;
111
+ const rebuilt = buildGLPipeline(SHARED.gl);
112
+ SHARED.program = rebuilt.program;
113
+ SHARED.buffer = rebuilt.buffer;
114
+ SHARED.uniforms = rebuilt.uniforms;
115
+ SHARED.presetDirty = true;
116
+ SHARED.contextLost = false;
117
+ _onContextRestored?.();
118
+ };
119
+ glCanvas.addEventListener("webglcontextlost", onContextLost, false);
120
+ glCanvas.addEventListener("webglcontextrestored", onContextRestored, false);
121
+ SHARED = {
122
+ glCanvas,
123
+ gl,
124
+ program,
125
+ buffer,
126
+ uniforms,
127
+ preset: PRESETS.chromatic.modes.dark,
128
+ presetName: "chromatic",
129
+ presetTheme: "dark",
130
+ presetDirty: true,
131
+ contextLost: false,
132
+ useOffscreen,
133
+ startMs: performance.now(),
134
+ pausedMs: 0,
135
+ pausedAtMs: null,
136
+ rafId: 0,
137
+ dpr,
138
+ instances: new Set(),
139
+ frameCount: 0,
140
+ glowPixels: new Uint8Array(size * size * 4),
141
+ glowPixelsW: size,
142
+ glowPixelsH: size
143
+ };
144
+ return SHARED;
145
+ }
146
+ function teardownSharedRenderer() {
147
+ if (!SHARED) return;
148
+ const { gl, program, buffer } = SHARED;
149
+ try {
150
+ gl.deleteBuffer(buffer);
151
+ gl.deleteProgram(program);
152
+ gl.getExtension("WEBGL_lose_context")?.loseContext();
153
+ } catch {}
154
+ SHARED = null;
155
+ }
156
+ export { CANONICAL_PILL_H, CANONICAL_PILL_W, CIRCLE_SHADER_SCALE, PILL_SHADER_SCALE, SHARED, ensureSharedRenderer, setContextRestoredCallback, teardownSharedRenderer };
@@ -0,0 +1,30 @@
1
+ import { type PresetName, type PresetTheme } from "../presets";
2
+ import { type MetalFxInstance } from "./core";
3
+ interface CreateInstanceOptions {
4
+ hostCanvas: HTMLCanvasElement;
5
+ cssWidth: number;
6
+ cssHeight: number;
7
+ cornerRadius: number;
8
+ kind: "pill" | "circle";
9
+ presetName: PresetName;
10
+ presetTheme: PresetTheme;
11
+ shaderScale?: number;
12
+ ringCssPx?: number;
13
+ opacityMul?: number;
14
+ paused?: boolean;
15
+ scale?: number;
16
+ onAfterFrame?: () => void;
17
+ onFirstCopy?: () => void;
18
+ }
19
+ export declare function createInstance(opts: CreateInstanceOptions): MetalFxInstance;
20
+ export declare function destroyInstance(inst: MetalFxInstance): void;
21
+ export declare function registerGlowInstance(inst: MetalFxInstance): void;
22
+ export declare function unregisterGlowInstance(inst: MetalFxInstance): void;
23
+ export declare function updateInstance(inst: MetalFxInstance, patch: Partial<Pick<MetalFxInstance, "cssWidth" | "cssHeight" | "cornerRadius" | "kind" | "shaderScale" | "ringCssPx" | "opacityMul" | "paused" | "presetName" | "presetTheme" | "scale">>): void;
24
+ export declare function setInstanceVisible(inst: MetalFxInstance, visible: boolean): void;
25
+ export declare function pauseShared(): void;
26
+ export declare function resumeShared(): void;
27
+ export declare function getSharedFrameCount(): number;
28
+ export type GlowCallback = (inst: MetalFxInstance, nowMs: number) => void;
29
+ export declare function setGlowCallback(cb: GlowCallback | null): void;
30
+ export {};
@@ -0,0 +1,248 @@
1
+ import { hexToRgb } from "../color.js";
2
+ import { FRAME_INTERVAL_MS, GLOW_SKIP_FRAMES } from "../perfConfig.js";
3
+ import { PRESETS } from "../presets.js";
4
+ import { CANONICAL_PILL_H, CANONICAL_PILL_W, CIRCLE_SHADER_SCALE, PILL_SHADER_SCALE, SHARED, ensureSharedRenderer, setContextRestoredCallback, teardownSharedRenderer } from "./core.js";
5
+ import { refreshGlowPixels } from "./sampling.js";
6
+ setContextRestoredCallback(()=>{
7
+ if (SHARED && SHARED.instances.size > 0 && null === SHARED.pausedAtMs) startSharedLoop();
8
+ });
9
+ if ("u" > typeof document) document.addEventListener("visibilitychange", ()=>{
10
+ if (!SHARED || null !== SHARED.pausedAtMs || SHARED.contextLost) return;
11
+ if (document.hidden) stopSharedLoop();
12
+ else if (SHARED.instances.size > 0) startSharedLoop();
13
+ });
14
+ function createInstance(opts) {
15
+ const renderer = ensureSharedRenderer();
16
+ const ctx = opts.hostCanvas.getContext("2d", {
17
+ alpha: true
18
+ });
19
+ if (!ctx) throw new Error("metal-fx: canvas 2D context unavailable");
20
+ const scale = opts.scale ?? 1;
21
+ const inst = {
22
+ canvas: opts.hostCanvas,
23
+ ctx,
24
+ cssWidth: opts.cssWidth,
25
+ cssHeight: opts.cssHeight,
26
+ cornerRadius: opts.cornerRadius,
27
+ kind: opts.kind,
28
+ ringCssPx: opts.ringCssPx ?? ("circle" === opts.kind ? 2 : 1) * scale,
29
+ shaderScale: opts.shaderScale ?? ("circle" === opts.kind ? CIRCLE_SHADER_SCALE : PILL_SHADER_SCALE) * scale,
30
+ opacityMul: opts.opacityMul ?? 1,
31
+ visible: true,
32
+ paused: opts.paused ?? false,
33
+ everCopied: false,
34
+ dpr: "u" > typeof window ? window.devicePixelRatio || 1 : 1,
35
+ presetName: opts.presetName,
36
+ presetTheme: opts.presetTheme,
37
+ glowEnabled: false,
38
+ scale,
39
+ onAfterFrame: opts.onAfterFrame,
40
+ onFirstCopy: opts.onFirstCopy
41
+ };
42
+ resizeInstanceCanvas(inst);
43
+ renderer.instances.add(inst);
44
+ if (0 === renderer.rafId && null === renderer.pausedAtMs) startSharedLoop();
45
+ return inst;
46
+ }
47
+ function destroyInstance(inst) {
48
+ if (!SHARED) return;
49
+ SHARED.instances["delete"](inst);
50
+ if (0 === SHARED.instances.size) {
51
+ stopSharedLoop();
52
+ teardownSharedRenderer();
53
+ }
54
+ }
55
+ function registerGlowInstance(inst) {
56
+ inst.glowEnabled = true;
57
+ }
58
+ function unregisterGlowInstance(inst) {
59
+ inst.glowEnabled = false;
60
+ }
61
+ function updateInstance(inst, patch) {
62
+ let dirty = false;
63
+ if (void 0 !== patch.cssWidth && patch.cssWidth !== inst.cssWidth) {
64
+ inst.cssWidth = patch.cssWidth;
65
+ dirty = true;
66
+ }
67
+ if (void 0 !== patch.cssHeight && patch.cssHeight !== inst.cssHeight) {
68
+ inst.cssHeight = patch.cssHeight;
69
+ dirty = true;
70
+ }
71
+ if (void 0 !== patch.cornerRadius) inst.cornerRadius = patch.cornerRadius;
72
+ if (void 0 !== patch.scale) inst.scale = patch.scale;
73
+ if (void 0 !== patch.kind && patch.kind !== inst.kind) {
74
+ inst.kind = patch.kind;
75
+ if (void 0 === patch.shaderScale) inst.shaderScale = ("circle" === patch.kind ? CIRCLE_SHADER_SCALE : PILL_SHADER_SCALE) * inst.scale;
76
+ if (void 0 === patch.ringCssPx) inst.ringCssPx = ("circle" === patch.kind ? 2 : 1) * inst.scale;
77
+ }
78
+ if (void 0 !== patch.shaderScale) inst.shaderScale = patch.shaderScale;
79
+ if (void 0 !== patch.ringCssPx) inst.ringCssPx = patch.ringCssPx;
80
+ if (void 0 !== patch.opacityMul) inst.opacityMul = patch.opacityMul;
81
+ if (void 0 !== patch.presetName) inst.presetName = patch.presetName;
82
+ if (void 0 !== patch.presetTheme) inst.presetTheme = patch.presetTheme;
83
+ if (void 0 !== patch.paused && patch.paused !== inst.paused) {
84
+ inst.paused = patch.paused;
85
+ if (!patch.paused && SHARED && 0 === SHARED.rafId && null === SHARED.pausedAtMs && !SHARED.contextLost) startSharedLoop();
86
+ }
87
+ if (dirty) resizeInstanceCanvas(inst);
88
+ }
89
+ function setInstanceVisible(inst, visible) {
90
+ inst.visible = visible;
91
+ if (visible && SHARED && 0 === SHARED.rafId && null === SHARED.pausedAtMs && !SHARED.contextLost) startSharedLoop();
92
+ }
93
+ function syncRendererPreset(name, theme) {
94
+ const shared = ensureSharedRenderer();
95
+ if (shared.presetName === name && shared.presetTheme === theme && !shared.presetDirty) return;
96
+ shared.preset = PRESETS[name].modes[theme];
97
+ shared.presetName = name;
98
+ shared.presetTheme = theme;
99
+ shared.presetDirty = true;
100
+ }
101
+ function pauseShared() {
102
+ if (!SHARED || null !== SHARED.pausedAtMs) return;
103
+ SHARED.pausedAtMs = performance.now();
104
+ stopSharedLoop();
105
+ }
106
+ function resumeShared() {
107
+ if (!SHARED || null === SHARED.pausedAtMs) return;
108
+ SHARED.pausedMs += performance.now() - SHARED.pausedAtMs;
109
+ SHARED.pausedAtMs = null;
110
+ if (SHARED.instances.size > 0) startSharedLoop();
111
+ }
112
+ function getSharedFrameCount() {
113
+ return SHARED?.frameCount ?? 0;
114
+ }
115
+ let _glowCallback = null;
116
+ function setGlowCallback(cb) {
117
+ _glowCallback = cb;
118
+ }
119
+ function resizeInstanceCanvas(inst) {
120
+ inst.dpr = "u" > typeof window ? window.devicePixelRatio || 1 : 1;
121
+ const w = Math.max(1, Math.round(inst.cssWidth * inst.dpr));
122
+ const h = Math.max(1, Math.round(inst.cssHeight * inst.dpr));
123
+ if (inst.canvas.width !== w) inst.canvas.width = w;
124
+ if (inst.canvas.height !== h) inst.canvas.height = h;
125
+ }
126
+ function punchInnerHole(inst) {
127
+ const { ctx, dpr, canvas } = inst;
128
+ const stroke = inst.ringCssPx * dpr;
129
+ const w = canvas.width;
130
+ const h = canvas.height;
131
+ const innerR = Math.max(0, (inst.cornerRadius - inst.ringCssPx) * dpr);
132
+ ctx.save();
133
+ ctx.globalCompositeOperation = "destination-out";
134
+ ctx.fillStyle = "#000";
135
+ ctx.beginPath();
136
+ ctx.roundRect(stroke, stroke, w - 2 * stroke, h - 2 * stroke, innerR);
137
+ ctx.fill();
138
+ ctx.restore();
139
+ }
140
+ function copyShaderToInstance(inst) {
141
+ if (!SHARED) return;
142
+ const src = SHARED.glCanvas;
143
+ const dpr = inst.dpr;
144
+ const dw = inst.canvas.width;
145
+ const dh = inst.canvas.height;
146
+ if (dw < 1 || dh < 1) return;
147
+ const cw = SHARED.glCanvas.width;
148
+ const ch = SHARED.glCanvas.height;
149
+ const bdW = CANONICAL_PILL_W * dpr;
150
+ const bdH = CANONICAL_PILL_H * dpr;
151
+ let srcW = cw / bdW * dw / inst.shaderScale;
152
+ let srcH = ch / bdH * dh / inst.shaderScale;
153
+ if (srcW > cw) srcW = cw;
154
+ if (srcH > ch) srcH = ch;
155
+ const sx = Math.max(0, (cw - srcW) / 2);
156
+ const sy = Math.max(0, (ch - srcH) / 2);
157
+ inst.ctx.clearRect(0, 0, dw, dh);
158
+ if (inst.opacityMul < 1) inst.ctx.globalAlpha = inst.opacityMul;
159
+ inst.ctx.drawImage(src, sx, sy, srcW, srcH, 0, 0, dw, dh);
160
+ if (inst.opacityMul < 1) inst.ctx.globalAlpha = 1;
161
+ punchInnerHole(inst);
162
+ if (inst.onFirstCopy) {
163
+ const cb = inst.onFirstCopy;
164
+ inst.onFirstCopy = void 0;
165
+ cb();
166
+ }
167
+ inst.onAfterFrame?.();
168
+ }
169
+ function uploadPresetUniforms() {
170
+ if (!SHARED) return;
171
+ const { gl, uniforms, preset, glCanvas } = SHARED;
172
+ if (uniforms.u_resolution) gl.uniform2f(uniforms.u_resolution, glCanvas.width, glCanvas.height);
173
+ for(let i = 0; i < 7; i++){
174
+ const cLoc = uniforms[`u_color${i + 1}`];
175
+ if (cLoc) {
176
+ const [r, g, b] = hexToRgb(preset.colors[i]);
177
+ gl.uniform3f(cLoc, r, g, b);
178
+ }
179
+ const aLoc = uniforms[`u_alpha${i + 1}`];
180
+ if (aLoc) gl.uniform1f(aLoc, preset.alphas[i]);
181
+ }
182
+ if (uniforms.u_intensity) gl.uniform1f(uniforms.u_intensity, preset.intensity);
183
+ if (uniforms.u_scale) gl.uniform1f(uniforms.u_scale, preset.scale);
184
+ if (uniforms.u_direction) gl.uniform1f(uniforms.u_direction, preset.direction * Math.PI / 180);
185
+ if (uniforms.u_softness) gl.uniform1f(uniforms.u_softness, preset.softness);
186
+ if (uniforms.u_distortion) gl.uniform1f(uniforms.u_distortion, preset.distortion);
187
+ if (uniforms.u_complexity) gl.uniform1f(uniforms.u_complexity, preset.complexity);
188
+ if (uniforms.u_shape) gl.uniform1f(uniforms.u_shape, preset.shape);
189
+ if (uniforms.u_vignette) gl.uniform1f(uniforms.u_vignette, preset.vignette);
190
+ if (uniforms.u_vigOpacity) gl.uniform1f(uniforms.u_vigOpacity, preset.vigOpacity);
191
+ if (uniforms.u_blur) gl.uniform1f(uniforms.u_blur, preset.blur);
192
+ if (uniforms.u_shaderOpacity) gl.uniform1f(uniforms.u_shaderOpacity, preset.shaderOpacity);
193
+ SHARED.presetDirty = false;
194
+ }
195
+ function renderSharedFrame(now, presetName, presetTheme) {
196
+ if (!SHARED) return;
197
+ syncRendererPreset(presetName, presetTheme);
198
+ const { gl, uniforms, preset, glCanvas } = SHARED;
199
+ const t = (now - SHARED.startMs - SHARED.pausedMs) / 1000 * preset.speed;
200
+ gl.viewport(0, 0, glCanvas.width, glCanvas.height);
201
+ gl.clearColor(0, 0, 0, 0);
202
+ gl.clear(gl.COLOR_BUFFER_BIT);
203
+ if (SHARED.presetDirty) uploadPresetUniforms();
204
+ if (uniforms.u_time) gl.uniform1f(uniforms.u_time, t);
205
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
206
+ SHARED.frameCount++;
207
+ }
208
+ let lastFrameMs = 0;
209
+ function tick(now) {
210
+ if (!SHARED) return;
211
+ if (SHARED.contextLost) {
212
+ SHARED.rafId = 0;
213
+ return;
214
+ }
215
+ let anyWork = false;
216
+ for (const inst of SHARED.instances)if (inst.visible && (!inst.paused || !inst.everCopied)) {
217
+ anyWork = true;
218
+ break;
219
+ }
220
+ if (!anyWork) {
221
+ SHARED.rafId = 0;
222
+ return;
223
+ }
224
+ SHARED.rafId = requestAnimationFrame(tick);
225
+ if (now - lastFrameMs < FRAME_INTERVAL_MS) return;
226
+ lastFrameMs = now;
227
+ for (const inst of SHARED.instances)if (inst.visible) {
228
+ if (!inst.paused || !inst.everCopied) {
229
+ renderSharedFrame(now, inst.presetName, inst.presetTheme);
230
+ copyShaderToInstance(inst);
231
+ inst.everCopied = true;
232
+ if (_glowCallback && inst.glowEnabled && !inst.paused && SHARED.frameCount % GLOW_SKIP_FRAMES === 0) {
233
+ refreshGlowPixels();
234
+ _glowCallback(inst, now);
235
+ }
236
+ }
237
+ }
238
+ }
239
+ function startSharedLoop() {
240
+ if (!SHARED || 0 !== SHARED.rafId) return;
241
+ SHARED.rafId = requestAnimationFrame(tick);
242
+ }
243
+ function stopSharedLoop() {
244
+ if (!SHARED) return;
245
+ if (0 !== SHARED.rafId) cancelAnimationFrame(SHARED.rafId);
246
+ SHARED.rafId = 0;
247
+ }
248
+ export { createInstance, destroyInstance, getSharedFrameCount, pauseShared, registerGlowInstance, resumeShared, setGlowCallback, setInstanceVisible, unregisterGlowInstance, updateInstance };
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Pixel readback and luminance/colour sampling from the shared GL canvas.
3
+ *
4
+ * All glow luminance/color sampling reads from a shared pixel buffer
5
+ * (SHARED.glowPixels). The buffer is refreshed via gl.readPixels at most
6
+ * every GLOW_READBACK_INTERVAL_MS to avoid the expensive GPU→CPU pipeline
7
+ * flush on every frame. The plasma shader evolves slowly so 200ms-stale
8
+ * data is visually indistinguishable.
9
+ */
10
+ import { type MetalFxInstance, type ShaderRGB } from "./core";
11
+ export declare function refreshGlowPixels(): void;
12
+ export declare function sampleShaderLumAt(inst: MetalFxInstance, cssPxX: number, cssPxY: number, radius: number): number;
13
+ export declare function sampleShaderRGBAt(inst: MetalFxInstance, cssPxX: number, cssPxY: number, radius: number): ShaderRGB;
14
+ export declare function sampleShaderRGBChromatic(inst: MetalFxInstance, cssPxX: number, cssPxY: number, radius: number): ShaderRGB;
@@ -0,0 +1,145 @@
1
+ import { CANONICAL_PILL_H, CANONICAL_PILL_W, SHARED } from "./core.js";
2
+ function refreshGlowPixels() {
3
+ if (!SHARED) return;
4
+ const { gl, glCanvas } = SHARED;
5
+ const cw = glCanvas.width;
6
+ const ch = glCanvas.height;
7
+ if (SHARED.glowPixelsW !== cw || SHARED.glowPixelsH !== ch) {
8
+ SHARED.glowPixelsW = cw;
9
+ SHARED.glowPixelsH = ch;
10
+ SHARED.glowPixels = new Uint8Array(cw * ch * 4);
11
+ }
12
+ gl.readPixels(0, 0, cw, ch, gl.RGBA, gl.UNSIGNED_BYTE, SHARED.glowPixels);
13
+ }
14
+ const _map = {
15
+ bx: 0,
16
+ by: 0
17
+ };
18
+ function mapToGlowBuf(inst, cssPxX, cssPxY) {
19
+ if (!SHARED) {
20
+ _map.bx = 0;
21
+ _map.by = 0;
22
+ return _map;
23
+ }
24
+ const { glCanvas } = SHARED;
25
+ const cw = glCanvas.width;
26
+ const ch = glCanvas.height;
27
+ const dpr = inst.dpr;
28
+ const dw = inst.cssWidth * dpr;
29
+ const dh = inst.cssHeight * dpr;
30
+ const bdW = CANONICAL_PILL_W * dpr;
31
+ const bdH = CANONICAL_PILL_H * dpr;
32
+ let srcW = cw / bdW * dw / inst.shaderScale;
33
+ let srcH = ch / bdH * dh / inst.shaderScale;
34
+ if (srcW > cw) srcW = cw;
35
+ if (srcH > ch) srcH = ch;
36
+ const sx = (cw - srcW) / 2;
37
+ const sy = (ch - srcH) / 2;
38
+ const glX = sx + cssPxX / inst.cssWidth * srcW;
39
+ const glY = sy + cssPxY / inst.cssHeight * srcH;
40
+ _map.bx = Math.round(glX);
41
+ _map.by = Math.round(ch - 1 - glY);
42
+ return _map;
43
+ }
44
+ const _sr = {
45
+ r: 0,
46
+ g: 0,
47
+ b: 0,
48
+ lum: 0,
49
+ count: 0
50
+ };
51
+ function sampleRegion(buf, W, H, bx, by, radius) {
52
+ const r = Math.max(1, 0 | radius);
53
+ const x0 = Math.max(0, bx - r);
54
+ const x1 = Math.min(W, bx + r + 1);
55
+ const y0 = Math.max(0, by - r);
56
+ const y1 = Math.min(H, by + r + 1);
57
+ _sr.r = 0;
58
+ _sr.g = 0;
59
+ _sr.b = 0;
60
+ _sr.lum = 0;
61
+ _sr.count = 0;
62
+ for(let py = y0; py < y1; py++){
63
+ const row = py * W;
64
+ for(let px = x0; px < x1; px++){
65
+ const i = (row + px) * 4;
66
+ _sr.r += buf[i];
67
+ _sr.g += buf[i + 1];
68
+ _sr.b += buf[i + 2];
69
+ _sr.lum += (0.2126 * buf[i] + 0.7152 * buf[i + 1] + 0.0722 * buf[i + 2]) / 255;
70
+ _sr.count++;
71
+ }
72
+ }
73
+ return _sr;
74
+ }
75
+ const _rgb = {
76
+ r: 255,
77
+ g: 255,
78
+ b: 255
79
+ };
80
+ function sampleShaderLumAt(inst, cssPxX, cssPxY, radius) {
81
+ if (!SHARED) return 0;
82
+ const m = mapToGlowBuf(inst, cssPxX, cssPxY);
83
+ const s = sampleRegion(SHARED.glowPixels, SHARED.glowPixelsW, SHARED.glowPixelsH, m.bx, m.by, radius);
84
+ return s.count > 0 ? s.lum / s.count : 0;
85
+ }
86
+ function sampleShaderRGBAt(inst, cssPxX, cssPxY, radius) {
87
+ if (!SHARED) {
88
+ _rgb.r = 255;
89
+ _rgb.g = 255;
90
+ _rgb.b = 255;
91
+ return _rgb;
92
+ }
93
+ const m = mapToGlowBuf(inst, cssPxX, cssPxY);
94
+ const s = sampleRegion(SHARED.glowPixels, SHARED.glowPixelsW, SHARED.glowPixelsH, m.bx, m.by, radius);
95
+ if (0 === s.count) {
96
+ _rgb.r = 255;
97
+ _rgb.g = 255;
98
+ _rgb.b = 255;
99
+ return _rgb;
100
+ }
101
+ _rgb.r = s.r / s.count;
102
+ _rgb.g = s.g / s.count;
103
+ _rgb.b = s.b / s.count;
104
+ return _rgb;
105
+ }
106
+ function sampleShaderRGBChromatic(inst, cssPxX, cssPxY, radius) {
107
+ if (!SHARED) {
108
+ _rgb.r = 255;
109
+ _rgb.g = 255;
110
+ _rgb.b = 255;
111
+ return _rgb;
112
+ }
113
+ const m = mapToGlowBuf(inst, cssPxX, cssPxY);
114
+ const { glowPixels: buf, glowPixelsW: W, glowPixelsH: H } = SHARED;
115
+ const r = Math.max(1, 0 | radius);
116
+ const x0 = Math.max(0, m.bx - r);
117
+ const x1 = Math.min(W, m.bx + r + 1);
118
+ const y0 = Math.max(0, m.by - r);
119
+ const y1 = Math.min(H, m.by + r + 1);
120
+ let bestScore = -1;
121
+ _rgb.r = 255;
122
+ _rgb.g = 255;
123
+ _rgb.b = 255;
124
+ for(let py = y0; py < y1; py++){
125
+ const row = py * W;
126
+ for(let px = x0; px < x1; px++){
127
+ const i = (row + px) * 4;
128
+ const rr = buf[i];
129
+ const gg = buf[i + 1];
130
+ const bb = buf[i + 2];
131
+ const maxC = Math.max(rr, gg, bb);
132
+ const minC = Math.min(rr, gg, bb);
133
+ const sat = maxC > 0 ? (maxC - minC) / maxC : 0;
134
+ const score = sat * (0.35 + maxC / 255 * 0.65);
135
+ if (score > bestScore) {
136
+ bestScore = score;
137
+ _rgb.r = rr;
138
+ _rgb.g = gg;
139
+ _rgb.b = bb;
140
+ }
141
+ }
142
+ }
143
+ return _rgb;
144
+ }
145
+ export { refreshGlowPixels, sampleShaderLumAt, sampleShaderRGBAt, sampleShaderRGBChromatic };
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Vertex + fragment shader for the metal-fx effect.
3
+ *
4
+ * Source-of-truth: the `FRAG_SRC` block at L3626–4179 of the canonical
5
+ * `Image loader/index.html` engine. The chromatic / silver / gold presets all
6
+ * run `effectIndex: 1` (Plasma), so we ship ONLY that branch — the original
7
+ * carries 24 effects plus a dot-mode raster grid that this library does not
8
+ * expose. Everything else (warp, snoise, fbm, palette, paletteAlpha, vignette,
9
+ * gamma) is preserved character-for-character so the visible output matches
10
+ * `metal.html` 1:1.
11
+ *
12
+ * Uniforms:
13
+ * u_resolution vec2 — destination pixel buffer (DPR-scaled)
14
+ * u_time float — seconds since boot, JS-side multiplied by speed
15
+ * u_color1..u_color5 vec3 — palette stops (effect 1 uses 5; uniforms 6/7 are
16
+ * still uploaded for forward-compat with effect 24)
17
+ * u_color6, u_color7 vec3 — extra stops, unused at effect 1
18
+ * u_alpha1..u_alpha7 float
19
+ * u_intensity float — amplitude of the wave field
20
+ * u_scale float — noise zoom (smaller = chunkier features)
21
+ * u_direction float — drift angle (radians)
22
+ * u_softness float — kept for shader parity (effect 1 ignores)
23
+ * u_distortion float — warp strength on the sin band field
24
+ * u_complexity float — fbm octaves + frequency multiplier
25
+ * u_shape float — kept for shader parity (effect 1 ignores)
26
+ * u_vignette float — vignette range (0..1)
27
+ * u_vigOpacity float — vignette darkening strength (0..1)
28
+ * u_blur float — sample-radius for the 9-tap blur (0..1)
29
+ * u_shaderOpacity float — final alpha multiplier (0..1)
30
+ */
31
+ export declare const VERT_SHADER_SRC = "\n attribute vec2 a_position;\n void main() { gl_Position = vec4(a_position, 0.0, 1.0); }\n";
32
+ export declare const FRAG_SHADER_SRC = "\n precision highp float;\n\n uniform vec2 u_resolution;\n uniform float u_time;\n uniform vec3 u_color1, u_color2, u_color3, u_color4, u_color5, u_color6, u_color7;\n uniform float u_alpha1, u_alpha2, u_alpha3, u_alpha4, u_alpha5, u_alpha6, u_alpha7;\n uniform float u_intensity, u_scale, u_direction;\n uniform float u_softness, u_distortion, u_complexity, u_shape;\n uniform float u_vignette, u_vigOpacity, u_blur, u_shaderOpacity;\n\n vec3 mod289(vec3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }\n vec2 mod289v2(vec2 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }\n vec3 permute(vec3 x) { return mod289((x * 34.0 + 1.0) * x); }\n\n float snoise(vec2 v) {\n const vec4 C = vec4(0.211324865405187, 0.366025403784439,\n -0.577350269189626, 0.024390243902439);\n vec2 i = floor(v + dot(v, C.yy));\n vec2 x0 = v - i + dot(i, C.xx);\n vec2 i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);\n vec4 x12 = x0.xyxy + C.xxzz;\n x12.xy -= i1;\n i = mod289v2(i);\n vec3 p = permute(permute(i.y + vec3(0.0, i1.y, 1.0)) + i.x + vec3(0.0, i1.x, 1.0));\n vec3 m = max(0.5 - vec3(dot(x0, x0), dot(x12.xy, x12.xy), dot(x12.zw, x12.zw)), 0.0);\n m = m * m; m = m * m;\n vec3 x_ = 2.0 * fract(p * C.www) - 1.0;\n vec3 h = abs(x_) - 0.5;\n vec3 ox = floor(x_ + 0.5);\n vec3 a0 = x_ - ox;\n m *= 1.79284291400159 - 0.85373472095314 * (a0 * a0 + h * h);\n vec3 g;\n g.x = a0.x * x0.x + h.x * x0.y;\n g.yz = a0.yz * x12.xz + h.yz * x12.yw;\n return 130.0 * dot(m, g);\n }\n\n float fbm(vec2 p, float oct) {\n float val = 0.0, amp = 0.5;\n int n = int(oct);\n for (int i = 0; i < 7; i++) {\n if (i >= n) break;\n val += amp * snoise(p);\n p *= 2.0;\n amp *= 0.5;\n }\n return val;\n }\n\n float nfbm(vec2 p) { return fbm(p, 3.0 + u_complexity * 4.0); }\n\n /* 5-stop palette used by effect 1 (Plasma) \u2014 direct port of `palette` from\n * the canonical engine. Stops at t = 0, 0.25, 0.5, 0.75, 1.0. */\n vec3 palette(float t) {\n t = clamp(t, 0.0, 1.0);\n t = t * t * (3.0 - 2.0 * t);\n float k = 64.0;\n float w1 = u_alpha1 * exp(-k * t * t);\n float w2 = u_alpha2 * exp(-k * (t - 0.25) * (t - 0.25));\n float w3 = u_alpha3 * exp(-k * (t - 0.5) * (t - 0.5));\n float w4 = u_alpha4 * exp(-k * (t - 0.75) * (t - 0.75));\n float w5 = u_alpha5 * exp(-k * (t - 1.0) * (t - 1.0));\n float total = w1 + w2 + w3 + w4 + w5 + 0.0001;\n return (u_color1 * w1 + u_color2 * w2 + u_color3 * w3 +\n u_color4 * w4 + u_color5 * w5) / total;\n }\n\n /* Per-pixel alpha that re-introduces transparency when the user dials any\n * palette stop's alpha below 1. Same `paletteAlpha` from the canonical\n * engine. With every preset shipping all-1 alphas, this returns ~1 for every\n * pixel \u2014 but mirroring it keeps custom-preset behaviour identical. */\n float paletteAlpha(float t) {\n t = clamp(t, 0.0, 1.0);\n t = t * t * (3.0 - 2.0 * t);\n float k = 64.0;\n float w1 = u_alpha1 * exp(-k * t * t);\n float w2 = u_alpha2 * exp(-k * (t - 0.25) * (t - 0.25));\n float w3 = u_alpha3 * exp(-k * (t - 0.5) * (t - 0.5));\n float w4 = u_alpha4 * exp(-k * (t - 0.75) * (t - 0.75));\n float w5 = u_alpha5 * exp(-k * (t - 1.0) * (t - 1.0));\n float totalW = w1 + w2 + w3 + w4 + w5 + 0.0001;\n float rawW = exp(-k * t * t)\n + exp(-k * (t - 0.25) * (t - 0.25))\n + exp(-k * (t - 0.5) * (t - 0.5))\n + exp(-k * (t - 0.75) * (t - 0.75))\n + exp(-k * (t - 1.0) * (t - 1.0))\n + 0.0001;\n return totalW / rawW;\n }\n\n vec2 warp(vec2 p, float t) {\n float str = u_distortion * 2.0;\n return vec2(\n nfbm(p + vec2(t * 0.1, 0.0)),\n nfbm(p + vec2(0.0, t * 0.12) + 5.0)\n ) * str;\n }\n\n /* Plasma: four sine bands warped by an FBM field, mapped through the\n * 5-stop palette. Identical to effect 1 in the canonical engine. */\n vec3 computeEffect(vec2 uv, float aspect, float t, float dist, float cpx) {\n vec2 p = (uv - 0.5) * u_scale;\n p.x *= aspect;\n p += vec2(cos(u_direction), sin(u_direction)) * t * 0.15;\n\n float freq = 3.0 + cpx * 8.0;\n float val = 0.0;\n val += sin(p.x * freq + t);\n val += sin(p.y * freq + t * 1.3);\n val += sin((p.x + p.y) * freq * 0.7 + t * 0.7);\n val += sin(length(p) * freq * 0.8 - t * 1.5);\n vec2 w = warp(p, t);\n val += (w.x + w.y) * dist;\n val = val * 0.2 * u_intensity + 0.5;\n\n return palette(clamp(val, 0.0, 1.0));\n }\n\n void main() {\n vec2 uv = gl_FragCoord.xy / u_resolution;\n float aspect = u_resolution.x / u_resolution.y;\n float t = u_time; // JS already multiplied u_time by preset.speed.\n float dist = u_distortion;\n float cpx = u_complexity;\n\n /* 5-tap cross blur (center + cardinal offsets). The chromatic/silver/gold\n * presets all ship with blur=1 so this path is always active. 5 taps\n * instead of the canonical engine's 9 saves ~44% fragment work; the\n * perceptual difference is nil because the output is already soft from\n * the plasma's low spatial frequency and CSS blur on reflections. */\n vec3 col;\n if (u_blur < 0.01) {\n col = computeEffect(uv, aspect, t, dist, cpx);\n } else {\n float r = u_blur * 0.02;\n col = computeEffect(uv, aspect, t, dist, cpx) * 0.4;\n col += computeEffect(uv + vec2( r, 0.0), aspect, t, dist, cpx) * 0.15;\n col += computeEffect(uv + vec2(-r, 0.0), aspect, t, dist, cpx) * 0.15;\n col += computeEffect(uv + vec2(0.0, r), aspect, t, dist, cpx) * 0.15;\n col += computeEffect(uv + vec2(0.0, -r), aspect, t, dist, cpx) * 0.15;\n }\n\n /* Gamma punch \u2014 adds the contrast pop that defines the chromatic\n * highlights. From the canonical engine: `col = pow(col, vec3(1.3))`. */\n col = pow(col, vec3(1.3));\n\n /* Vignette \u2014 soft edge darkening so corners read as recessed. The 40-px\n * scale at the bottom of the formula is hard-coded in the canonical\n * engine; we keep it for visual parity. */\n float edgeDist = min(min(uv.x, 1.0 - uv.x), min(uv.y, 1.0 - uv.y));\n float vigPx = 40.0 / min(u_resolution.x, u_resolution.y);\n float vigRange = vigPx * (1.0 + u_vignette * 3.0);\n float vig = edgeDist * edgeDist / (vigRange * vigRange);\n vig = smoothstep(0.0, 1.0, vig);\n col *= mix(1.0, vig, u_vignette * u_vigOpacity);\n\n /* Per-pixel alpha. With all-1 alphas the formula collapses to ~1 but the\n * computation matches the canonical engine so custom presets behave the\n * same. */\n float colorAlpha = (u_alpha1 + u_alpha2 + u_alpha3 + u_alpha4 + u_alpha5) / 5.0;\n if (colorAlpha < 0.999) {\n vec3 c1d = col - u_color1, c2d = col - u_color2, c3d = col - u_color3,\n c4d = col - u_color4, c5d = col - u_color5;\n float prox1 = exp(-8.0 * dot(c1d, c1d));\n float prox2 = exp(-8.0 * dot(c2d, c2d));\n float prox3 = exp(-8.0 * dot(c3d, c3d));\n float prox4 = exp(-8.0 * dot(c4d, c4d));\n float prox5 = exp(-8.0 * dot(c5d, c5d));\n float pTotal = prox1 + prox2 + prox3 + prox4 + prox5 + 0.0001;\n colorAlpha = (prox1 * u_alpha1 + prox2 * u_alpha2 + prox3 * u_alpha3 +\n prox4 * u_alpha4 + prox5 * u_alpha5) / pTotal;\n }\n float alpha = colorAlpha;\n\n /* Touch the unused-at-effect-1 uniforms so GL drivers that complain about\n * declared-but-unread uniforms (some Mali / Adreno builds do) keep them\n * live. The contribution is provably zero. */\n alpha += 0.0 * (u_softness + u_shape +\n u_alpha6 + u_alpha7 +\n u_color6.x + u_color7.x);\n\n gl_FragColor = vec4(col, alpha * u_shaderOpacity);\n }\n";
33
+ /** Compile a single shader stage. Throws with the GL info log on failure. */
34
+ export declare function compileShader(gl: WebGLRenderingContext, type: number, source: string): WebGLShader;
35
+ /** Link a vertex + fragment shader pair into a complete program. */
36
+ export declare function linkProgram(gl: WebGLRenderingContext, vert: WebGLShader, frag: WebGLShader): WebGLProgram;