PluginProbe
Extendify / 3.2.1
Extendify v3.2.1
3.2.1 3.2.0 3.1.6 3.1.5 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.6 3.0.5 3.0.4 trunk 0.1.0 0.10.0 0.10.1 0.10.2 0.11.0 0.11.1 0.2.0 0.3.0 0.3.1 0.4.0 0.5.0 0.6.0 All 127 releases
extendify / src / AutoLaunch / components / ShaderBackground.jsx

ShaderBackground.jsx in Extendify 3.2.1, at src/AutoLaunch/components/ShaderBackground.jsx

106 lines 2.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import {
2 createShaderCanvas,
3 DEFAULT_SHADER,
4 } from '@auto-launch/functions/shader-canvas';
5 import { derivedShaderColors } from '@auto-launch/functions/shader-colors';
6 import { BG_SOURCE_ATTR } from '@auto-launch/functions/tokens';
7 import { useEffect, useRef, useState } from '@wordpress/element';
8 import { colord } from 'colord';
9 import { useReducedMotion } from 'framer-motion';
10
11 // The resolved tokens sit on the wrapper, not :root, so read from inside it.
12 const readVar = (node, name) =>
13 getComputedStyle(node).getPropertyValue(name).trim();
14
15 const readSource = (node) =>
16 node.closest(`[${BG_SOURCE_ATTR}]`)?.getAttribute(BG_SOURCE_ATTR) ||
17 DEFAULT_SHADER;
18
19 const toTriple = (value) => {
20 const { r, g, b } = colord(value).toRgb();
21 return [r / 255, g / 255, b / 255];
22 };
23
24 const derivedColors = (node) =>
25 derivedShaderColors(
26 readVar(node, '--color-ui-page') || '#2271b1',
27 readVar(node, '--color-ui-action') || '#2271b1',
28 );
29
30 const numberVar = (node, name, fallback) => {
31 const raw = readVar(node, name);
32 if (!raw) return fallback;
33 const value = Number.parseFloat(raw);
34 return Number.isNaN(value) ? fallback : value;
35 };
36
37 export const ShaderBackground = ({ still = false }) => {
38 const canvasRef = useRef(null);
39 const engineRef = useRef(null);
40 const shouldReduceMotion = useReducedMotion();
41 const [tokens, setTokens] = useState(null);
42
43 useEffect(() => {
44 const node = canvasRef.current;
45 if (!node) return;
46 const read = () => {
47 const derived = derivedColors(node);
48 setTokens({
49 source: readSource(node),
50 speed: numberVar(node, '--ext-ui-bg-speed', 1),
51 scale: numberVar(node, '--ext-ui-bg-scale', 1),
52 intensity: numberVar(node, '--ext-ui-bg-intensity', 1),
53 offset: [
54 numberVar(node, '--ext-ui-bg-offset-x', 0),
55 numberVar(node, '--ext-ui-bg-offset-y', 0),
56 ],
57 colors: [
58 readVar(node, '--ext-ui-bg-color-1') || derived[0],
59 readVar(node, '--ext-ui-bg-color-2') || derived[1],
60 readVar(node, '--ext-ui-bg-color-3') || derived[2],
61 ],
62 });
63 };
64 read();
65 }, []);
66
67 useEffect(() => {
68 const engine = createShaderCanvas(canvasRef.current);
69 engineRef.current = engine;
70 return () => {
71 engine?.destroy();
72 engineRef.current = null;
73 };
74 }, []);
75
76 useEffect(() => {
77 const engine = engineRef.current;
78 if (!engine || !tokens) return;
79 // GLSL compiles per driver, so a design's own source can be rejected here.
80 if (engine.setSource(tokens.source)) return;
81 engine.setSource(DEFAULT_SHADER);
82 }, [tokens]);
83
84 useEffect(() => {
85 if (!tokens) return;
86 engineRef.current?.setValues({
87 speed: tokens.speed,
88 scale: tokens.scale,
89 intensity: tokens.intensity,
90 offset: tokens.offset,
91 colors: tokens.colors.map(toTriple),
92 });
93 }, [tokens]);
94
95 useEffect(() => {
96 engineRef.current?.setStill(still || Boolean(shouldReduceMotion));
97 }, [still, shouldReduceMotion]);
98
99 return (
100 <canvas
101 ref={canvasRef}
102 className="pointer-events-none absolute inset-0 h-full w-full"
103 />
104 );
105 };
106