Mirror: A frag-canvas custom element to apply Shadertoy fragment shaders to a canvas or image/video element
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Initial Commit

+895
+1
.gitignore
··· 1 + node_modules
+13
package.json
··· 1 + { 2 + "name": "frag-canvas-element", 3 + "sideEffects": true, 4 + "version": "0.1.0", 5 + "main": "index.js", 6 + "keywords": [], 7 + "author": "", 8 + "license": "ISC", 9 + "devDependencies": { 10 + "typescript": "^5.7.3", 11 + "vite": "^6.2.0" 12 + } 13 + }
+556
pnpm-lock.yaml
··· 1 + lockfileVersion: '9.0' 2 + 3 + settings: 4 + autoInstallPeers: true 5 + excludeLinksFromLockfile: false 6 + 7 + importers: 8 + 9 + .: 10 + devDependencies: 11 + typescript: 12 + specifier: ^5.7.3 13 + version: 5.7.3 14 + vite: 15 + specifier: ^6.2.0 16 + version: 6.2.0 17 + 18 + packages: 19 + 20 + '@esbuild/aix-ppc64@0.25.0': 21 + resolution: {integrity: sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==} 22 + engines: {node: '>=18'} 23 + cpu: [ppc64] 24 + os: [aix] 25 + 26 + '@esbuild/android-arm64@0.25.0': 27 + resolution: {integrity: sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g==} 28 + engines: {node: '>=18'} 29 + cpu: [arm64] 30 + os: [android] 31 + 32 + '@esbuild/android-arm@0.25.0': 33 + resolution: {integrity: sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g==} 34 + engines: {node: '>=18'} 35 + cpu: [arm] 36 + os: [android] 37 + 38 + '@esbuild/android-x64@0.25.0': 39 + resolution: {integrity: sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg==} 40 + engines: {node: '>=18'} 41 + cpu: [x64] 42 + os: [android] 43 + 44 + '@esbuild/darwin-arm64@0.25.0': 45 + resolution: {integrity: sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw==} 46 + engines: {node: '>=18'} 47 + cpu: [arm64] 48 + os: [darwin] 49 + 50 + '@esbuild/darwin-x64@0.25.0': 51 + resolution: {integrity: sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg==} 52 + engines: {node: '>=18'} 53 + cpu: [x64] 54 + os: [darwin] 55 + 56 + '@esbuild/freebsd-arm64@0.25.0': 57 + resolution: {integrity: sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w==} 58 + engines: {node: '>=18'} 59 + cpu: [arm64] 60 + os: [freebsd] 61 + 62 + '@esbuild/freebsd-x64@0.25.0': 63 + resolution: {integrity: sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A==} 64 + engines: {node: '>=18'} 65 + cpu: [x64] 66 + os: [freebsd] 67 + 68 + '@esbuild/linux-arm64@0.25.0': 69 + resolution: {integrity: sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==} 70 + engines: {node: '>=18'} 71 + cpu: [arm64] 72 + os: [linux] 73 + 74 + '@esbuild/linux-arm@0.25.0': 75 + resolution: {integrity: sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg==} 76 + engines: {node: '>=18'} 77 + cpu: [arm] 78 + os: [linux] 79 + 80 + '@esbuild/linux-ia32@0.25.0': 81 + resolution: {integrity: sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg==} 82 + engines: {node: '>=18'} 83 + cpu: [ia32] 84 + os: [linux] 85 + 86 + '@esbuild/linux-loong64@0.25.0': 87 + resolution: {integrity: sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw==} 88 + engines: {node: '>=18'} 89 + cpu: [loong64] 90 + os: [linux] 91 + 92 + '@esbuild/linux-mips64el@0.25.0': 93 + resolution: {integrity: sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ==} 94 + engines: {node: '>=18'} 95 + cpu: [mips64el] 96 + os: [linux] 97 + 98 + '@esbuild/linux-ppc64@0.25.0': 99 + resolution: {integrity: sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw==} 100 + engines: {node: '>=18'} 101 + cpu: [ppc64] 102 + os: [linux] 103 + 104 + '@esbuild/linux-riscv64@0.25.0': 105 + resolution: {integrity: sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA==} 106 + engines: {node: '>=18'} 107 + cpu: [riscv64] 108 + os: [linux] 109 + 110 + '@esbuild/linux-s390x@0.25.0': 111 + resolution: {integrity: sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA==} 112 + engines: {node: '>=18'} 113 + cpu: [s390x] 114 + os: [linux] 115 + 116 + '@esbuild/linux-x64@0.25.0': 117 + resolution: {integrity: sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw==} 118 + engines: {node: '>=18'} 119 + cpu: [x64] 120 + os: [linux] 121 + 122 + '@esbuild/netbsd-arm64@0.25.0': 123 + resolution: {integrity: sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw==} 124 + engines: {node: '>=18'} 125 + cpu: [arm64] 126 + os: [netbsd] 127 + 128 + '@esbuild/netbsd-x64@0.25.0': 129 + resolution: {integrity: sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA==} 130 + engines: {node: '>=18'} 131 + cpu: [x64] 132 + os: [netbsd] 133 + 134 + '@esbuild/openbsd-arm64@0.25.0': 135 + resolution: {integrity: sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw==} 136 + engines: {node: '>=18'} 137 + cpu: [arm64] 138 + os: [openbsd] 139 + 140 + '@esbuild/openbsd-x64@0.25.0': 141 + resolution: {integrity: sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg==} 142 + engines: {node: '>=18'} 143 + cpu: [x64] 144 + os: [openbsd] 145 + 146 + '@esbuild/sunos-x64@0.25.0': 147 + resolution: {integrity: sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg==} 148 + engines: {node: '>=18'} 149 + cpu: [x64] 150 + os: [sunos] 151 + 152 + '@esbuild/win32-arm64@0.25.0': 153 + resolution: {integrity: sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw==} 154 + engines: {node: '>=18'} 155 + cpu: [arm64] 156 + os: [win32] 157 + 158 + '@esbuild/win32-ia32@0.25.0': 159 + resolution: {integrity: sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA==} 160 + engines: {node: '>=18'} 161 + cpu: [ia32] 162 + os: [win32] 163 + 164 + '@esbuild/win32-x64@0.25.0': 165 + resolution: {integrity: sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ==} 166 + engines: {node: '>=18'} 167 + cpu: [x64] 168 + os: [win32] 169 + 170 + '@rollup/rollup-android-arm-eabi@4.34.8': 171 + resolution: {integrity: sha512-q217OSE8DTp8AFHuNHXo0Y86e1wtlfVrXiAlwkIvGRQv9zbc6mE3sjIVfwI8sYUyNxwOg0j/Vm1RKM04JcWLJw==} 172 + cpu: [arm] 173 + os: [android] 174 + 175 + '@rollup/rollup-android-arm64@4.34.8': 176 + resolution: {integrity: sha512-Gigjz7mNWaOL9wCggvoK3jEIUUbGul656opstjaUSGC3eT0BM7PofdAJaBfPFWWkXNVAXbaQtC99OCg4sJv70Q==} 177 + cpu: [arm64] 178 + os: [android] 179 + 180 + '@rollup/rollup-darwin-arm64@4.34.8': 181 + resolution: {integrity: sha512-02rVdZ5tgdUNRxIUrFdcMBZQoaPMrxtwSb+/hOfBdqkatYHR3lZ2A2EGyHq2sGOd0Owk80oV3snlDASC24He3Q==} 182 + cpu: [arm64] 183 + os: [darwin] 184 + 185 + '@rollup/rollup-darwin-x64@4.34.8': 186 + resolution: {integrity: sha512-qIP/elwR/tq/dYRx3lgwK31jkZvMiD6qUtOycLhTzCvrjbZ3LjQnEM9rNhSGpbLXVJYQ3rq39A6Re0h9tU2ynw==} 187 + cpu: [x64] 188 + os: [darwin] 189 + 190 + '@rollup/rollup-freebsd-arm64@4.34.8': 191 + resolution: {integrity: sha512-IQNVXL9iY6NniYbTaOKdrlVP3XIqazBgJOVkddzJlqnCpRi/yAeSOa8PLcECFSQochzqApIOE1GHNu3pCz+BDA==} 192 + cpu: [arm64] 193 + os: [freebsd] 194 + 195 + '@rollup/rollup-freebsd-x64@4.34.8': 196 + resolution: {integrity: sha512-TYXcHghgnCqYFiE3FT5QwXtOZqDj5GmaFNTNt3jNC+vh22dc/ukG2cG+pi75QO4kACohZzidsq7yKTKwq/Jq7Q==} 197 + cpu: [x64] 198 + os: [freebsd] 199 + 200 + '@rollup/rollup-linux-arm-gnueabihf@4.34.8': 201 + resolution: {integrity: sha512-A4iphFGNkWRd+5m3VIGuqHnG3MVnqKe7Al57u9mwgbyZ2/xF9Jio72MaY7xxh+Y87VAHmGQr73qoKL9HPbXj1g==} 202 + cpu: [arm] 203 + os: [linux] 204 + 205 + '@rollup/rollup-linux-arm-musleabihf@4.34.8': 206 + resolution: {integrity: sha512-S0lqKLfTm5u+QTxlFiAnb2J/2dgQqRy/XvziPtDd1rKZFXHTyYLoVL58M/XFwDI01AQCDIevGLbQrMAtdyanpA==} 207 + cpu: [arm] 208 + os: [linux] 209 + 210 + '@rollup/rollup-linux-arm64-gnu@4.34.8': 211 + resolution: {integrity: sha512-jpz9YOuPiSkL4G4pqKrus0pn9aYwpImGkosRKwNi+sJSkz+WU3anZe6hi73StLOQdfXYXC7hUfsQlTnjMd3s1A==} 212 + cpu: [arm64] 213 + os: [linux] 214 + 215 + '@rollup/rollup-linux-arm64-musl@4.34.8': 216 + resolution: {integrity: sha512-KdSfaROOUJXgTVxJNAZ3KwkRc5nggDk+06P6lgi1HLv1hskgvxHUKZ4xtwHkVYJ1Rep4GNo+uEfycCRRxht7+Q==} 217 + cpu: [arm64] 218 + os: [linux] 219 + 220 + '@rollup/rollup-linux-loongarch64-gnu@4.34.8': 221 + resolution: {integrity: sha512-NyF4gcxwkMFRjgXBM6g2lkT58OWztZvw5KkV2K0qqSnUEqCVcqdh2jN4gQrTn/YUpAcNKyFHfoOZEer9nwo6uQ==} 222 + cpu: [loong64] 223 + os: [linux] 224 + 225 + '@rollup/rollup-linux-powerpc64le-gnu@4.34.8': 226 + resolution: {integrity: sha512-LMJc999GkhGvktHU85zNTDImZVUCJ1z/MbAJTnviiWmmjyckP5aQsHtcujMjpNdMZPT2rQEDBlJfubhs3jsMfw==} 227 + cpu: [ppc64] 228 + os: [linux] 229 + 230 + '@rollup/rollup-linux-riscv64-gnu@4.34.8': 231 + resolution: {integrity: sha512-xAQCAHPj8nJq1PI3z8CIZzXuXCstquz7cIOL73HHdXiRcKk8Ywwqtx2wrIy23EcTn4aZ2fLJNBB8d0tQENPCmw==} 232 + cpu: [riscv64] 233 + os: [linux] 234 + 235 + '@rollup/rollup-linux-s390x-gnu@4.34.8': 236 + resolution: {integrity: sha512-DdePVk1NDEuc3fOe3dPPTb+rjMtuFw89gw6gVWxQFAuEqqSdDKnrwzZHrUYdac7A7dXl9Q2Vflxpme15gUWQFA==} 237 + cpu: [s390x] 238 + os: [linux] 239 + 240 + '@rollup/rollup-linux-x64-gnu@4.34.8': 241 + resolution: {integrity: sha512-8y7ED8gjxITUltTUEJLQdgpbPh1sUQ0kMTmufRF/Ns5tI9TNMNlhWtmPKKHCU0SilX+3MJkZ0zERYYGIVBYHIA==} 242 + cpu: [x64] 243 + os: [linux] 244 + 245 + '@rollup/rollup-linux-x64-musl@4.34.8': 246 + resolution: {integrity: sha512-SCXcP0ZpGFIe7Ge+McxY5zKxiEI5ra+GT3QRxL0pMMtxPfpyLAKleZODi1zdRHkz5/BhueUrYtYVgubqe9JBNQ==} 247 + cpu: [x64] 248 + os: [linux] 249 + 250 + '@rollup/rollup-win32-arm64-msvc@4.34.8': 251 + resolution: {integrity: sha512-YHYsgzZgFJzTRbth4h7Or0m5O74Yda+hLin0irAIobkLQFRQd1qWmnoVfwmKm9TXIZVAD0nZ+GEb2ICicLyCnQ==} 252 + cpu: [arm64] 253 + os: [win32] 254 + 255 + '@rollup/rollup-win32-ia32-msvc@4.34.8': 256 + resolution: {integrity: sha512-r3NRQrXkHr4uWy5TOjTpTYojR9XmF0j/RYgKCef+Ag46FWUTltm5ziticv8LdNsDMehjJ543x/+TJAek/xBA2w==} 257 + cpu: [ia32] 258 + os: [win32] 259 + 260 + '@rollup/rollup-win32-x64-msvc@4.34.8': 261 + resolution: {integrity: sha512-U0FaE5O1BCpZSeE6gBl3c5ObhePQSfk9vDRToMmTkbhCOgW4jqvtS5LGyQ76L1fH8sM0keRp4uDTsbjiUyjk0g==} 262 + cpu: [x64] 263 + os: [win32] 264 + 265 + '@types/estree@1.0.6': 266 + resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} 267 + 268 + esbuild@0.25.0: 269 + resolution: {integrity: sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==} 270 + engines: {node: '>=18'} 271 + hasBin: true 272 + 273 + fsevents@2.3.3: 274 + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} 275 + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 276 + os: [darwin] 277 + 278 + nanoid@3.3.8: 279 + resolution: {integrity: sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==} 280 + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} 281 + hasBin: true 282 + 283 + picocolors@1.1.1: 284 + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} 285 + 286 + postcss@8.5.3: 287 + resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==} 288 + engines: {node: ^10 || ^12 || >=14} 289 + 290 + rollup@4.34.8: 291 + resolution: {integrity: sha512-489gTVMzAYdiZHFVA/ig/iYFllCcWFHMvUHI1rpFmkoUtRlQxqh6/yiNqnYibjMZ2b/+FUQwldG+aLsEt6bglQ==} 292 + engines: {node: '>=18.0.0', npm: '>=8.0.0'} 293 + hasBin: true 294 + 295 + source-map-js@1.2.1: 296 + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} 297 + engines: {node: '>=0.10.0'} 298 + 299 + typescript@5.7.3: 300 + resolution: {integrity: sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==} 301 + engines: {node: '>=14.17'} 302 + hasBin: true 303 + 304 + vite@6.2.0: 305 + resolution: {integrity: sha512-7dPxoo+WsT/64rDcwoOjk76XHj+TqNTIvHKcuMQ1k4/SeHDaQt5GFAeLYzrimZrMpn/O6DtdI03WUjdxuPM0oQ==} 306 + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} 307 + hasBin: true 308 + peerDependencies: 309 + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 310 + jiti: '>=1.21.0' 311 + less: '*' 312 + lightningcss: ^1.21.0 313 + sass: '*' 314 + sass-embedded: '*' 315 + stylus: '*' 316 + sugarss: '*' 317 + terser: ^5.16.0 318 + tsx: ^4.8.1 319 + yaml: ^2.4.2 320 + peerDependenciesMeta: 321 + '@types/node': 322 + optional: true 323 + jiti: 324 + optional: true 325 + less: 326 + optional: true 327 + lightningcss: 328 + optional: true 329 + sass: 330 + optional: true 331 + sass-embedded: 332 + optional: true 333 + stylus: 334 + optional: true 335 + sugarss: 336 + optional: true 337 + terser: 338 + optional: true 339 + tsx: 340 + optional: true 341 + yaml: 342 + optional: true 343 + 344 + snapshots: 345 + 346 + '@esbuild/aix-ppc64@0.25.0': 347 + optional: true 348 + 349 + '@esbuild/android-arm64@0.25.0': 350 + optional: true 351 + 352 + '@esbuild/android-arm@0.25.0': 353 + optional: true 354 + 355 + '@esbuild/android-x64@0.25.0': 356 + optional: true 357 + 358 + '@esbuild/darwin-arm64@0.25.0': 359 + optional: true 360 + 361 + '@esbuild/darwin-x64@0.25.0': 362 + optional: true 363 + 364 + '@esbuild/freebsd-arm64@0.25.0': 365 + optional: true 366 + 367 + '@esbuild/freebsd-x64@0.25.0': 368 + optional: true 369 + 370 + '@esbuild/linux-arm64@0.25.0': 371 + optional: true 372 + 373 + '@esbuild/linux-arm@0.25.0': 374 + optional: true 375 + 376 + '@esbuild/linux-ia32@0.25.0': 377 + optional: true 378 + 379 + '@esbuild/linux-loong64@0.25.0': 380 + optional: true 381 + 382 + '@esbuild/linux-mips64el@0.25.0': 383 + optional: true 384 + 385 + '@esbuild/linux-ppc64@0.25.0': 386 + optional: true 387 + 388 + '@esbuild/linux-riscv64@0.25.0': 389 + optional: true 390 + 391 + '@esbuild/linux-s390x@0.25.0': 392 + optional: true 393 + 394 + '@esbuild/linux-x64@0.25.0': 395 + optional: true 396 + 397 + '@esbuild/netbsd-arm64@0.25.0': 398 + optional: true 399 + 400 + '@esbuild/netbsd-x64@0.25.0': 401 + optional: true 402 + 403 + '@esbuild/openbsd-arm64@0.25.0': 404 + optional: true 405 + 406 + '@esbuild/openbsd-x64@0.25.0': 407 + optional: true 408 + 409 + '@esbuild/sunos-x64@0.25.0': 410 + optional: true 411 + 412 + '@esbuild/win32-arm64@0.25.0': 413 + optional: true 414 + 415 + '@esbuild/win32-ia32@0.25.0': 416 + optional: true 417 + 418 + '@esbuild/win32-x64@0.25.0': 419 + optional: true 420 + 421 + '@rollup/rollup-android-arm-eabi@4.34.8': 422 + optional: true 423 + 424 + '@rollup/rollup-android-arm64@4.34.8': 425 + optional: true 426 + 427 + '@rollup/rollup-darwin-arm64@4.34.8': 428 + optional: true 429 + 430 + '@rollup/rollup-darwin-x64@4.34.8': 431 + optional: true 432 + 433 + '@rollup/rollup-freebsd-arm64@4.34.8': 434 + optional: true 435 + 436 + '@rollup/rollup-freebsd-x64@4.34.8': 437 + optional: true 438 + 439 + '@rollup/rollup-linux-arm-gnueabihf@4.34.8': 440 + optional: true 441 + 442 + '@rollup/rollup-linux-arm-musleabihf@4.34.8': 443 + optional: true 444 + 445 + '@rollup/rollup-linux-arm64-gnu@4.34.8': 446 + optional: true 447 + 448 + '@rollup/rollup-linux-arm64-musl@4.34.8': 449 + optional: true 450 + 451 + '@rollup/rollup-linux-loongarch64-gnu@4.34.8': 452 + optional: true 453 + 454 + '@rollup/rollup-linux-powerpc64le-gnu@4.34.8': 455 + optional: true 456 + 457 + '@rollup/rollup-linux-riscv64-gnu@4.34.8': 458 + optional: true 459 + 460 + '@rollup/rollup-linux-s390x-gnu@4.34.8': 461 + optional: true 462 + 463 + '@rollup/rollup-linux-x64-gnu@4.34.8': 464 + optional: true 465 + 466 + '@rollup/rollup-linux-x64-musl@4.34.8': 467 + optional: true 468 + 469 + '@rollup/rollup-win32-arm64-msvc@4.34.8': 470 + optional: true 471 + 472 + '@rollup/rollup-win32-ia32-msvc@4.34.8': 473 + optional: true 474 + 475 + '@rollup/rollup-win32-x64-msvc@4.34.8': 476 + optional: true 477 + 478 + '@types/estree@1.0.6': {} 479 + 480 + esbuild@0.25.0: 481 + optionalDependencies: 482 + '@esbuild/aix-ppc64': 0.25.0 483 + '@esbuild/android-arm': 0.25.0 484 + '@esbuild/android-arm64': 0.25.0 485 + '@esbuild/android-x64': 0.25.0 486 + '@esbuild/darwin-arm64': 0.25.0 487 + '@esbuild/darwin-x64': 0.25.0 488 + '@esbuild/freebsd-arm64': 0.25.0 489 + '@esbuild/freebsd-x64': 0.25.0 490 + '@esbuild/linux-arm': 0.25.0 491 + '@esbuild/linux-arm64': 0.25.0 492 + '@esbuild/linux-ia32': 0.25.0 493 + '@esbuild/linux-loong64': 0.25.0 494 + '@esbuild/linux-mips64el': 0.25.0 495 + '@esbuild/linux-ppc64': 0.25.0 496 + '@esbuild/linux-riscv64': 0.25.0 497 + '@esbuild/linux-s390x': 0.25.0 498 + '@esbuild/linux-x64': 0.25.0 499 + '@esbuild/netbsd-arm64': 0.25.0 500 + '@esbuild/netbsd-x64': 0.25.0 501 + '@esbuild/openbsd-arm64': 0.25.0 502 + '@esbuild/openbsd-x64': 0.25.0 503 + '@esbuild/sunos-x64': 0.25.0 504 + '@esbuild/win32-arm64': 0.25.0 505 + '@esbuild/win32-ia32': 0.25.0 506 + '@esbuild/win32-x64': 0.25.0 507 + 508 + fsevents@2.3.3: 509 + optional: true 510 + 511 + nanoid@3.3.8: {} 512 + 513 + picocolors@1.1.1: {} 514 + 515 + postcss@8.5.3: 516 + dependencies: 517 + nanoid: 3.3.8 518 + picocolors: 1.1.1 519 + source-map-js: 1.2.1 520 + 521 + rollup@4.34.8: 522 + dependencies: 523 + '@types/estree': 1.0.6 524 + optionalDependencies: 525 + '@rollup/rollup-android-arm-eabi': 4.34.8 526 + '@rollup/rollup-android-arm64': 4.34.8 527 + '@rollup/rollup-darwin-arm64': 4.34.8 528 + '@rollup/rollup-darwin-x64': 4.34.8 529 + '@rollup/rollup-freebsd-arm64': 4.34.8 530 + '@rollup/rollup-freebsd-x64': 4.34.8 531 + '@rollup/rollup-linux-arm-gnueabihf': 4.34.8 532 + '@rollup/rollup-linux-arm-musleabihf': 4.34.8 533 + '@rollup/rollup-linux-arm64-gnu': 4.34.8 534 + '@rollup/rollup-linux-arm64-musl': 4.34.8 535 + '@rollup/rollup-linux-loongarch64-gnu': 4.34.8 536 + '@rollup/rollup-linux-powerpc64le-gnu': 4.34.8 537 + '@rollup/rollup-linux-riscv64-gnu': 4.34.8 538 + '@rollup/rollup-linux-s390x-gnu': 4.34.8 539 + '@rollup/rollup-linux-x64-gnu': 4.34.8 540 + '@rollup/rollup-linux-x64-musl': 4.34.8 541 + '@rollup/rollup-win32-arm64-msvc': 4.34.8 542 + '@rollup/rollup-win32-ia32-msvc': 4.34.8 543 + '@rollup/rollup-win32-x64-msvc': 4.34.8 544 + fsevents: 2.3.3 545 + 546 + source-map-js@1.2.1: {} 547 + 548 + typescript@5.7.3: {} 549 + 550 + vite@6.2.0: 551 + dependencies: 552 + esbuild: 0.25.0 553 + postcss: 8.5.3 554 + rollup: 4.34.8 555 + optionalDependencies: 556 + fsevents: 2.3.3
+324
src/frag-canvas-element.ts
··· 1 + const VS_SOURCE_100 = 2 + 'attribute vec2 vPos;\n' 3 + + 'void main() {\n' 4 + + ' gl_Position = vec4(vPos, 0.0, 1.0);\n' 5 + + '}'; 6 + const VS_SOURCE_300 = 7 + '#version 300 es\n' 8 + + 'in vec4 vPos;\n' 9 + + 'void main() {\n' 10 + + ' gl_Position = vPos;\n' 11 + + '}'; 12 + 13 + const makeDateVector = () => { 14 + const DATE = new Date(); 15 + const year = DATE.getFullYear(); 16 + const month = DATE.getMonth() + 1; 17 + const day = DATE.getDate(); 18 + const time = DATE.getHours() * 60 * 60 + DATE.getMinutes() * 60 + DATE.getSeconds() + DATE.getMilliseconds() * 0.001; 19 + return [year, month, day, time] as const; 20 + }; 21 + 22 + interface InitState { 23 + width: number; 24 + height: number; 25 + fragSource: string; 26 + } 27 + 28 + function createState(gl: WebGL2RenderingContext, init: InitState) { 29 + const program = gl.createProgram(); 30 + 31 + const vertShader300 = gl.createShader(gl.VERTEX_SHADER); 32 + const vertShader100 = gl.createShader(gl.VERTEX_SHADER); 33 + 34 + const fragShader = gl.createShader(gl.FRAGMENT_SHADER); 35 + if (!vertShader100 || !vertShader300 || !fragShader) { 36 + return null; 37 + } 38 + 39 + gl.viewport(0, 0, gl.canvas.width, gl.canvas.height); 40 + 41 + gl.shaderSource(vertShader100, VS_SOURCE_100); 42 + gl.compileShader(vertShader100); 43 + gl.shaderSource(vertShader300, VS_SOURCE_300); 44 + gl.compileShader(vertShader300); 45 + 46 + const screenVertex = new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]); 47 + const vertexBuffer = gl.createBuffer(); 48 + gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); 49 + gl.bufferData(gl.ARRAY_BUFFER, screenVertex, gl.STATIC_DRAW); 50 + 51 + const texture = gl.createTexture(); 52 + gl.activeTexture(gl['TEXTURE0']); 53 + gl.bindTexture(gl.TEXTURE_2D, texture); 54 + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); 55 + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); 56 + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); 57 + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); 58 + 59 + let width = init.width; 60 + let height = init.height; 61 + 62 + let vertexPos: GLint = 0; 63 + let iResolution: WebGLUniformLocation | null = null; 64 + let iChannelResolution: WebGLUniformLocation | null = null; 65 + let iTime: WebGLUniformLocation | null = null; 66 + let iTimeDelta: WebGLUniformLocation | null = null; 67 + let iFrame: WebGLUniformLocation | null = null; 68 + let iChannel: WebGLUniformLocation | null = null; 69 + let iDate: WebGLUniformLocation | null = null; 70 + 71 + let frameCount = 0; 72 + let prevTimestamp: DOMHighResTimeStamp; 73 + 74 + const state = { 75 + draw(source: TexImageSource, timestamp: DOMHighResTimeStamp) { 76 + prevTimestamp = timestamp; 77 + 78 + gl.useProgram(program); 79 + 80 + if (source) { 81 + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, source); 82 + if (iChannelResolution) 83 + gl.uniform3fv(iChannelResolution, [width, height, 0]); 84 + } else { 85 + if (iChannelResolution) 86 + gl.uniform3fv(iChannelResolution, [0, 0, 0]); 87 + } 88 + 89 + if (iResolution) 90 + gl.uniform2f(iResolution, width, height); 91 + if (iTime) 92 + gl.uniform1f(iTime, timestamp / 1000); 93 + if (iTimeDelta) 94 + gl.uniform1f(iTime, (timestamp - prevTimestamp) / 1000); 95 + if (iFrame) 96 + gl.uniform1f(iFrame, frameCount++); 97 + if (iChannel) 98 + gl.uniform1i(iChannel, 0); 99 + if (iDate) 100 + gl.uniform4f(iDate, ...makeDateVector()); 101 + 102 + gl.enableVertexAttribArray(vertexPos); 103 + gl.vertexAttribPointer(vertexPos, 2, gl.FLOAT, false, 0, 0); 104 + gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); 105 + }, 106 + 107 + updateViewport(newWidth: number, newHeight: number) { 108 + gl.canvas.width = (width = newWidth); 109 + gl.canvas.height = (height = newHeight); 110 + gl.viewport(0, 0, width, height); 111 + }, 112 + 113 + updateFragShader(fragSource: string) { 114 + fragSource = fragSource.trim(); 115 + gl.shaderSource(fragShader, fragSource); 116 + gl.compileShader(fragShader); 117 + 118 + const vertShader = /\s+#version 300/i.test(fragSource) ? vertShader300 : vertShader100; 119 + gl.attachShader(program, vertShader); 120 + gl.attachShader(program, fragShader); 121 + 122 + gl.linkProgram(program); 123 + 124 + vertexPos = gl.getAttribLocation(program, 'vPos'); 125 + iResolution = gl.getUniformLocation(program, 'iResolution'); 126 + iChannelResolution = gl.getUniformLocation(program, 'iChannelResolution'); 127 + iTime = gl.getUniformLocation(program, 'iTime'); 128 + iTimeDelta = gl.getUniformLocation(program, 'iTimeDelta'); 129 + iFrame = gl.getUniformLocation(program, 'iFrame'); 130 + iChannel = gl.getUniformLocation(program, 'iChannel'); 131 + iDate = gl.getUniformLocation(program, 'iDate'); 132 + }, 133 + 134 + drawImmediate() { 135 + gl.useProgram(program); 136 + gl.enableVertexAttribArray(vertexPos); 137 + gl.vertexAttribPointer(vertexPos, 2, gl.FLOAT, false, 0, 0); 138 + gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); 139 + }, 140 + }; 141 + 142 + state.updateViewport(width, height); 143 + state.updateFragShader(init.fragSource); 144 + return state; 145 + } 146 + 147 + class FragCanvas extends HTMLElement implements HTMLCanvasElement { 148 + static observedAttributes = []; 149 + 150 + private state: ReturnType<typeof createState> | null; 151 + private input: HTMLCanvasElement | HTMLImageElement | HTMLVideoElement; 152 + private output: HTMLCanvasElement; 153 + 154 + #mutationObserver = new MutationObserver(() => { 155 + if (this.state) { 156 + this.state.updateFragShader(this.source); 157 + } 158 + }); 159 + 160 + #resizeObserver = new ResizeObserver((entries) => { 161 + const entry = entries[0]; 162 + if (this.state && entry) { 163 + const width = entry.devicePixelContentBoxSize[0].inlineSize; 164 + const height = entry.devicePixelContentBoxSize[0].blockSize; 165 + if (this.autoresize) { 166 + this.input.width = width; 167 + this.input.height = height; 168 + } 169 + this.state.updateViewport(width, height); 170 + this.state.drawImmediate(); 171 + this.#rescheduleDraw(); 172 + } 173 + }); 174 + 175 + constructor() { 176 + super(); 177 + 178 + const sheet = new CSSStyleSheet(); 179 + sheet.insertRule(':host([hidden]) { display: none; }'); 180 + sheet.insertRule(':host { display: block; position: relative; }'); 181 + sheet.insertRule(':host * { position: absolute; width: 100%; height: 100%; }'); 182 + sheet.insertRule(':host *:not(:last-child) { visibility: hidden; }'); 183 + 184 + const shadow = this.attachShadow({ mode: 'closed' }); 185 + const output = (this.output = document.createElement('canvas')); 186 + const input = (this.input = (this.querySelector(':not(canvas, script)') || document.createElement('canvas'))); 187 + 188 + shadow.adoptedStyleSheets = [sheet]; 189 + shadow.appendChild(input); 190 + shadow.appendChild(output); 191 + } 192 + 193 + getContext(contextId: '2d', options?: CanvasRenderingContext2DSettings): CanvasRenderingContext2D | null; 194 + getContext(contextId: 'bitmaprenderer', options?: ImageBitmapRenderingContextSettings): ImageBitmapRenderingContext | null; 195 + getContext(contextId: 'webgl', options?: WebGLContextAttributes): WebGLRenderingContext | null; 196 + getContext(contextId: 'webgl2', options?: WebGLContextAttributes): WebGL2RenderingContext | null; 197 + 198 + getContext(contextId: string, options?: any) { 199 + if (!(this.input instanceof HTMLCanvasElement)) { 200 + return null; 201 + } 202 + this.input.width = this.width; 203 + this.input.height = this.height; 204 + return this.input.getContext(contextId, { 205 + alpha: true, 206 + desynchronized: true, 207 + preserveDrawingBuffer: true, 208 + ...options, 209 + }); 210 + } 211 + 212 + toBlob(callback: BlobCallback, type?: string, quality?: any): void { 213 + return this.output.toBlob(callback, type, quality); 214 + } 215 + 216 + toDataURL(type?: string, quality?: any): string { 217 + return this.output.toDataURL(type, quality); 218 + } 219 + 220 + captureStream(frameRequestRate?: number): MediaStream { 221 + return this.output.captureStream(frameRequestRate); 222 + } 223 + 224 + transferControlToOffscreen(): OffscreenCanvas { 225 + return (this.input instanceof HTMLCanvasElement ? this.input : this.output).transferControlToOffscreen(); 226 + } 227 + 228 + get autoresize() { 229 + return this.hasAttribute('autoresize'); 230 + } 231 + 232 + set autoresize(autoresize: boolean) { 233 + if (autoresize) { 234 + this.setAttribute('autoresize', ''); 235 + } else { 236 + this.removeAttribute('autoresize'); 237 + } 238 + } 239 + 240 + get source() { 241 + let text = ''; 242 + for (const child of this.childNodes) { 243 + if (child.nodeType === Node.TEXT_NODE) { 244 + text += child.textContent || ''; 245 + } else if (child instanceof HTMLScriptElement) { 246 + text = child.textContent || ''; 247 + break; 248 + } 249 + } 250 + return text.trim(); 251 + } 252 + 253 + get width() { 254 + if (this.state) { 255 + return this.output.width; 256 + } else { 257 + return this.clientWidth * devicePixelRatio; 258 + } 259 + } 260 + 261 + set width(width) { 262 + this.input.width = width; 263 + } 264 + 265 + get height() { 266 + if (this.state) { 267 + return this.output.height; 268 + } else { 269 + return this.clientHeight * devicePixelRatio; 270 + } 271 + } 272 + 273 + set height(height) { 274 + this.input.height = height; 275 + } 276 + 277 + #frameID: number | undefined; 278 + #rescheduleDraw() { 279 + const self = this; 280 + if (this.#frameID !== undefined) { 281 + cancelAnimationFrame(this.#frameID); 282 + this.#frameID = undefined; 283 + } 284 + this.#frameID = requestAnimationFrame(function draw(timestamp: DOMHighResTimeStamp) { 285 + if (self.state) { 286 + self.state.draw(self.input, timestamp); 287 + self.#frameID = requestAnimationFrame(draw); 288 + } 289 + }); 290 + } 291 + 292 + connectedCallback() { 293 + const gl = this.output.getContext('webgl2', { 294 + alpha: true, 295 + desynchronized: true, 296 + preserveDrawingBuffer: true, 297 + }); 298 + 299 + const init = { 300 + fragSource: this.source, 301 + width: this.clientWidth * devicePixelRatio, 302 + height: this.clientHeight * devicePixelRatio, 303 + }; 304 + 305 + const state = (this.state = gl && createState(gl, init)); 306 + if (state) { 307 + this.#mutationObserver.observe(this, { subtree: true, characterData: true }); 308 + this.#resizeObserver.observe(this, { box: 'device-pixel-content-box' }); 309 + this.#rescheduleDraw(); 310 + } 311 + } 312 + 313 + disconnectedCallback() { 314 + this.#mutationObserver.disconnect(); 315 + this.#resizeObserver.disconnect(); 316 + if (this.#frameID !== undefined) { 317 + cancelAnimationFrame(this.#frameID); 318 + this.#frameID = undefined; 319 + } 320 + } 321 + } 322 + 323 + customElements.define('frag-canvas', FragCanvas); 324 + export { FragCanvas };
+1
src/index.ts
··· 1 + export * from './frag-canvas-element';