├── .gitignore ├── LICENSE ├── README.md ├── assets └── harmony.png ├── package.json ├── pnpm-lock.yaml ├── src ├── index.tsx └── utils.ts ├── tsconfig.json └── website ├── .eslintrc.json ├── .gitignore ├── README.md ├── next.config.js ├── package-lock.json ├── package.json ├── pnpm-lock.yaml ├── postcss.config.js ├── public ├── next.svg └── vercel.svg ├── src ├── app │ ├── ClientPage.tsx │ ├── favicon.ico │ ├── globals.css │ ├── layout.tsx │ └── page.tsx └── components │ └── GradientMesh │ └── GradientMesh.js ├── tailwind.config.ts └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_STORE 2 | node_modules 3 | .env 4 | build -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 New Fragment 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Harmony](./assets/harmony.png) 2 | 3 | # Harmony 4 | 5 | A new kind of Color Picker, which computes harmonic colors along with the primary one. It supports Analogous, Triad, Tetradic, Complementary & Square harmonies. 6 | 7 | [Read more about the implementation here.](https://polar.sh/emilwidlund/posts/a-new-kind-of-color-picker-with-react-typescript) 8 | 9 | ### Installation 10 | 11 | Harmony is available on the npm registry. It requires React as a peer dependency. 12 | 13 | `pnpm install @newfrgmnt/harmony` 14 | 15 | ### API 16 | 17 | ```typescript 18 | import {ColorWheel} from '@newfrgmnt/harmony'; 19 | 20 | export const MyColorPicker = () => { 21 | return ( 22 | 23 | ); 24 | } 25 | ``` 26 | 27 | #### Supported properties 28 | 29 | ```typescript 30 | radius: number; 31 | harmony: 'tetradic' | 'triad' | 'analogous' | 'square' | 'complementary'; 32 | color?: {hue: number, saturation: number, value: number}; 33 | defaultColor?: {hue: number, saturation: number, value: number}; 34 | onChange?: (colors: { hue: number; saturation: number; value: number }[]) => void; 35 | ``` 36 | 37 | #### Convert the HSV format to RGB 38 | 39 | You can use the following function to convert the HSV output to RGB. 40 | 41 | ```typescript 42 | function HSVtoRGB(h: number, s: number, v: number) { 43 | var r, g, b, i, f, p, q, t; 44 | h = h / 360; 45 | i = Math.floor(h * 6); 46 | f = h * 6 - i; 47 | p = v * (1 - s); 48 | q = v * (1 - f * s); 49 | t = v * (1 - (1 - f) * s); 50 | switch (i % 6) { 51 | case 0: 52 | (r = v), (g = t), (b = p); 53 | break; 54 | case 1: 55 | (r = q), (g = v), (b = p); 56 | break; 57 | case 2: 58 | (r = p), (g = v), (b = t); 59 | break; 60 | case 3: 61 | (r = p), (g = q), (b = v); 62 | break; 63 | case 4: 64 | (r = t), (g = p), (b = v); 65 | break; 66 | case 5: 67 | (r = v), (g = p), (b = q); 68 | break; 69 | } 70 | return { 71 | r, 72 | g, 73 | b, 74 | }; 75 | } 76 | ``` -------------------------------------------------------------------------------- /assets/harmony.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emilwidlund/harmony/4858d4c305441f9ba54a0efab57cca3304757e6c/assets/harmony.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@newfrgmnt/harmony", 3 | "version": "1.0.3", 4 | "main": "./build/index.cjs", 5 | "module": "./build/index.js", 6 | "types": "./build/index.d.ts", 7 | "files": [ 8 | "build/*" 9 | ], 10 | "scripts": { 11 | "build": "tsup src/index.tsx --format cjs,esm --dts --outDir build", 12 | "prepublishOnly": "pnpm run build" 13 | }, 14 | "keywords": [], 15 | "author": "", 16 | "repository": { 17 | "type": "git", 18 | "url": "https://github.com/newfrgmnt/harmony" 19 | }, 20 | "license": "MIT", 21 | "devDependencies": { 22 | "@types/react": "^18.2.47", 23 | "react": "^18.2.0", 24 | "tsup": "^8.0.1", 25 | "typescript": "^5.3.3" 26 | }, 27 | "publishConfig": { 28 | "access": "public" 29 | }, 30 | "type": "module", 31 | "dependencies": { 32 | "react-draggable": "^4.4.6" 33 | }, 34 | "peerDependencies": { 35 | "react": "^18.2.0" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '6.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | dependencies: 8 | react-draggable: 9 | specifier: ^4.4.6 10 | version: 4.4.6(react-dom@18.2.0)(react@18.2.0) 11 | 12 | devDependencies: 13 | '@types/react': 14 | specifier: ^18.2.47 15 | version: 18.2.47 16 | react: 17 | specifier: ^18.2.0 18 | version: 18.2.0 19 | tsup: 20 | specifier: ^8.0.1 21 | version: 8.0.1(typescript@5.3.3) 22 | typescript: 23 | specifier: ^5.3.3 24 | version: 5.3.3 25 | 26 | packages: 27 | 28 | /@esbuild/aix-ppc64@0.19.11: 29 | resolution: {integrity: sha512-FnzU0LyE3ySQk7UntJO4+qIiQgI7KoODnZg5xzXIrFJlKd2P2gwHsHY4927xj9y5PJmJSzULiUCWmv7iWnNa7g==} 30 | engines: {node: '>=12'} 31 | cpu: [ppc64] 32 | os: [aix] 33 | requiresBuild: true 34 | dev: true 35 | optional: true 36 | 37 | /@esbuild/android-arm64@0.19.11: 38 | resolution: {integrity: sha512-aiu7K/5JnLj//KOnOfEZ0D90obUkRzDMyqd/wNAUQ34m4YUPVhRZpnqKV9uqDGxT7cToSDnIHsGooyIczu9T+Q==} 39 | engines: {node: '>=12'} 40 | cpu: [arm64] 41 | os: [android] 42 | requiresBuild: true 43 | dev: true 44 | optional: true 45 | 46 | /@esbuild/android-arm@0.19.11: 47 | resolution: {integrity: sha512-5OVapq0ClabvKvQ58Bws8+wkLCV+Rxg7tUVbo9xu034Nm536QTII4YzhaFriQ7rMrorfnFKUsArD2lqKbFY4vw==} 48 | engines: {node: '>=12'} 49 | cpu: [arm] 50 | os: [android] 51 | requiresBuild: true 52 | dev: true 53 | optional: true 54 | 55 | /@esbuild/android-x64@0.19.11: 56 | resolution: {integrity: sha512-eccxjlfGw43WYoY9QgB82SgGgDbibcqyDTlk3l3C0jOVHKxrjdc9CTwDUQd0vkvYg5um0OH+GpxYvp39r+IPOg==} 57 | engines: {node: '>=12'} 58 | cpu: [x64] 59 | os: [android] 60 | requiresBuild: true 61 | dev: true 62 | optional: true 63 | 64 | /@esbuild/darwin-arm64@0.19.11: 65 | resolution: {integrity: sha512-ETp87DRWuSt9KdDVkqSoKoLFHYTrkyz2+65fj9nfXsaV3bMhTCjtQfw3y+um88vGRKRiF7erPrh/ZuIdLUIVxQ==} 66 | engines: {node: '>=12'} 67 | cpu: [arm64] 68 | os: [darwin] 69 | requiresBuild: true 70 | dev: true 71 | optional: true 72 | 73 | /@esbuild/darwin-x64@0.19.11: 74 | resolution: {integrity: sha512-fkFUiS6IUK9WYUO/+22omwetaSNl5/A8giXvQlcinLIjVkxwTLSktbF5f/kJMftM2MJp9+fXqZ5ezS7+SALp4g==} 75 | engines: {node: '>=12'} 76 | cpu: [x64] 77 | os: [darwin] 78 | requiresBuild: true 79 | dev: true 80 | optional: true 81 | 82 | /@esbuild/freebsd-arm64@0.19.11: 83 | resolution: {integrity: sha512-lhoSp5K6bxKRNdXUtHoNc5HhbXVCS8V0iZmDvyWvYq9S5WSfTIHU2UGjcGt7UeS6iEYp9eeymIl5mJBn0yiuxA==} 84 | engines: {node: '>=12'} 85 | cpu: [arm64] 86 | os: [freebsd] 87 | requiresBuild: true 88 | dev: true 89 | optional: true 90 | 91 | /@esbuild/freebsd-x64@0.19.11: 92 | resolution: {integrity: sha512-JkUqn44AffGXitVI6/AbQdoYAq0TEullFdqcMY/PCUZ36xJ9ZJRtQabzMA+Vi7r78+25ZIBosLTOKnUXBSi1Kw==} 93 | engines: {node: '>=12'} 94 | cpu: [x64] 95 | os: [freebsd] 96 | requiresBuild: true 97 | dev: true 98 | optional: true 99 | 100 | /@esbuild/linux-arm64@0.19.11: 101 | resolution: {integrity: sha512-LneLg3ypEeveBSMuoa0kwMpCGmpu8XQUh+mL8XXwoYZ6Be2qBnVtcDI5azSvh7vioMDhoJFZzp9GWp9IWpYoUg==} 102 | engines: {node: '>=12'} 103 | cpu: [arm64] 104 | os: [linux] 105 | requiresBuild: true 106 | dev: true 107 | optional: true 108 | 109 | /@esbuild/linux-arm@0.19.11: 110 | resolution: {integrity: sha512-3CRkr9+vCV2XJbjwgzjPtO8T0SZUmRZla+UL1jw+XqHZPkPgZiyWvbDvl9rqAN8Zl7qJF0O/9ycMtjU67HN9/Q==} 111 | engines: {node: '>=12'} 112 | cpu: [arm] 113 | os: [linux] 114 | requiresBuild: true 115 | dev: true 116 | optional: true 117 | 118 | /@esbuild/linux-ia32@0.19.11: 119 | resolution: {integrity: sha512-caHy++CsD8Bgq2V5CodbJjFPEiDPq8JJmBdeyZ8GWVQMjRD0sU548nNdwPNvKjVpamYYVL40AORekgfIubwHoA==} 120 | engines: {node: '>=12'} 121 | cpu: [ia32] 122 | os: [linux] 123 | requiresBuild: true 124 | dev: true 125 | optional: true 126 | 127 | /@esbuild/linux-loong64@0.19.11: 128 | resolution: {integrity: sha512-ppZSSLVpPrwHccvC6nQVZaSHlFsvCQyjnvirnVjbKSHuE5N24Yl8F3UwYUUR1UEPaFObGD2tSvVKbvR+uT1Nrg==} 129 | engines: {node: '>=12'} 130 | cpu: [loong64] 131 | os: [linux] 132 | requiresBuild: true 133 | dev: true 134 | optional: true 135 | 136 | /@esbuild/linux-mips64el@0.19.11: 137 | resolution: {integrity: sha512-B5x9j0OgjG+v1dF2DkH34lr+7Gmv0kzX6/V0afF41FkPMMqaQ77pH7CrhWeR22aEeHKaeZVtZ6yFwlxOKPVFyg==} 138 | engines: {node: '>=12'} 139 | cpu: [mips64el] 140 | os: [linux] 141 | requiresBuild: true 142 | dev: true 143 | optional: true 144 | 145 | /@esbuild/linux-ppc64@0.19.11: 146 | resolution: {integrity: sha512-MHrZYLeCG8vXblMetWyttkdVRjQlQUb/oMgBNurVEnhj4YWOr4G5lmBfZjHYQHHN0g6yDmCAQRR8MUHldvvRDA==} 147 | engines: {node: '>=12'} 148 | cpu: [ppc64] 149 | os: [linux] 150 | requiresBuild: true 151 | dev: true 152 | optional: true 153 | 154 | /@esbuild/linux-riscv64@0.19.11: 155 | resolution: {integrity: sha512-f3DY++t94uVg141dozDu4CCUkYW+09rWtaWfnb3bqe4w5NqmZd6nPVBm+qbz7WaHZCoqXqHz5p6CM6qv3qnSSQ==} 156 | engines: {node: '>=12'} 157 | cpu: [riscv64] 158 | os: [linux] 159 | requiresBuild: true 160 | dev: true 161 | optional: true 162 | 163 | /@esbuild/linux-s390x@0.19.11: 164 | resolution: {integrity: sha512-A5xdUoyWJHMMlcSMcPGVLzYzpcY8QP1RtYzX5/bS4dvjBGVxdhuiYyFwp7z74ocV7WDc0n1harxmpq2ePOjI0Q==} 165 | engines: {node: '>=12'} 166 | cpu: [s390x] 167 | os: [linux] 168 | requiresBuild: true 169 | dev: true 170 | optional: true 171 | 172 | /@esbuild/linux-x64@0.19.11: 173 | resolution: {integrity: sha512-grbyMlVCvJSfxFQUndw5mCtWs5LO1gUlwP4CDi4iJBbVpZcqLVT29FxgGuBJGSzyOxotFG4LoO5X+M1350zmPA==} 174 | engines: {node: '>=12'} 175 | cpu: [x64] 176 | os: [linux] 177 | requiresBuild: true 178 | dev: true 179 | optional: true 180 | 181 | /@esbuild/netbsd-x64@0.19.11: 182 | resolution: {integrity: sha512-13jvrQZJc3P230OhU8xgwUnDeuC/9egsjTkXN49b3GcS5BKvJqZn86aGM8W9pd14Kd+u7HuFBMVtrNGhh6fHEQ==} 183 | engines: {node: '>=12'} 184 | cpu: [x64] 185 | os: [netbsd] 186 | requiresBuild: true 187 | dev: true 188 | optional: true 189 | 190 | /@esbuild/openbsd-x64@0.19.11: 191 | resolution: {integrity: sha512-ysyOGZuTp6SNKPE11INDUeFVVQFrhcNDVUgSQVDzqsqX38DjhPEPATpid04LCoUr2WXhQTEZ8ct/EgJCUDpyNw==} 192 | engines: {node: '>=12'} 193 | cpu: [x64] 194 | os: [openbsd] 195 | requiresBuild: true 196 | dev: true 197 | optional: true 198 | 199 | /@esbuild/sunos-x64@0.19.11: 200 | resolution: {integrity: sha512-Hf+Sad9nVwvtxy4DXCZQqLpgmRTQqyFyhT3bZ4F2XlJCjxGmRFF0Shwn9rzhOYRB61w9VMXUkxlBy56dk9JJiQ==} 201 | engines: {node: '>=12'} 202 | cpu: [x64] 203 | os: [sunos] 204 | requiresBuild: true 205 | dev: true 206 | optional: true 207 | 208 | /@esbuild/win32-arm64@0.19.11: 209 | resolution: {integrity: sha512-0P58Sbi0LctOMOQbpEOvOL44Ne0sqbS0XWHMvvrg6NE5jQ1xguCSSw9jQeUk2lfrXYsKDdOe6K+oZiwKPilYPQ==} 210 | engines: {node: '>=12'} 211 | cpu: [arm64] 212 | os: [win32] 213 | requiresBuild: true 214 | dev: true 215 | optional: true 216 | 217 | /@esbuild/win32-ia32@0.19.11: 218 | resolution: {integrity: sha512-6YOrWS+sDJDmshdBIQU+Uoyh7pQKrdykdefC1avn76ss5c+RN6gut3LZA4E2cH5xUEp5/cA0+YxRaVtRAb0xBg==} 219 | engines: {node: '>=12'} 220 | cpu: [ia32] 221 | os: [win32] 222 | requiresBuild: true 223 | dev: true 224 | optional: true 225 | 226 | /@esbuild/win32-x64@0.19.11: 227 | resolution: {integrity: sha512-vfkhltrjCAb603XaFhqhAF4LGDi2M4OrCRrFusyQ+iTLQ/o60QQXxc9cZC/FFpihBI9N1Grn6SMKVJ4KP7Fuiw==} 228 | engines: {node: '>=12'} 229 | cpu: [x64] 230 | os: [win32] 231 | requiresBuild: true 232 | dev: true 233 | optional: true 234 | 235 | /@isaacs/cliui@8.0.2: 236 | resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} 237 | engines: {node: '>=12'} 238 | dependencies: 239 | string-width: 5.1.2 240 | string-width-cjs: /string-width@4.2.3 241 | strip-ansi: 7.1.0 242 | strip-ansi-cjs: /strip-ansi@6.0.1 243 | wrap-ansi: 8.1.0 244 | wrap-ansi-cjs: /wrap-ansi@7.0.0 245 | dev: true 246 | 247 | /@jridgewell/gen-mapping@0.3.3: 248 | resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} 249 | engines: {node: '>=6.0.0'} 250 | dependencies: 251 | '@jridgewell/set-array': 1.1.2 252 | '@jridgewell/sourcemap-codec': 1.4.15 253 | '@jridgewell/trace-mapping': 0.3.20 254 | dev: true 255 | 256 | /@jridgewell/resolve-uri@3.1.1: 257 | resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==} 258 | engines: {node: '>=6.0.0'} 259 | dev: true 260 | 261 | /@jridgewell/set-array@1.1.2: 262 | resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} 263 | engines: {node: '>=6.0.0'} 264 | dev: true 265 | 266 | /@jridgewell/sourcemap-codec@1.4.15: 267 | resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} 268 | dev: true 269 | 270 | /@jridgewell/trace-mapping@0.3.20: 271 | resolution: {integrity: sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==} 272 | dependencies: 273 | '@jridgewell/resolve-uri': 3.1.1 274 | '@jridgewell/sourcemap-codec': 1.4.15 275 | dev: true 276 | 277 | /@nodelib/fs.scandir@2.1.5: 278 | resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} 279 | engines: {node: '>= 8'} 280 | dependencies: 281 | '@nodelib/fs.stat': 2.0.5 282 | run-parallel: 1.2.0 283 | dev: true 284 | 285 | /@nodelib/fs.stat@2.0.5: 286 | resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} 287 | engines: {node: '>= 8'} 288 | dev: true 289 | 290 | /@nodelib/fs.walk@1.2.8: 291 | resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} 292 | engines: {node: '>= 8'} 293 | dependencies: 294 | '@nodelib/fs.scandir': 2.1.5 295 | fastq: 1.16.0 296 | dev: true 297 | 298 | /@pkgjs/parseargs@0.11.0: 299 | resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} 300 | engines: {node: '>=14'} 301 | requiresBuild: true 302 | dev: true 303 | optional: true 304 | 305 | /@rollup/rollup-android-arm-eabi@4.9.4: 306 | resolution: {integrity: sha512-ub/SN3yWqIv5CWiAZPHVS1DloyZsJbtXmX4HxUTIpS0BHm9pW5iYBo2mIZi+hE3AeiTzHz33blwSnhdUo+9NpA==} 307 | cpu: [arm] 308 | os: [android] 309 | requiresBuild: true 310 | dev: true 311 | optional: true 312 | 313 | /@rollup/rollup-android-arm64@4.9.4: 314 | resolution: {integrity: sha512-ehcBrOR5XTl0W0t2WxfTyHCR/3Cq2jfb+I4W+Ch8Y9b5G+vbAecVv0Fx/J1QKktOrgUYsIKxWAKgIpvw56IFNA==} 315 | cpu: [arm64] 316 | os: [android] 317 | requiresBuild: true 318 | dev: true 319 | optional: true 320 | 321 | /@rollup/rollup-darwin-arm64@4.9.4: 322 | resolution: {integrity: sha512-1fzh1lWExwSTWy8vJPnNbNM02WZDS8AW3McEOb7wW+nPChLKf3WG2aG7fhaUmfX5FKw9zhsF5+MBwArGyNM7NA==} 323 | cpu: [arm64] 324 | os: [darwin] 325 | requiresBuild: true 326 | dev: true 327 | optional: true 328 | 329 | /@rollup/rollup-darwin-x64@4.9.4: 330 | resolution: {integrity: sha512-Gc6cukkF38RcYQ6uPdiXi70JB0f29CwcQ7+r4QpfNpQFVHXRd0DfWFidoGxjSx1DwOETM97JPz1RXL5ISSB0pA==} 331 | cpu: [x64] 332 | os: [darwin] 333 | requiresBuild: true 334 | dev: true 335 | optional: true 336 | 337 | /@rollup/rollup-linux-arm-gnueabihf@4.9.4: 338 | resolution: {integrity: sha512-g21RTeFzoTl8GxosHbnQZ0/JkuFIB13C3T7Y0HtKzOXmoHhewLbVTFBQZu+z5m9STH6FZ7L/oPgU4Nm5ErN2fw==} 339 | cpu: [arm] 340 | os: [linux] 341 | requiresBuild: true 342 | dev: true 343 | optional: true 344 | 345 | /@rollup/rollup-linux-arm64-gnu@4.9.4: 346 | resolution: {integrity: sha512-TVYVWD/SYwWzGGnbfTkrNpdE4HON46orgMNHCivlXmlsSGQOx/OHHYiQcMIOx38/GWgwr/po2LBn7wypkWw/Mg==} 347 | cpu: [arm64] 348 | os: [linux] 349 | requiresBuild: true 350 | dev: true 351 | optional: true 352 | 353 | /@rollup/rollup-linux-arm64-musl@4.9.4: 354 | resolution: {integrity: sha512-XcKvuendwizYYhFxpvQ3xVpzje2HHImzg33wL9zvxtj77HvPStbSGI9czrdbfrf8DGMcNNReH9pVZv8qejAQ5A==} 355 | cpu: [arm64] 356 | os: [linux] 357 | requiresBuild: true 358 | dev: true 359 | optional: true 360 | 361 | /@rollup/rollup-linux-riscv64-gnu@4.9.4: 362 | resolution: {integrity: sha512-LFHS/8Q+I9YA0yVETyjonMJ3UA+DczeBd/MqNEzsGSTdNvSJa1OJZcSH8GiXLvcizgp9AlHs2walqRcqzjOi3A==} 363 | cpu: [riscv64] 364 | os: [linux] 365 | requiresBuild: true 366 | dev: true 367 | optional: true 368 | 369 | /@rollup/rollup-linux-x64-gnu@4.9.4: 370 | resolution: {integrity: sha512-dIYgo+j1+yfy81i0YVU5KnQrIJZE8ERomx17ReU4GREjGtDW4X+nvkBak2xAUpyqLs4eleDSj3RrV72fQos7zw==} 371 | cpu: [x64] 372 | os: [linux] 373 | requiresBuild: true 374 | dev: true 375 | optional: true 376 | 377 | /@rollup/rollup-linux-x64-musl@4.9.4: 378 | resolution: {integrity: sha512-RoaYxjdHQ5TPjaPrLsfKqR3pakMr3JGqZ+jZM0zP2IkDtsGa4CqYaWSfQmZVgFUCgLrTnzX+cnHS3nfl+kB6ZQ==} 379 | cpu: [x64] 380 | os: [linux] 381 | requiresBuild: true 382 | dev: true 383 | optional: true 384 | 385 | /@rollup/rollup-win32-arm64-msvc@4.9.4: 386 | resolution: {integrity: sha512-T8Q3XHV+Jjf5e49B4EAaLKV74BbX7/qYBRQ8Wop/+TyyU0k+vSjiLVSHNWdVd1goMjZcbhDmYZUYW5RFqkBNHQ==} 387 | cpu: [arm64] 388 | os: [win32] 389 | requiresBuild: true 390 | dev: true 391 | optional: true 392 | 393 | /@rollup/rollup-win32-ia32-msvc@4.9.4: 394 | resolution: {integrity: sha512-z+JQ7JirDUHAsMecVydnBPWLwJjbppU+7LZjffGf+Jvrxq+dVjIE7By163Sc9DKc3ADSU50qPVw0KonBS+a+HQ==} 395 | cpu: [ia32] 396 | os: [win32] 397 | requiresBuild: true 398 | dev: true 399 | optional: true 400 | 401 | /@rollup/rollup-win32-x64-msvc@4.9.4: 402 | resolution: {integrity: sha512-LfdGXCV9rdEify1oxlN9eamvDSjv9md9ZVMAbNHA87xqIfFCxImxan9qZ8+Un54iK2nnqPlbnSi4R54ONtbWBw==} 403 | cpu: [x64] 404 | os: [win32] 405 | requiresBuild: true 406 | dev: true 407 | optional: true 408 | 409 | /@types/estree@1.0.5: 410 | resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} 411 | dev: true 412 | 413 | /@types/prop-types@15.7.11: 414 | resolution: {integrity: sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==} 415 | dev: true 416 | 417 | /@types/react@18.2.47: 418 | resolution: {integrity: sha512-xquNkkOirwyCgoClNk85BjP+aqnIS+ckAJ8i37gAbDs14jfW/J23f2GItAf33oiUPQnqNMALiFeoM9Y5mbjpVQ==} 419 | dependencies: 420 | '@types/prop-types': 15.7.11 421 | '@types/scheduler': 0.16.8 422 | csstype: 3.1.3 423 | dev: true 424 | 425 | /@types/scheduler@0.16.8: 426 | resolution: {integrity: sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==} 427 | dev: true 428 | 429 | /ansi-regex@5.0.1: 430 | resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} 431 | engines: {node: '>=8'} 432 | dev: true 433 | 434 | /ansi-regex@6.0.1: 435 | resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} 436 | engines: {node: '>=12'} 437 | dev: true 438 | 439 | /ansi-styles@4.3.0: 440 | resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} 441 | engines: {node: '>=8'} 442 | dependencies: 443 | color-convert: 2.0.1 444 | dev: true 445 | 446 | /ansi-styles@6.2.1: 447 | resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} 448 | engines: {node: '>=12'} 449 | dev: true 450 | 451 | /any-promise@1.3.0: 452 | resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} 453 | dev: true 454 | 455 | /anymatch@3.1.3: 456 | resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} 457 | engines: {node: '>= 8'} 458 | dependencies: 459 | normalize-path: 3.0.0 460 | picomatch: 2.3.1 461 | dev: true 462 | 463 | /array-union@2.1.0: 464 | resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} 465 | engines: {node: '>=8'} 466 | dev: true 467 | 468 | /balanced-match@1.0.2: 469 | resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} 470 | dev: true 471 | 472 | /binary-extensions@2.2.0: 473 | resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} 474 | engines: {node: '>=8'} 475 | dev: true 476 | 477 | /brace-expansion@2.0.1: 478 | resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} 479 | dependencies: 480 | balanced-match: 1.0.2 481 | dev: true 482 | 483 | /braces@3.0.2: 484 | resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} 485 | engines: {node: '>=8'} 486 | dependencies: 487 | fill-range: 7.0.1 488 | dev: true 489 | 490 | /bundle-require@4.0.2(esbuild@0.19.11): 491 | resolution: {integrity: sha512-jwzPOChofl67PSTW2SGubV9HBQAhhR2i6nskiOThauo9dzwDUgOWQScFVaJkjEfYX+UXiD+LEx8EblQMc2wIag==} 492 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 493 | peerDependencies: 494 | esbuild: '>=0.17' 495 | dependencies: 496 | esbuild: 0.19.11 497 | load-tsconfig: 0.2.5 498 | dev: true 499 | 500 | /cac@6.7.14: 501 | resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} 502 | engines: {node: '>=8'} 503 | dev: true 504 | 505 | /chokidar@3.5.3: 506 | resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} 507 | engines: {node: '>= 8.10.0'} 508 | dependencies: 509 | anymatch: 3.1.3 510 | braces: 3.0.2 511 | glob-parent: 5.1.2 512 | is-binary-path: 2.1.0 513 | is-glob: 4.0.3 514 | normalize-path: 3.0.0 515 | readdirp: 3.6.0 516 | optionalDependencies: 517 | fsevents: 2.3.3 518 | dev: true 519 | 520 | /clsx@1.2.1: 521 | resolution: {integrity: sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==} 522 | engines: {node: '>=6'} 523 | dev: false 524 | 525 | /color-convert@2.0.1: 526 | resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} 527 | engines: {node: '>=7.0.0'} 528 | dependencies: 529 | color-name: 1.1.4 530 | dev: true 531 | 532 | /color-name@1.1.4: 533 | resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} 534 | dev: true 535 | 536 | /commander@4.1.1: 537 | resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} 538 | engines: {node: '>= 6'} 539 | dev: true 540 | 541 | /cross-spawn@7.0.3: 542 | resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} 543 | engines: {node: '>= 8'} 544 | dependencies: 545 | path-key: 3.1.1 546 | shebang-command: 2.0.0 547 | which: 2.0.2 548 | dev: true 549 | 550 | /csstype@3.1.3: 551 | resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} 552 | dev: true 553 | 554 | /debug@4.3.4: 555 | resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} 556 | engines: {node: '>=6.0'} 557 | peerDependencies: 558 | supports-color: '*' 559 | peerDependenciesMeta: 560 | supports-color: 561 | optional: true 562 | dependencies: 563 | ms: 2.1.2 564 | dev: true 565 | 566 | /dir-glob@3.0.1: 567 | resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} 568 | engines: {node: '>=8'} 569 | dependencies: 570 | path-type: 4.0.0 571 | dev: true 572 | 573 | /eastasianwidth@0.2.0: 574 | resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} 575 | dev: true 576 | 577 | /emoji-regex@8.0.0: 578 | resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} 579 | dev: true 580 | 581 | /emoji-regex@9.2.2: 582 | resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} 583 | dev: true 584 | 585 | /esbuild@0.19.11: 586 | resolution: {integrity: sha512-HJ96Hev2hX/6i5cDVwcqiJBBtuo9+FeIJOtZ9W1kA5M6AMJRHUZlpYZ1/SbEwtO0ioNAW8rUooVpC/WehY2SfA==} 587 | engines: {node: '>=12'} 588 | hasBin: true 589 | requiresBuild: true 590 | optionalDependencies: 591 | '@esbuild/aix-ppc64': 0.19.11 592 | '@esbuild/android-arm': 0.19.11 593 | '@esbuild/android-arm64': 0.19.11 594 | '@esbuild/android-x64': 0.19.11 595 | '@esbuild/darwin-arm64': 0.19.11 596 | '@esbuild/darwin-x64': 0.19.11 597 | '@esbuild/freebsd-arm64': 0.19.11 598 | '@esbuild/freebsd-x64': 0.19.11 599 | '@esbuild/linux-arm': 0.19.11 600 | '@esbuild/linux-arm64': 0.19.11 601 | '@esbuild/linux-ia32': 0.19.11 602 | '@esbuild/linux-loong64': 0.19.11 603 | '@esbuild/linux-mips64el': 0.19.11 604 | '@esbuild/linux-ppc64': 0.19.11 605 | '@esbuild/linux-riscv64': 0.19.11 606 | '@esbuild/linux-s390x': 0.19.11 607 | '@esbuild/linux-x64': 0.19.11 608 | '@esbuild/netbsd-x64': 0.19.11 609 | '@esbuild/openbsd-x64': 0.19.11 610 | '@esbuild/sunos-x64': 0.19.11 611 | '@esbuild/win32-arm64': 0.19.11 612 | '@esbuild/win32-ia32': 0.19.11 613 | '@esbuild/win32-x64': 0.19.11 614 | dev: true 615 | 616 | /execa@5.1.1: 617 | resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} 618 | engines: {node: '>=10'} 619 | dependencies: 620 | cross-spawn: 7.0.3 621 | get-stream: 6.0.1 622 | human-signals: 2.1.0 623 | is-stream: 2.0.1 624 | merge-stream: 2.0.0 625 | npm-run-path: 4.0.1 626 | onetime: 5.1.2 627 | signal-exit: 3.0.7 628 | strip-final-newline: 2.0.0 629 | dev: true 630 | 631 | /fast-glob@3.3.2: 632 | resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} 633 | engines: {node: '>=8.6.0'} 634 | dependencies: 635 | '@nodelib/fs.stat': 2.0.5 636 | '@nodelib/fs.walk': 1.2.8 637 | glob-parent: 5.1.2 638 | merge2: 1.4.1 639 | micromatch: 4.0.5 640 | dev: true 641 | 642 | /fastq@1.16.0: 643 | resolution: {integrity: sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==} 644 | dependencies: 645 | reusify: 1.0.4 646 | dev: true 647 | 648 | /fill-range@7.0.1: 649 | resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} 650 | engines: {node: '>=8'} 651 | dependencies: 652 | to-regex-range: 5.0.1 653 | dev: true 654 | 655 | /foreground-child@3.1.1: 656 | resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==} 657 | engines: {node: '>=14'} 658 | dependencies: 659 | cross-spawn: 7.0.3 660 | signal-exit: 4.1.0 661 | dev: true 662 | 663 | /fsevents@2.3.3: 664 | resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} 665 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 666 | os: [darwin] 667 | requiresBuild: true 668 | dev: true 669 | optional: true 670 | 671 | /get-stream@6.0.1: 672 | resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} 673 | engines: {node: '>=10'} 674 | dev: true 675 | 676 | /glob-parent@5.1.2: 677 | resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} 678 | engines: {node: '>= 6'} 679 | dependencies: 680 | is-glob: 4.0.3 681 | dev: true 682 | 683 | /glob@10.3.10: 684 | resolution: {integrity: sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==} 685 | engines: {node: '>=16 || 14 >=14.17'} 686 | hasBin: true 687 | dependencies: 688 | foreground-child: 3.1.1 689 | jackspeak: 2.3.6 690 | minimatch: 9.0.3 691 | minipass: 7.0.4 692 | path-scurry: 1.10.1 693 | dev: true 694 | 695 | /globby@11.1.0: 696 | resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} 697 | engines: {node: '>=10'} 698 | dependencies: 699 | array-union: 2.1.0 700 | dir-glob: 3.0.1 701 | fast-glob: 3.3.2 702 | ignore: 5.3.0 703 | merge2: 1.4.1 704 | slash: 3.0.0 705 | dev: true 706 | 707 | /human-signals@2.1.0: 708 | resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} 709 | engines: {node: '>=10.17.0'} 710 | dev: true 711 | 712 | /ignore@5.3.0: 713 | resolution: {integrity: sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==} 714 | engines: {node: '>= 4'} 715 | dev: true 716 | 717 | /is-binary-path@2.1.0: 718 | resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} 719 | engines: {node: '>=8'} 720 | dependencies: 721 | binary-extensions: 2.2.0 722 | dev: true 723 | 724 | /is-extglob@2.1.1: 725 | resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} 726 | engines: {node: '>=0.10.0'} 727 | dev: true 728 | 729 | /is-fullwidth-code-point@3.0.0: 730 | resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} 731 | engines: {node: '>=8'} 732 | dev: true 733 | 734 | /is-glob@4.0.3: 735 | resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} 736 | engines: {node: '>=0.10.0'} 737 | dependencies: 738 | is-extglob: 2.1.1 739 | dev: true 740 | 741 | /is-number@7.0.0: 742 | resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} 743 | engines: {node: '>=0.12.0'} 744 | dev: true 745 | 746 | /is-stream@2.0.1: 747 | resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} 748 | engines: {node: '>=8'} 749 | dev: true 750 | 751 | /isexe@2.0.0: 752 | resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} 753 | dev: true 754 | 755 | /jackspeak@2.3.6: 756 | resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==} 757 | engines: {node: '>=14'} 758 | dependencies: 759 | '@isaacs/cliui': 8.0.2 760 | optionalDependencies: 761 | '@pkgjs/parseargs': 0.11.0 762 | dev: true 763 | 764 | /joycon@3.1.1: 765 | resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} 766 | engines: {node: '>=10'} 767 | dev: true 768 | 769 | /js-tokens@4.0.0: 770 | resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} 771 | 772 | /lilconfig@3.0.0: 773 | resolution: {integrity: sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==} 774 | engines: {node: '>=14'} 775 | dev: true 776 | 777 | /lines-and-columns@1.2.4: 778 | resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} 779 | dev: true 780 | 781 | /load-tsconfig@0.2.5: 782 | resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} 783 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 784 | dev: true 785 | 786 | /lodash.sortby@4.7.0: 787 | resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} 788 | dev: true 789 | 790 | /loose-envify@1.4.0: 791 | resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} 792 | hasBin: true 793 | dependencies: 794 | js-tokens: 4.0.0 795 | 796 | /lru-cache@10.1.0: 797 | resolution: {integrity: sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==} 798 | engines: {node: 14 || >=16.14} 799 | dev: true 800 | 801 | /merge-stream@2.0.0: 802 | resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} 803 | dev: true 804 | 805 | /merge2@1.4.1: 806 | resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} 807 | engines: {node: '>= 8'} 808 | dev: true 809 | 810 | /micromatch@4.0.5: 811 | resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} 812 | engines: {node: '>=8.6'} 813 | dependencies: 814 | braces: 3.0.2 815 | picomatch: 2.3.1 816 | dev: true 817 | 818 | /mimic-fn@2.1.0: 819 | resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} 820 | engines: {node: '>=6'} 821 | dev: true 822 | 823 | /minimatch@9.0.3: 824 | resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} 825 | engines: {node: '>=16 || 14 >=14.17'} 826 | dependencies: 827 | brace-expansion: 2.0.1 828 | dev: true 829 | 830 | /minipass@7.0.4: 831 | resolution: {integrity: sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==} 832 | engines: {node: '>=16 || 14 >=14.17'} 833 | dev: true 834 | 835 | /ms@2.1.2: 836 | resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} 837 | dev: true 838 | 839 | /mz@2.7.0: 840 | resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} 841 | dependencies: 842 | any-promise: 1.3.0 843 | object-assign: 4.1.1 844 | thenify-all: 1.6.0 845 | dev: true 846 | 847 | /normalize-path@3.0.0: 848 | resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} 849 | engines: {node: '>=0.10.0'} 850 | dev: true 851 | 852 | /npm-run-path@4.0.1: 853 | resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} 854 | engines: {node: '>=8'} 855 | dependencies: 856 | path-key: 3.1.1 857 | dev: true 858 | 859 | /object-assign@4.1.1: 860 | resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} 861 | engines: {node: '>=0.10.0'} 862 | 863 | /onetime@5.1.2: 864 | resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} 865 | engines: {node: '>=6'} 866 | dependencies: 867 | mimic-fn: 2.1.0 868 | dev: true 869 | 870 | /path-key@3.1.1: 871 | resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} 872 | engines: {node: '>=8'} 873 | dev: true 874 | 875 | /path-scurry@1.10.1: 876 | resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==} 877 | engines: {node: '>=16 || 14 >=14.17'} 878 | dependencies: 879 | lru-cache: 10.1.0 880 | minipass: 7.0.4 881 | dev: true 882 | 883 | /path-type@4.0.0: 884 | resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} 885 | engines: {node: '>=8'} 886 | dev: true 887 | 888 | /picomatch@2.3.1: 889 | resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} 890 | engines: {node: '>=8.6'} 891 | dev: true 892 | 893 | /pirates@4.0.6: 894 | resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} 895 | engines: {node: '>= 6'} 896 | dev: true 897 | 898 | /postcss-load-config@4.0.2: 899 | resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} 900 | engines: {node: '>= 14'} 901 | peerDependencies: 902 | postcss: '>=8.0.9' 903 | ts-node: '>=9.0.0' 904 | peerDependenciesMeta: 905 | postcss: 906 | optional: true 907 | ts-node: 908 | optional: true 909 | dependencies: 910 | lilconfig: 3.0.0 911 | yaml: 2.3.4 912 | dev: true 913 | 914 | /prop-types@15.8.1: 915 | resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} 916 | dependencies: 917 | loose-envify: 1.4.0 918 | object-assign: 4.1.1 919 | react-is: 16.13.1 920 | dev: false 921 | 922 | /punycode@2.3.1: 923 | resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} 924 | engines: {node: '>=6'} 925 | dev: true 926 | 927 | /queue-microtask@1.2.3: 928 | resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} 929 | dev: true 930 | 931 | /react-dom@18.2.0(react@18.2.0): 932 | resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} 933 | peerDependencies: 934 | react: ^18.2.0 935 | dependencies: 936 | loose-envify: 1.4.0 937 | react: 18.2.0 938 | scheduler: 0.23.0 939 | dev: false 940 | 941 | /react-draggable@4.4.6(react-dom@18.2.0)(react@18.2.0): 942 | resolution: {integrity: sha512-LtY5Xw1zTPqHkVmtM3X8MUOxNDOUhv/khTgBgrUvwaS064bwVvxT+q5El0uUFNx5IEPKXuRejr7UqLwBIg5pdw==} 943 | peerDependencies: 944 | react: '>= 16.3.0' 945 | react-dom: '>= 16.3.0' 946 | dependencies: 947 | clsx: 1.2.1 948 | prop-types: 15.8.1 949 | react: 18.2.0 950 | react-dom: 18.2.0(react@18.2.0) 951 | dev: false 952 | 953 | /react-is@16.13.1: 954 | resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} 955 | dev: false 956 | 957 | /react@18.2.0: 958 | resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} 959 | engines: {node: '>=0.10.0'} 960 | dependencies: 961 | loose-envify: 1.4.0 962 | 963 | /readdirp@3.6.0: 964 | resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} 965 | engines: {node: '>=8.10.0'} 966 | dependencies: 967 | picomatch: 2.3.1 968 | dev: true 969 | 970 | /resolve-from@5.0.0: 971 | resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} 972 | engines: {node: '>=8'} 973 | dev: true 974 | 975 | /reusify@1.0.4: 976 | resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} 977 | engines: {iojs: '>=1.0.0', node: '>=0.10.0'} 978 | dev: true 979 | 980 | /rollup@4.9.4: 981 | resolution: {integrity: sha512-2ztU7pY/lrQyXSCnnoU4ICjT/tCG9cdH3/G25ERqE3Lst6vl2BCM5hL2Nw+sslAvAf+ccKsAq1SkKQALyqhR7g==} 982 | engines: {node: '>=18.0.0', npm: '>=8.0.0'} 983 | hasBin: true 984 | dependencies: 985 | '@types/estree': 1.0.5 986 | optionalDependencies: 987 | '@rollup/rollup-android-arm-eabi': 4.9.4 988 | '@rollup/rollup-android-arm64': 4.9.4 989 | '@rollup/rollup-darwin-arm64': 4.9.4 990 | '@rollup/rollup-darwin-x64': 4.9.4 991 | '@rollup/rollup-linux-arm-gnueabihf': 4.9.4 992 | '@rollup/rollup-linux-arm64-gnu': 4.9.4 993 | '@rollup/rollup-linux-arm64-musl': 4.9.4 994 | '@rollup/rollup-linux-riscv64-gnu': 4.9.4 995 | '@rollup/rollup-linux-x64-gnu': 4.9.4 996 | '@rollup/rollup-linux-x64-musl': 4.9.4 997 | '@rollup/rollup-win32-arm64-msvc': 4.9.4 998 | '@rollup/rollup-win32-ia32-msvc': 4.9.4 999 | '@rollup/rollup-win32-x64-msvc': 4.9.4 1000 | fsevents: 2.3.3 1001 | dev: true 1002 | 1003 | /run-parallel@1.2.0: 1004 | resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} 1005 | dependencies: 1006 | queue-microtask: 1.2.3 1007 | dev: true 1008 | 1009 | /scheduler@0.23.0: 1010 | resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==} 1011 | dependencies: 1012 | loose-envify: 1.4.0 1013 | dev: false 1014 | 1015 | /shebang-command@2.0.0: 1016 | resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} 1017 | engines: {node: '>=8'} 1018 | dependencies: 1019 | shebang-regex: 3.0.0 1020 | dev: true 1021 | 1022 | /shebang-regex@3.0.0: 1023 | resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} 1024 | engines: {node: '>=8'} 1025 | dev: true 1026 | 1027 | /signal-exit@3.0.7: 1028 | resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} 1029 | dev: true 1030 | 1031 | /signal-exit@4.1.0: 1032 | resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} 1033 | engines: {node: '>=14'} 1034 | dev: true 1035 | 1036 | /slash@3.0.0: 1037 | resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} 1038 | engines: {node: '>=8'} 1039 | dev: true 1040 | 1041 | /source-map@0.8.0-beta.0: 1042 | resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} 1043 | engines: {node: '>= 8'} 1044 | dependencies: 1045 | whatwg-url: 7.1.0 1046 | dev: true 1047 | 1048 | /string-width@4.2.3: 1049 | resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} 1050 | engines: {node: '>=8'} 1051 | dependencies: 1052 | emoji-regex: 8.0.0 1053 | is-fullwidth-code-point: 3.0.0 1054 | strip-ansi: 6.0.1 1055 | dev: true 1056 | 1057 | /string-width@5.1.2: 1058 | resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} 1059 | engines: {node: '>=12'} 1060 | dependencies: 1061 | eastasianwidth: 0.2.0 1062 | emoji-regex: 9.2.2 1063 | strip-ansi: 7.1.0 1064 | dev: true 1065 | 1066 | /strip-ansi@6.0.1: 1067 | resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} 1068 | engines: {node: '>=8'} 1069 | dependencies: 1070 | ansi-regex: 5.0.1 1071 | dev: true 1072 | 1073 | /strip-ansi@7.1.0: 1074 | resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} 1075 | engines: {node: '>=12'} 1076 | dependencies: 1077 | ansi-regex: 6.0.1 1078 | dev: true 1079 | 1080 | /strip-final-newline@2.0.0: 1081 | resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} 1082 | engines: {node: '>=6'} 1083 | dev: true 1084 | 1085 | /sucrase@3.35.0: 1086 | resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} 1087 | engines: {node: '>=16 || 14 >=14.17'} 1088 | hasBin: true 1089 | dependencies: 1090 | '@jridgewell/gen-mapping': 0.3.3 1091 | commander: 4.1.1 1092 | glob: 10.3.10 1093 | lines-and-columns: 1.2.4 1094 | mz: 2.7.0 1095 | pirates: 4.0.6 1096 | ts-interface-checker: 0.1.13 1097 | dev: true 1098 | 1099 | /thenify-all@1.6.0: 1100 | resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} 1101 | engines: {node: '>=0.8'} 1102 | dependencies: 1103 | thenify: 3.3.1 1104 | dev: true 1105 | 1106 | /thenify@3.3.1: 1107 | resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} 1108 | dependencies: 1109 | any-promise: 1.3.0 1110 | dev: true 1111 | 1112 | /to-regex-range@5.0.1: 1113 | resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} 1114 | engines: {node: '>=8.0'} 1115 | dependencies: 1116 | is-number: 7.0.0 1117 | dev: true 1118 | 1119 | /tr46@1.0.1: 1120 | resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==} 1121 | dependencies: 1122 | punycode: 2.3.1 1123 | dev: true 1124 | 1125 | /tree-kill@1.2.2: 1126 | resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} 1127 | hasBin: true 1128 | dev: true 1129 | 1130 | /ts-interface-checker@0.1.13: 1131 | resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} 1132 | dev: true 1133 | 1134 | /tsup@8.0.1(typescript@5.3.3): 1135 | resolution: {integrity: sha512-hvW7gUSG96j53ZTSlT4j/KL0q1Q2l6TqGBFc6/mu/L46IoNWqLLUzLRLP1R8Q7xrJTmkDxxDoojV5uCVs1sVOg==} 1136 | engines: {node: '>=18'} 1137 | hasBin: true 1138 | peerDependencies: 1139 | '@microsoft/api-extractor': ^7.36.0 1140 | '@swc/core': ^1 1141 | postcss: ^8.4.12 1142 | typescript: '>=4.5.0' 1143 | peerDependenciesMeta: 1144 | '@microsoft/api-extractor': 1145 | optional: true 1146 | '@swc/core': 1147 | optional: true 1148 | postcss: 1149 | optional: true 1150 | typescript: 1151 | optional: true 1152 | dependencies: 1153 | bundle-require: 4.0.2(esbuild@0.19.11) 1154 | cac: 6.7.14 1155 | chokidar: 3.5.3 1156 | debug: 4.3.4 1157 | esbuild: 0.19.11 1158 | execa: 5.1.1 1159 | globby: 11.1.0 1160 | joycon: 3.1.1 1161 | postcss-load-config: 4.0.2 1162 | resolve-from: 5.0.0 1163 | rollup: 4.9.4 1164 | source-map: 0.8.0-beta.0 1165 | sucrase: 3.35.0 1166 | tree-kill: 1.2.2 1167 | typescript: 5.3.3 1168 | transitivePeerDependencies: 1169 | - supports-color 1170 | - ts-node 1171 | dev: true 1172 | 1173 | /typescript@5.3.3: 1174 | resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==} 1175 | engines: {node: '>=14.17'} 1176 | hasBin: true 1177 | dev: true 1178 | 1179 | /webidl-conversions@4.0.2: 1180 | resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} 1181 | dev: true 1182 | 1183 | /whatwg-url@7.1.0: 1184 | resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==} 1185 | dependencies: 1186 | lodash.sortby: 4.7.0 1187 | tr46: 1.0.1 1188 | webidl-conversions: 4.0.2 1189 | dev: true 1190 | 1191 | /which@2.0.2: 1192 | resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} 1193 | engines: {node: '>= 8'} 1194 | hasBin: true 1195 | dependencies: 1196 | isexe: 2.0.0 1197 | dev: true 1198 | 1199 | /wrap-ansi@7.0.0: 1200 | resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} 1201 | engines: {node: '>=10'} 1202 | dependencies: 1203 | ansi-styles: 4.3.0 1204 | string-width: 4.2.3 1205 | strip-ansi: 6.0.1 1206 | dev: true 1207 | 1208 | /wrap-ansi@8.1.0: 1209 | resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} 1210 | engines: {node: '>=12'} 1211 | dependencies: 1212 | ansi-styles: 6.2.1 1213 | string-width: 5.1.2 1214 | strip-ansi: 7.1.0 1215 | dev: true 1216 | 1217 | /yaml@2.3.4: 1218 | resolution: {integrity: sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==} 1219 | engines: {node: '>= 14'} 1220 | dev: true 1221 | -------------------------------------------------------------------------------- /src/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { ComponentProps, useCallback, useEffect, useMemo, useRef, useState } from 'react'; 2 | import Draggable, { DraggableEventHandler } from 'react-draggable'; 3 | import { harmonies, hsv2rgb, hsv2xy, polar2xy, rad2deg, xy2polar, xy2rgb } from './utils'; 4 | 5 | export * from './utils' 6 | 7 | export type ColorWheelProps = Omit, 'color'> & { 8 | radius: number 9 | harmony: keyof typeof harmonies; 10 | color?: {hue: number, saturation: number, value: number}; 11 | defaultColor?: {hue: number, saturation: number, value: number}; 12 | onChange?: (colors: { hue: number; saturation: number; value: number }[]) => void; 13 | } 14 | 15 | export const ColorWheel = ({ radius, harmony: harmonyName, color, defaultColor, onChange, ...props }: ColorWheelProps) => { 16 | const ref = useRef(null); 17 | const [position, setPosition] = useState(defaultColor ? hsv2xy(defaultColor.hue, defaultColor.saturation, defaultColor.value, radius) : hsv2xy(0, 1, 1, radius)); 18 | const harmony = useMemo(() => harmonies[harmonyName], [harmonies, harmonyName]); 19 | 20 | useEffect(() => { 21 | if (!ref.current) return; 22 | const ctx = ref.current.getContext('2d'); 23 | 24 | if (!ctx) return; 25 | 26 | ctx.canvas.width = radius * 2 27 | ctx.canvas.height = radius * 2 28 | 29 | drawCircle(ctx); 30 | }, []); 31 | 32 | useEffect(() => { 33 | if (color) { 34 | setPosition(hsv2xy(color.hue, color.saturation, color.value, radius)) 35 | } 36 | }, [color, radius]) 37 | 38 | const handleDrag: DraggableEventHandler = useCallback((e, data) => { 39 | if (!ref.current) return; 40 | 41 | e.stopPropagation() 42 | e.preventDefault() 43 | 44 | let [r, phi] = xy2polar(data.x - radius, data.y - radius); 45 | // Limit radial distance to radius 46 | r = Math.min(r, radius); 47 | const [x, y] = polar2xy(r, phi); 48 | setPosition({ x: x + radius, y: y + radius }); 49 | }, [radius]); 50 | 51 | const harmonyPairs = useMemo(() => { 52 | const x = position.x - radius; 53 | const y = position.y - radius; 54 | 55 | const [r, phi] = xy2polar(x, y); 56 | 57 | const hue = rad2deg(phi); 58 | const saturation = r / radius; 59 | const value = 1.0; 60 | 61 | const colors = harmony.map(harmonyHue => { 62 | let newHue = (hue + harmonyHue) % 360; 63 | newHue = newHue < 0 ? 360 + newHue : newHue; 64 | 65 | const [x, y] = polar2xy(r, newHue * (Math.PI / 180)); 66 | return { x: -x + radius, y: -y + radius, hue: newHue, saturation, value }; 67 | }); 68 | 69 | onChange?.([{ hue, saturation, value }, ...colors]); 70 | 71 | return colors; 72 | }, [position, harmony, polar2xy, onChange, xy2polar, rad2deg, radius]); 73 | 74 | 75 | const drawCircle = useCallback((ctx: CanvasRenderingContext2D) => { 76 | let image = ctx.createImageData(2 * radius, 2 * radius); 77 | let data = image.data; 78 | 79 | for (let x = -radius; x < radius; x++) { 80 | for (let y = -radius; y < radius; y++) { 81 | let [r, phi] = xy2polar(x, y); 82 | 83 | let deg = rad2deg(phi); 84 | 85 | // Figure out the starting index of this pixel in the image data array. 86 | let rowLength = 2 * radius; 87 | let adjustedX = x + radius; // convert x from [-50, 50] to [0, 100] (the coordinates of the image data array) 88 | let adjustedY = y + radius; // convert y from [-50, 50] to [0, 100] (the coordinates of the image data array) 89 | let pixelWidth = 4; // each pixel requires 4 slots in the data array 90 | let index = (adjustedX + adjustedY * rowLength) * pixelWidth; 91 | 92 | let hue = deg; 93 | let saturation = r / radius; 94 | let value = 1.0; 95 | 96 | let [red, green, blue] = hsv2rgb(hue, saturation, value); 97 | let alpha = 255; 98 | 99 | data[index] = red; 100 | data[index + 1] = green; 101 | data[index + 2] = blue; 102 | data[index + 3] = alpha; 103 | } 104 | } 105 | 106 | ctx.putImageData(image, 0, 0); 107 | }, [radius]); 108 | 109 | const [r, g, b] = useMemo(() => xy2rgb(position.x, position.y, radius), [position, radius]); 110 | 111 | return ( 112 |
120 | 128 | {harmonyPairs.map((harmony, i) => { 129 | const [r, g, b] = hsv2rgb(harmony.hue, harmony.saturation, harmony.value); 130 | return ( 131 |
146 | ) 147 | })} 148 | 149 |
166 |
174 |
175 | 176 |
177 | ); 178 | }; 179 | -------------------------------------------------------------------------------- /src/utils.ts: -------------------------------------------------------------------------------- 1 | export const harmonies = { 2 | triad: [120, 240], 3 | tetradic: [60, 180, 240], 4 | complementary: [180], 5 | analogous: [-30, 30], 6 | square: [90, 180, 270] 7 | } as const; 8 | 9 | export const xy2polar = (x: number, y: number): [number, number] => { 10 | let r = Math.sqrt(x * x + y * y); 11 | let phi = Math.atan2(y, x); 12 | return [r, phi]; 13 | } 14 | 15 | export const polar2xy = (r: number, phi: number): [number, number] => { 16 | let x = r * Math.cos(phi); 17 | let y = r * Math.sin(phi); 18 | return [x, y]; 19 | } 20 | 21 | export const rad2deg = (rad: number) => { 22 | return ((rad + Math.PI) / (2 * Math.PI)) * 360; 23 | } 24 | 25 | export const deg2rad = (hue: number) => { 26 | return hue * (Math.PI / 180); 27 | } 28 | 29 | // hue in range [0, 360] 30 | // saturation, value in range [0,1] 31 | // return [r,g,b] each in range [0,255] 32 | // See: https://en.wikipedia.org/wiki/HSL_and_HSV#From_HSV 33 | export const hsv2rgb = (hue: number, saturation: number, value: number): [number, number, number] => { 34 | let chroma = value * saturation; 35 | let hue1 = hue / 60; 36 | let x = chroma * (1 - Math.abs((hue1 % 2) - 1)); 37 | let r1: number = 0, 38 | g1: number = 0, 39 | b1: number = 0; 40 | if (hue1 >= 0 && hue1 <= 1) { 41 | [r1, g1, b1] = [chroma, x, 0]; 42 | } else if (hue1 >= 1 && hue1 <= 2) { 43 | [r1, g1, b1] = [x, chroma, 0]; 44 | } else if (hue1 >= 2 && hue1 <= 3) { 45 | [r1, g1, b1] = [0, chroma, x]; 46 | } else if (hue1 >= 3 && hue1 <= 4) { 47 | [r1, g1, b1] = [0, x, chroma]; 48 | } else if (hue1 >= 4 && hue1 <= 5) { 49 | [r1, g1, b1] = [x, 0, chroma]; 50 | } else if (hue1 >= 5 && hue1 <= 6) { 51 | [r1, g1, b1] = [chroma, 0, x]; 52 | } 53 | 54 | let m = value - chroma; 55 | let [r, g, b] = [r1 + m, g1 + m, b1 + m]; 56 | 57 | // Change r,g,b values from [0,1] to [0,255] 58 | return [255 * r, 255 * g, 255 * b]; 59 | } 60 | 61 | export const xy2rgb = (x: number, y: number, radius: number) => { 62 | x -= radius; 63 | y -= radius; 64 | 65 | const [r, phi] = xy2polar(x, y); 66 | 67 | const hue = rad2deg(phi); 68 | const saturation = r / radius; 69 | const value = 1.0; 70 | 71 | return hsv2rgb(hue, saturation, value); 72 | } 73 | 74 | export const hsv2xy = (hue: number, saturation: number, value: number, radius: number) => { 75 | const adjustedHue = hue - 180; 76 | const [r, phi] = polar2xy(radius * saturation, deg2rad(adjustedHue)); 77 | return { 78 | x: r + radius, 79 | y: phi + radius 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "esModuleInterop": true, 4 | "jsx": "react-jsx", 5 | "module": "ESNext", 6 | "moduleResolution": "Bundler", 7 | "skipLibCheck": true, 8 | "strict": true, 9 | "noEmit": true 10 | }, 11 | "include": ["src/**/*"] 12 | } -------------------------------------------------------------------------------- /website/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /website/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | -------------------------------------------------------------------------------- /website/README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). 2 | 3 | ## Getting Started 4 | 5 | First, run the development server: 6 | 7 | ```bash 8 | npm run dev 9 | # or 10 | yarn dev 11 | # or 12 | pnpm dev 13 | # or 14 | bun dev 15 | ``` 16 | 17 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 18 | 19 | You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. 20 | 21 | This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. 22 | 23 | ## Learn More 24 | 25 | To learn more about Next.js, take a look at the following resources: 26 | 27 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 28 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 29 | 30 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 31 | 32 | ## Deploy on Vercel 33 | 34 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. 35 | 36 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. 37 | -------------------------------------------------------------------------------- /website/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {} 3 | 4 | module.exports = nextConfig 5 | -------------------------------------------------------------------------------- /website/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "harmony", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@newfrgmnt/harmony": "^1.0.3", 13 | "@vercel/analytics": "^1.1.1", 14 | "framer-motion": "^10.18.0", 15 | "next": "14.0.4", 16 | "react": "^18", 17 | "react-dom": "^18" 18 | }, 19 | "devDependencies": { 20 | "@types/node": "^20", 21 | "@types/react": "^18", 22 | "@types/react-dom": "^18", 23 | "autoprefixer": "^10.0.1", 24 | "eslint": "^8", 25 | "eslint-config-next": "14.0.4", 26 | "postcss": "^8", 27 | "tailwindcss": "^3.3.0", 28 | "typescript": "^5" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /website/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /website/public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /website/public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /website/src/app/ClientPage.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | /* eslint-disable */ 4 | import { ColorWheel, harmonies } from "@newfrgmnt/harmony"; 5 | /* @ts-ignore */ 6 | import { Gradient } from "../components/GradientMesh/GradientMesh"; 7 | import { useEffect, useMemo, useCallback, useState } from "react"; 8 | import { HTMLMotionProps, Variants, motion } from "framer-motion"; 9 | 10 | function HSVtoRGB(h: number, s: number, v: number) { 11 | var r, g, b, i, f, p, q, t; 12 | h = h / 360; 13 | i = Math.floor(h * 6); 14 | f = h * 6 - i; 15 | p = v * (1 - s); 16 | q = v * (1 - f * s); 17 | t = v * (1 - (1 - f) * s); 18 | switch (i % 6) { 19 | case 0: 20 | (r = v), (g = t), (b = p); 21 | break; 22 | case 1: 23 | (r = q), (g = v), (b = p); 24 | break; 25 | case 2: 26 | (r = p), (g = v), (b = t); 27 | break; 28 | case 3: 29 | (r = p), (g = q), (b = v); 30 | break; 31 | case 4: 32 | (r = t), (g = p), (b = v); 33 | break; 34 | case 5: 35 | (r = v), (g = p), (b = q); 36 | break; 37 | } 38 | return { 39 | r, 40 | g, 41 | b, 42 | }; 43 | } 44 | 45 | export default function App() { 46 | const [selectedHarmony, setSelectedHarmony] = 47 | useState("analogous"); 48 | const gradient = useMemo(() => new Gradient(), []); 49 | 50 | useEffect(() => { 51 | const root = document.documentElement; 52 | 53 | root.style.setProperty("--gradient-color-1", "#aaa"); 54 | root.style.setProperty("--gradient-color-2", "#ccc"); 55 | root.style.setProperty("--gradient-color-3", "#ddd"); 56 | root.style.setProperty("--gradient-color-4", "#fff"); 57 | 58 | /* @ts-ignore */ 59 | gradient.initGradient("#gradient-canvas"); 60 | }, [gradient]); 61 | 62 | /* @ts-ignore */ 63 | const handleColorChange = useCallback( 64 | /* @ts-ignore */ 65 | (colors) => { 66 | if (!gradient.material) { 67 | return setTimeout(() => handleColorChange(colors), 200); 68 | } 69 | 70 | /* @ts-ignore */ 71 | const newColors = colors 72 | /* @ts-ignore */ 73 | .map((color, i) => { 74 | const { r, g, b } = HSVtoRGB( 75 | color.hue, 76 | color.saturation, 77 | color.value 78 | ); 79 | return [r, g, b]; 80 | }); 81 | 82 | const [base, ...waves] = newColors; 83 | 84 | gradient.material.uniforms["u_baseColor"].value = base; 85 | 86 | for (const [index, wave] of Object.entries(waves)) { 87 | gradient.material.uniforms["u_waveLayers"].value[ 88 | index 89 | ].value.color.value = wave; 90 | } 91 | }, 92 | [gradient] 93 | ); 94 | 95 | return ( 96 |
106 | 117 | 118 | 127 | {" "} 128 | 129 |

130 | Harmony 131 |

132 |
133 |
134 |

135 | 136 | A new kind of 137 |
138 |
139 | Color Picker 140 |

141 | 142 |

143 | Unlock the power of color harmonies 144 |

145 |
146 | 147 |
148 | 149 | npm install @newfrgmnt/harmony 150 | 151 |
152 |
153 |
154 | 168 | 174 | 190 | 191 |
192 |
193 | ); 194 | } 195 | 196 | const variants: Variants = { 197 | initial: { 198 | y: "100%", 199 | }, 200 | animate: { 201 | y: "0%", 202 | transition: { 203 | duration: 1.5, 204 | ease: [0.75, 0, 0.25, 1], 205 | }, 206 | }, 207 | }; 208 | 209 | const TextReveal = ({ 210 | children, 211 | className, 212 | ...props 213 | }: HTMLMotionProps<"div">) => { 214 | return ( 215 | 216 | 217 | {children} 218 | 219 | 220 | ); 221 | }; 222 | -------------------------------------------------------------------------------- /website/src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emilwidlund/harmony/4858d4c305441f9ba54a0efab57cca3304757e6c/website/src/app/favicon.ico -------------------------------------------------------------------------------- /website/src/app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | :root { 6 | --foreground-rgb: 0, 0, 0; 7 | --background-start-rgb: 214, 219, 220; 8 | --background-end-rgb: 255, 255, 255; 9 | } 10 | 11 | @media (prefers-color-scheme: dark) { 12 | :root { 13 | --foreground-rgb: 255, 255, 255; 14 | --background-start-rgb: 0, 0, 0; 15 | --background-end-rgb: 0, 0, 0; 16 | } 17 | } 18 | 19 | body { 20 | color: #fff; 21 | background: linear-gradient( 22 | to bottom, 23 | transparent, 24 | rgb(var(--background-end-rgb)) 25 | ) 26 | rgb(var(--background-start-rgb)); 27 | } 28 | -------------------------------------------------------------------------------- /website/src/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import type { Metadata } from 'next' 2 | import { Inter } from 'next/font/google' 3 | import './globals.css' 4 | import { Analytics } from '@vercel/analytics/react'; 5 | 6 | const inter = Inter({ subsets: ['latin'] }) 7 | 8 | export const metadata: Metadata = { 9 | title: 'Create Next App', 10 | description: 'Generated by create next app', 11 | } 12 | 13 | export default function RootLayout({ 14 | children, 15 | }: { 16 | children: React.ReactNode 17 | }) { 18 | return ( 19 | 20 | {children} 21 | 22 | ) 23 | } 24 | -------------------------------------------------------------------------------- /website/src/app/page.tsx: -------------------------------------------------------------------------------- 1 | import { Metadata } from 'next' 2 | import ClientPage from './ClientPage' 3 | 4 | export const metadata: Metadata = { 5 | title: 'Harmony - A different kind of color picker', 6 | description: 'A color harmony picker for React', 7 | } 8 | 9 | export default function Page() { 10 | return 11 | } -------------------------------------------------------------------------------- /website/src/components/GradientMesh/GradientMesh.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Stripe WebGl Gradient Animation 3 | * All Credits to Stripe.com 4 | * ScrollObserver functionality to disable animation when not scrolled into view has been disabled and 5 | * commented out for now. 6 | * https://kevinhufnagl.com 7 | */ 8 | 9 | //Converting colors to proper format 10 | export function normalizeColor(hexCode) { 11 | return [ 12 | ((hexCode >> 16) & 255) / 255, 13 | ((hexCode >> 8) & 255) / 255, 14 | (255 & hexCode) / 255, 15 | ]; 16 | } 17 | ["SCREEN", "LINEAR_LIGHT"].reduce( 18 | (hexCode, t, n) => 19 | Object.assign(hexCode, { 20 | [t]: n, 21 | }), 22 | {}, 23 | ); 24 | 25 | //Essential functionality of WebGl 26 | //t = width 27 | //n = height 28 | class MiniGl { 29 | constructor(canvas, width, height, debug = false) { 30 | const _miniGl = this, 31 | debug_output = 32 | -1 !== document.location.search.toLowerCase().indexOf("debug=webgl"); 33 | (_miniGl.canvas = canvas), 34 | (_miniGl.gl = _miniGl.canvas.getContext("webgl", { 35 | antialias: true, 36 | })), 37 | (_miniGl.meshes = []); 38 | const context = _miniGl.gl; 39 | width && height && this.setSize(width, height), 40 | _miniGl.lastDebugMsg, 41 | (_miniGl.debug = 42 | debug && debug_output 43 | ? function (e) { 44 | const t = new Date(); 45 | t - _miniGl.lastDebugMsg > 1e3 && console.log("---"), 46 | console.log( 47 | t.toLocaleTimeString() + 48 | Array(Math.max(0, 32 - e.length)).join(" ") + 49 | e + 50 | ": ", 51 | ...Array.from(arguments).slice(1), 52 | ), 53 | (_miniGl.lastDebugMsg = t); 54 | } 55 | : () => {}), 56 | Object.defineProperties(_miniGl, { 57 | Material: { 58 | enumerable: false, 59 | value: class { 60 | constructor(vertexShaders, fragments, uniforms = {}) { 61 | const material = this; 62 | function getShaderByType(type, source) { 63 | const shader = context.createShader(type); 64 | return ( 65 | context.shaderSource(shader, source), 66 | context.compileShader(shader), 67 | context.getShaderParameter(shader, context.COMPILE_STATUS) || 68 | console.error(context.getShaderInfoLog(shader)), 69 | _miniGl.debug("Material.compileShaderSource", { 70 | source: source, 71 | }), 72 | shader 73 | ); 74 | } 75 | function getUniformVariableDeclarations(uniforms, type) { 76 | return Object.entries(uniforms) 77 | .map(([uniform, value]) => 78 | value.getDeclaration(uniform, type), 79 | ) 80 | .join("\n"); 81 | } 82 | (material.uniforms = uniforms), (material.uniformInstances = []); 83 | 84 | const prefix = 85 | "\n precision highp float;\n "; 86 | (material.vertexSource = `\n ${prefix}\n attribute vec4 position;\n attribute vec2 uv;\n attribute vec2 uvNorm;\n ${getUniformVariableDeclarations( 87 | _miniGl.commonUniforms, 88 | "vertex", 89 | )}\n ${getUniformVariableDeclarations( 90 | uniforms, 91 | "vertex", 92 | )}\n ${vertexShaders}\n `), 93 | (material.Source = `\n ${prefix}\n ${getUniformVariableDeclarations( 94 | _miniGl.commonUniforms, 95 | "fragment", 96 | )}\n ${getUniformVariableDeclarations( 97 | uniforms, 98 | "fragment", 99 | )}\n ${fragments}\n `), 100 | (material.vertexShader = getShaderByType( 101 | context.VERTEX_SHADER, 102 | material.vertexSource, 103 | )), 104 | (material.fragmentShader = getShaderByType( 105 | context.FRAGMENT_SHADER, 106 | material.Source, 107 | )), 108 | (material.program = context.createProgram()), 109 | context.attachShader(material.program, material.vertexShader), 110 | context.attachShader(material.program, material.fragmentShader), 111 | context.linkProgram(material.program), 112 | context.getProgramParameter( 113 | material.program, 114 | context.LINK_STATUS, 115 | ) || console.error(context.getProgramInfoLog(material.program)), 116 | context.useProgram(material.program), 117 | material.attachUniforms(void 0, _miniGl.commonUniforms), 118 | material.attachUniforms(void 0, material.uniforms); 119 | } 120 | //t = uniform 121 | attachUniforms(name, uniforms) { 122 | //n = material 123 | const material = this; 124 | void 0 === name 125 | ? Object.entries(uniforms).forEach(([name, uniform]) => { 126 | material.attachUniforms(name, uniform); 127 | }) 128 | : "array" == uniforms.type 129 | ? uniforms.value.forEach((uniform, i) => 130 | material.attachUniforms(`${name}[${i}]`, uniform), 131 | ) 132 | : "struct" == uniforms.type 133 | ? Object.entries(uniforms.value).forEach(([uniform, i]) => 134 | material.attachUniforms(`${name}.${uniform}`, i), 135 | ) 136 | : (_miniGl.debug("Material.attachUniforms", { 137 | name: name, 138 | uniform: uniforms, 139 | }), 140 | material.uniformInstances.push({ 141 | uniform: uniforms, 142 | location: context.getUniformLocation( 143 | material.program, 144 | name, 145 | ), 146 | })); 147 | } 148 | }, 149 | }, 150 | Uniform: { 151 | enumerable: !1, 152 | value: class { 153 | constructor(e) { 154 | (this.type = "float"), Object.assign(this, e); 155 | (this.typeFn = 156 | { 157 | float: "1f", 158 | int: "1i", 159 | vec2: "2fv", 160 | vec3: "3fv", 161 | vec4: "4fv", 162 | mat4: "Matrix4fv", 163 | }[this.type] || "1f"), 164 | this.update(); 165 | } 166 | update(value) { 167 | void 0 !== this.value && 168 | context[`uniform${this.typeFn}`]( 169 | value, 170 | 0 === this.typeFn.indexOf("Matrix") 171 | ? this.transpose 172 | : this.value, 173 | 0 === this.typeFn.indexOf("Matrix") ? this.value : null, 174 | ); 175 | } 176 | //e - name 177 | //t - type 178 | //n - length 179 | getDeclaration(name, type, length) { 180 | const uniform = this; 181 | if (uniform.excludeFrom !== type) { 182 | if ("array" === uniform.type) 183 | return ( 184 | uniform.value[0].getDeclaration( 185 | name, 186 | type, 187 | uniform.value.length, 188 | ) + `\nconst int ${name}_length = ${uniform.value.length};` 189 | ); 190 | if ("struct" === uniform.type) { 191 | let name_no_prefix = name.replace("u_", ""); 192 | return ( 193 | (name_no_prefix = 194 | name_no_prefix.charAt(0).toUpperCase() + 195 | name_no_prefix.slice(1)), 196 | `uniform struct ${name_no_prefix} 197 | {\n` + 198 | Object.entries(uniform.value) 199 | .map(([name, uniform]) => 200 | uniform 201 | .getDeclaration(name, type) 202 | .replace(/^uniform/, ""), 203 | ) 204 | .join("") + 205 | `\n} ${name}${length > 0 ? `[${length}]` : ""};` 206 | ); 207 | } 208 | return `uniform ${uniform.type} ${name}${ 209 | length > 0 ? `[${length}]` : "" 210 | };`; 211 | } 212 | } 213 | }, 214 | }, 215 | PlaneGeometry: { 216 | enumerable: !1, 217 | value: class { 218 | constructor(width, height, n, i, orientation) { 219 | context.createBuffer(), 220 | (this.attributes = { 221 | position: new _miniGl.Attribute({ 222 | target: context.ARRAY_BUFFER, 223 | size: 3, 224 | }), 225 | uv: new _miniGl.Attribute({ 226 | target: context.ARRAY_BUFFER, 227 | size: 2, 228 | }), 229 | uvNorm: new _miniGl.Attribute({ 230 | target: context.ARRAY_BUFFER, 231 | size: 2, 232 | }), 233 | index: new _miniGl.Attribute({ 234 | target: context.ELEMENT_ARRAY_BUFFER, 235 | size: 3, 236 | type: context.UNSIGNED_SHORT, 237 | }), 238 | }), 239 | this.setTopology(n, i), 240 | this.setSize(width, height, orientation); 241 | } 242 | setTopology(e = 1, t = 1) { 243 | const n = this; 244 | (n.xSegCount = e), 245 | (n.ySegCount = t), 246 | (n.vertexCount = (n.xSegCount + 1) * (n.ySegCount + 1)), 247 | (n.quadCount = n.xSegCount * n.ySegCount * 2), 248 | (n.attributes.uv.values = new Float32Array(2 * n.vertexCount)), 249 | (n.attributes.uvNorm.values = new Float32Array( 250 | 2 * n.vertexCount, 251 | )), 252 | (n.attributes.index.values = new Uint16Array(3 * n.quadCount)); 253 | for (let e = 0; e <= n.ySegCount; e++) 254 | for (let t = 0; t <= n.xSegCount; t++) { 255 | const i = e * (n.xSegCount + 1) + t; 256 | if ( 257 | ((n.attributes.uv.values[2 * i] = t / n.xSegCount), 258 | (n.attributes.uv.values[2 * i + 1] = 1 - e / n.ySegCount), 259 | (n.attributes.uvNorm.values[2 * i] = 260 | (t / n.xSegCount) * 2 - 1), 261 | (n.attributes.uvNorm.values[2 * i + 1] = 262 | 1 - (e / n.ySegCount) * 2), 263 | t < n.xSegCount && e < n.ySegCount) 264 | ) { 265 | const s = e * n.xSegCount + t; 266 | (n.attributes.index.values[6 * s] = i), 267 | (n.attributes.index.values[6 * s + 1] = 268 | i + 1 + n.xSegCount), 269 | (n.attributes.index.values[6 * s + 2] = i + 1), 270 | (n.attributes.index.values[6 * s + 3] = i + 1), 271 | (n.attributes.index.values[6 * s + 4] = 272 | i + 1 + n.xSegCount), 273 | (n.attributes.index.values[6 * s + 5] = 274 | i + 2 + n.xSegCount); 275 | } 276 | } 277 | n.attributes.uv.update(), 278 | n.attributes.uvNorm.update(), 279 | n.attributes.index.update(), 280 | _miniGl.debug("Geometry.setTopology", { 281 | uv: n.attributes.uv, 282 | uvNorm: n.attributes.uvNorm, 283 | index: n.attributes.index, 284 | }); 285 | } 286 | setSize(width = 1, height = 1, orientation = "xz") { 287 | const geometry = this; 288 | (geometry.width = width), 289 | (geometry.height = height), 290 | (geometry.orientation = orientation), 291 | (geometry.attributes.position.values && 292 | geometry.attributes.position.values.length === 293 | 3 * geometry.vertexCount) || 294 | (geometry.attributes.position.values = new Float32Array( 295 | 3 * geometry.vertexCount, 296 | )); 297 | const o = width / -2, 298 | r = height / -2, 299 | segment_width = width / geometry.xSegCount, 300 | segment_height = height / geometry.ySegCount; 301 | for (let yIndex = 0; yIndex <= geometry.ySegCount; yIndex++) { 302 | const t = r + yIndex * segment_height; 303 | for (let xIndex = 0; xIndex <= geometry.xSegCount; xIndex++) { 304 | const r = o + xIndex * segment_width, 305 | l = yIndex * (geometry.xSegCount + 1) + xIndex; 306 | (geometry.attributes.position.values[ 307 | 3 * l + "xyz".indexOf(orientation[0]) 308 | ] = r), 309 | (geometry.attributes.position.values[ 310 | 3 * l + "xyz".indexOf(orientation[1]) 311 | ] = -t); 312 | } 313 | } 314 | geometry.attributes.position.update(), 315 | _miniGl.debug("Geometry.setSize", { 316 | position: geometry.attributes.position, 317 | }); 318 | } 319 | }, 320 | }, 321 | Mesh: { 322 | enumerable: !1, 323 | value: class { 324 | constructor(geometry, material) { 325 | const mesh = this; 326 | (mesh.geometry = geometry), 327 | (mesh.material = material), 328 | (mesh.wireframe = !1), 329 | (mesh.attributeInstances = []), 330 | Object.entries(mesh.geometry.attributes).forEach( 331 | ([e, attribute]) => { 332 | mesh.attributeInstances.push({ 333 | attribute: attribute, 334 | location: attribute.attach(e, mesh.material.program), 335 | }); 336 | }, 337 | ), 338 | _miniGl.meshes.push(mesh), 339 | _miniGl.debug("Mesh.constructor", { 340 | mesh: mesh, 341 | }); 342 | } 343 | draw() { 344 | context.useProgram(this.material.program), 345 | this.material.uniformInstances.forEach( 346 | ({ uniform: e, location: t }) => e.update(t), 347 | ), 348 | this.attributeInstances.forEach( 349 | ({ attribute: e, location: t }) => e.use(t), 350 | ), 351 | context.drawElements( 352 | this.wireframe ? context.LINES : context.TRIANGLES, 353 | this.geometry.attributes.index.values.length, 354 | context.UNSIGNED_SHORT, 355 | 0, 356 | ); 357 | } 358 | remove() { 359 | _miniGl.meshes = _miniGl.meshes.filter((e) => e != this); 360 | } 361 | }, 362 | }, 363 | Attribute: { 364 | enumerable: !1, 365 | value: class { 366 | constructor(e) { 367 | (this.type = context.FLOAT), 368 | (this.normalized = !1), 369 | (this.buffer = context.createBuffer()), 370 | Object.assign(this, e), 371 | this.update(); 372 | } 373 | update() { 374 | void 0 !== this.values && 375 | (context.bindBuffer(this.target, this.buffer), 376 | context.bufferData( 377 | this.target, 378 | this.values, 379 | context.STATIC_DRAW, 380 | )); 381 | } 382 | attach(e, t) { 383 | const n = context.getAttribLocation(t, e); 384 | return ( 385 | this.target === context.ARRAY_BUFFER && 386 | (context.enableVertexAttribArray(n), 387 | context.vertexAttribPointer( 388 | n, 389 | this.size, 390 | this.type, 391 | this.normalized, 392 | 0, 393 | 0, 394 | )), 395 | n 396 | ); 397 | } 398 | use(e) { 399 | context.bindBuffer(this.target, this.buffer), 400 | this.target === context.ARRAY_BUFFER && 401 | (context.enableVertexAttribArray(e), 402 | context.vertexAttribPointer( 403 | e, 404 | this.size, 405 | this.type, 406 | this.normalized, 407 | 0, 408 | 0, 409 | )); 410 | } 411 | }, 412 | }, 413 | }); 414 | const a = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]; 415 | _miniGl.commonUniforms = { 416 | projectionMatrix: new _miniGl.Uniform({ 417 | type: "mat4", 418 | value: a, 419 | }), 420 | modelViewMatrix: new _miniGl.Uniform({ 421 | type: "mat4", 422 | value: a, 423 | }), 424 | resolution: new _miniGl.Uniform({ 425 | type: "vec2", 426 | value: [1, 1], 427 | }), 428 | aspectRatio: new _miniGl.Uniform({ 429 | type: "float", 430 | value: 1, 431 | }), 432 | }; 433 | } 434 | setSize(e = 640, t = 480) { 435 | (this.width = e), 436 | (this.height = t), 437 | (this.canvas.width = e), 438 | (this.canvas.height = t), 439 | this.gl.viewport(0, 0, e, t), 440 | (this.commonUniforms.resolution.value = [e, t]), 441 | (this.commonUniforms.aspectRatio.value = e / t), 442 | this.debug("MiniGL.setSize", { 443 | width: e, 444 | height: t, 445 | }); 446 | } 447 | //left, right, top, bottom, near, far 448 | setOrthographicCamera(e = 0, t = 0, n = 0, i = -2e3, s = 2e3) { 449 | (this.commonUniforms.projectionMatrix.value = [ 450 | 2 / this.width, 451 | 0, 452 | 0, 453 | 0, 454 | 0, 455 | 2 / this.height, 456 | 0, 457 | 0, 458 | 0, 459 | 0, 460 | 2 / (i - s), 461 | 0, 462 | e, 463 | t, 464 | n, 465 | 1, 466 | ]), 467 | this.debug( 468 | "setOrthographicCamera", 469 | this.commonUniforms.projectionMatrix.value, 470 | ); 471 | } 472 | render() { 473 | this.gl.clearColor(0, 0, 0, 0), 474 | this.gl.clearDepth(1), 475 | this.meshes.forEach((e) => e.draw()); 476 | } 477 | } 478 | 479 | //Sets initial properties 480 | function e(object, propertyName, val) { 481 | return ( 482 | propertyName in object 483 | ? Object.defineProperty(object, propertyName, { 484 | value: val, 485 | enumerable: !0, 486 | configurable: !0, 487 | writable: !0, 488 | }) 489 | : (object[propertyName] = val), 490 | object 491 | ); 492 | } 493 | 494 | //Gradient object 495 | class Gradient { 496 | constructor(...t) { 497 | e(this, "el", void 0), 498 | e(this, "cssVarRetries", 0), 499 | e(this, "maxCssVarRetries", 200), 500 | e(this, "angle", 0), 501 | e(this, "isLoadedClass", !1), 502 | e(this, "isScrolling", !1), 503 | /*e(this, "isStatic", o.disableAmbientAnimations()),*/ e( 504 | this, 505 | "scrollingTimeout", 506 | void 0, 507 | ), 508 | e(this, "scrollingRefreshDelay", 200), 509 | e(this, "isIntersecting", !1), 510 | e(this, "shaderFiles", void 0), 511 | e(this, "vertexShader", void 0), 512 | e(this, "sectionColors", void 0), 513 | e(this, "computedCanvasStyle", void 0), 514 | e(this, "conf", void 0), 515 | e(this, "uniforms", void 0), 516 | e(this, "t", 1355106), 517 | e(this, "last", 0), 518 | e(this, "width", void 0), 519 | e(this, "minWidth", 1111), 520 | e(this, "height", 600), 521 | e(this, "xSegCount", void 0), 522 | e(this, "ySegCount", void 0), 523 | e(this, "mesh", void 0), 524 | e(this, "material", void 0), 525 | e(this, "geometry", void 0), 526 | e(this, "minigl", void 0), 527 | e(this, "scrollObserver", void 0), 528 | e(this, "amp", 600), 529 | e(this, "seed", 11), 530 | e(this, "freqX", 14e-5), 531 | e(this, "freqY", 12e-5), 532 | e(this, "freqDelta", 1e-5), 533 | e(this, "activeColors", [1, 1, 1, 1]), 534 | e(this, "isMetaKey", !1), 535 | e(this, "isGradientLegendVisible", !1), 536 | e(this, "isMouseDown", !1), 537 | e(this, "handleScroll", () => { 538 | clearTimeout(this.scrollingTimeout), 539 | (this.scrollingTimeout = setTimeout( 540 | this.handleScrollEnd, 541 | this.scrollingRefreshDelay, 542 | )), 543 | this.isGradientLegendVisible && this.hideGradientLegend(), 544 | this.conf.playing && ((this.isScrolling = !0), this.pause()); 545 | }), 546 | e(this, "handleScrollEnd", () => { 547 | (this.isScrolling = !1), this.isIntersecting && this.play(); 548 | }), 549 | e(this, "resize", () => { 550 | (this.width = window.innerWidth), 551 | this.minigl.setSize(this.width, this.height), 552 | this.minigl.setOrthographicCamera(), 553 | (this.xSegCount = Math.ceil(this.width * this.conf.density[0])), 554 | (this.ySegCount = Math.ceil(this.height * this.conf.density[1])), 555 | this.mesh.geometry.setTopology(this.xSegCount, this.ySegCount), 556 | this.mesh.geometry.setSize(this.width, this.height), 557 | (this.mesh.material.uniforms.u_shadow_power.value = 558 | this.width < 600 ? 5 : 6); 559 | }), 560 | e(this, "handleMouseDown", (e) => { 561 | this.isGradientLegendVisible && 562 | ((this.isMetaKey = e.metaKey), 563 | (this.isMouseDown = !0), 564 | !1 === this.conf.playing && requestAnimationFrame(this.animate)); 565 | }), 566 | e(this, "handleMouseUp", () => { 567 | this.isMouseDown = !1; 568 | }), 569 | e(this, "animate", (e) => { 570 | if (!this.shouldSkipFrame(e) || this.isMouseDown) { 571 | if ( 572 | ((this.t += Math.min(e - this.last, 1e3 / 15)), 573 | (this.last = e), 574 | this.isMouseDown) 575 | ) { 576 | let e = 160; 577 | this.isMetaKey && (e = -160), (this.t += e); 578 | } 579 | (this.mesh.material.uniforms.u_time.value = this.t), 580 | this.minigl.render(); 581 | } 582 | if (0 !== this.last && this.isStatic) 583 | return this.minigl.render(), void this.disconnect(); 584 | /*this.isIntersecting && */ (this.conf.playing || this.isMouseDown) && 585 | requestAnimationFrame(this.animate); 586 | }), 587 | e(this, "addIsLoadedClass", () => { 588 | /*this.isIntersecting && */ !this.isLoadedClass && 589 | ((this.isLoadedClass = !0), 590 | this.el.classList.add("isLoaded"), 591 | setTimeout(() => { 592 | this.el.parentElement.classList.add("isLoaded"); 593 | }, 3e3)); 594 | }), 595 | e(this, "pause", () => { 596 | this.conf.playing = false; 597 | }), 598 | e(this, "play", () => { 599 | requestAnimationFrame(this.animate), (this.conf.playing = true); 600 | }), 601 | e(this, "initGradient", (selector) => { 602 | this.el = document.querySelector(selector); 603 | this.connect(); 604 | return this; 605 | }); 606 | } 607 | async connect() { 608 | (this.shaderFiles = { 609 | vertex: 610 | "varying vec3 v_color;\n\nvoid main() {\n float time = u_time * u_global.noiseSpeed;\n\n vec2 noiseCoord = resolution * uvNorm * u_global.noiseFreq;\n\n vec2 st = 1. - uvNorm.xy;\n\n //\n // Tilting the plane\n //\n\n // Front-to-back tilt\n float tilt = resolution.y / 2.0 * uvNorm.y;\n\n // Left-to-right angle\n float incline = resolution.x * uvNorm.x / 2.0 * u_vertDeform.incline;\n\n // Up-down shift to offset incline\n float offset = resolution.x / 2.0 * u_vertDeform.incline * mix(u_vertDeform.offsetBottom, u_vertDeform.offsetTop, uv.y);\n\n //\n // Vertex noise\n //\n\n float noise = snoise(vec3(\n noiseCoord.x * u_vertDeform.noiseFreq.x + time * u_vertDeform.noiseFlow,\n noiseCoord.y * u_vertDeform.noiseFreq.y,\n time * u_vertDeform.noiseSpeed + u_vertDeform.noiseSeed\n )) * u_vertDeform.noiseAmp;\n\n // Fade noise to zero at edges\n noise *= 1.0 - pow(abs(uvNorm.y), 2.0);\n\n // Clamp to 0\n noise = max(0.0, noise);\n\n vec3 pos = vec3(\n position.x,\n position.y + tilt + incline + noise - offset,\n position.z\n );\n\n //\n // Vertex color, to be passed to fragment shader\n //\n\n if (u_active_colors[0] == 1.) {\n v_color = u_baseColor;\n }\n\n for (int i = 0; i < u_waveLayers_length; i++) {\n if (u_active_colors[i + 1] == 1.) {\n WaveLayers layer = u_waveLayers[i];\n\n float noise = smoothstep(\n layer.noiseFloor,\n layer.noiseCeil,\n snoise(vec3(\n noiseCoord.x * layer.noiseFreq.x + time * layer.noiseFlow,\n noiseCoord.y * layer.noiseFreq.y,\n time * layer.noiseSpeed + layer.noiseSeed\n )) / 2.0 + 0.5\n );\n\n v_color = blendNormal(v_color, layer.color, pow(noise, 4.));\n }\n }\n\n //\n // Finish\n //\n\n gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);\n}", 611 | noise: 612 | "//\n// Description : Array and textureless GLSL 2D/3D/4D simplex\n// noise functions.\n// Author : Ian McEwan, Ashima Arts.\n// Maintainer : stegu\n// Lastmod : 20110822 (ijm)\n// License : Copyright (C) 2011 Ashima Arts. All rights reserved.\n// Distributed under the MIT License. See LICENSE file.\n// https://github.com/ashima/webgl-noise\n// https://github.com/stegu/webgl-noise\n//\n\nvec3 mod289(vec3 x) {\n return x - floor(x * (1.0 / 289.0)) * 289.0;\n}\n\nvec4 mod289(vec4 x) {\n return x - floor(x * (1.0 / 289.0)) * 289.0;\n}\n\nvec4 permute(vec4 x) {\n return mod289(((x*34.0)+1.0)*x);\n}\n\nvec4 taylorInvSqrt(vec4 r)\n{\n return 1.79284291400159 - 0.85373472095314 * r;\n}\n\nfloat snoise(vec3 v)\n{\n const vec2 C = vec2(1.0/6.0, 1.0/3.0) ;\n const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);\n\n// First corner\n vec3 i = floor(v + dot(v, C.yyy) );\n vec3 x0 = v - i + dot(i, C.xxx) ;\n\n// Other corners\n vec3 g = step(x0.yzx, x0.xyz);\n vec3 l = 1.0 - g;\n vec3 i1 = min( g.xyz, l.zxy );\n vec3 i2 = max( g.xyz, l.zxy );\n\n // x0 = x0 - 0.0 + 0.0 * C.xxx;\n // x1 = x0 - i1 + 1.0 * C.xxx;\n // x2 = x0 - i2 + 2.0 * C.xxx;\n // x3 = x0 - 1.0 + 3.0 * C.xxx;\n vec3 x1 = x0 - i1 + C.xxx;\n vec3 x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y\n vec3 x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y\n\n// Permutations\n i = mod289(i);\n vec4 p = permute( permute( permute(\n i.z + vec4(0.0, i1.z, i2.z, 1.0 ))\n + i.y + vec4(0.0, i1.y, i2.y, 1.0 ))\n + i.x + vec4(0.0, i1.x, i2.x, 1.0 ));\n\n// Gradients: 7x7 points over a square, mapped onto an octahedron.\n// The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294)\n float n_ = 0.142857142857; // 1.0/7.0\n vec3 ns = n_ * D.wyz - D.xzx;\n\n vec4 j = p - 49.0 * floor(p * ns.z * ns.z); // mod(p,7*7)\n\n vec4 x_ = floor(j * ns.z);\n vec4 y_ = floor(j - 7.0 * x_ ); // mod(j,N)\n\n vec4 x = x_ *ns.x + ns.yyyy;\n vec4 y = y_ *ns.x + ns.yyyy;\n vec4 h = 1.0 - abs(x) - abs(y);\n\n vec4 b0 = vec4( x.xy, y.xy );\n vec4 b1 = vec4( x.zw, y.zw );\n\n //vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0;\n //vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0;\n vec4 s0 = floor(b0)*2.0 + 1.0;\n vec4 s1 = floor(b1)*2.0 + 1.0;\n vec4 sh = -step(h, vec4(0.0));\n\n vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy ;\n vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww ;\n\n vec3 p0 = vec3(a0.xy,h.x);\n vec3 p1 = vec3(a0.zw,h.y);\n vec3 p2 = vec3(a1.xy,h.z);\n vec3 p3 = vec3(a1.zw,h.w);\n\n//Normalise gradients\n vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3)));\n p0 *= norm.x;\n p1 *= norm.y;\n p2 *= norm.z;\n p3 *= norm.w;\n\n// Mix final noise value\n vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0);\n m = m * m;\n return 42.0 * dot( m*m, vec4( dot(p0,x0), dot(p1,x1),\n dot(p2,x2), dot(p3,x3) ) );\n}", 613 | blend: 614 | "//\n// https://github.com/jamieowen/glsl-blend\n//\n\n// Normal\n\nvec3 blendNormal(vec3 base, vec3 blend) {\n\treturn blend;\n}\n\nvec3 blendNormal(vec3 base, vec3 blend, float opacity) {\n\treturn (blendNormal(base, blend) * opacity + base * (1.0 - opacity));\n}\n\n// Screen\n\nfloat blendScreen(float base, float blend) {\n\treturn 1.0-((1.0-base)*(1.0-blend));\n}\n\nvec3 blendScreen(vec3 base, vec3 blend) {\n\treturn vec3(blendScreen(base.r,blend.r),blendScreen(base.g,blend.g),blendScreen(base.b,blend.b));\n}\n\nvec3 blendScreen(vec3 base, vec3 blend, float opacity) {\n\treturn (blendScreen(base, blend) * opacity + base * (1.0 - opacity));\n}\n\n// Multiply\n\nvec3 blendMultiply(vec3 base, vec3 blend) {\n\treturn base*blend;\n}\n\nvec3 blendMultiply(vec3 base, vec3 blend, float opacity) {\n\treturn (blendMultiply(base, blend) * opacity + base * (1.0 - opacity));\n}\n\n// Overlay\n\nfloat blendOverlay(float base, float blend) {\n\treturn base<0.5?(2.0*base*blend):(1.0-2.0*(1.0-base)*(1.0-blend));\n}\n\nvec3 blendOverlay(vec3 base, vec3 blend) {\n\treturn vec3(blendOverlay(base.r,blend.r),blendOverlay(base.g,blend.g),blendOverlay(base.b,blend.b));\n}\n\nvec3 blendOverlay(vec3 base, vec3 blend, float opacity) {\n\treturn (blendOverlay(base, blend) * opacity + base * (1.0 - opacity));\n}\n\n// Hard light\n\nvec3 blendHardLight(vec3 base, vec3 blend) {\n\treturn blendOverlay(blend,base);\n}\n\nvec3 blendHardLight(vec3 base, vec3 blend, float opacity) {\n\treturn (blendHardLight(base, blend) * opacity + base * (1.0 - opacity));\n}\n\n// Soft light\n\nfloat blendSoftLight(float base, float blend) {\n\treturn (blend<0.5)?(2.0*base*blend+base*base*(1.0-2.0*blend)):(sqrt(base)*(2.0*blend-1.0)+2.0*base*(1.0-blend));\n}\n\nvec3 blendSoftLight(vec3 base, vec3 blend) {\n\treturn vec3(blendSoftLight(base.r,blend.r),blendSoftLight(base.g,blend.g),blendSoftLight(base.b,blend.b));\n}\n\nvec3 blendSoftLight(vec3 base, vec3 blend, float opacity) {\n\treturn (blendSoftLight(base, blend) * opacity + base * (1.0 - opacity));\n}\n\n// Color dodge\n\nfloat blendColorDodge(float base, float blend) {\n\treturn (blend==1.0)?blend:min(base/(1.0-blend),1.0);\n}\n\nvec3 blendColorDodge(vec3 base, vec3 blend) {\n\treturn vec3(blendColorDodge(base.r,blend.r),blendColorDodge(base.g,blend.g),blendColorDodge(base.b,blend.b));\n}\n\nvec3 blendColorDodge(vec3 base, vec3 blend, float opacity) {\n\treturn (blendColorDodge(base, blend) * opacity + base * (1.0 - opacity));\n}\n\n// Color burn\n\nfloat blendColorBurn(float base, float blend) {\n\treturn (blend==0.0)?blend:max((1.0-((1.0-base)/blend)),0.0);\n}\n\nvec3 blendColorBurn(vec3 base, vec3 blend) {\n\treturn vec3(blendColorBurn(base.r,blend.r),blendColorBurn(base.g,blend.g),blendColorBurn(base.b,blend.b));\n}\n\nvec3 blendColorBurn(vec3 base, vec3 blend, float opacity) {\n\treturn (blendColorBurn(base, blend) * opacity + base * (1.0 - opacity));\n}\n\n// Vivid Light\n\nfloat blendVividLight(float base, float blend) {\n\treturn (blend<0.5)?blendColorBurn(base,(2.0*blend)):blendColorDodge(base,(2.0*(blend-0.5)));\n}\n\nvec3 blendVividLight(vec3 base, vec3 blend) {\n\treturn vec3(blendVividLight(base.r,blend.r),blendVividLight(base.g,blend.g),blendVividLight(base.b,blend.b));\n}\n\nvec3 blendVividLight(vec3 base, vec3 blend, float opacity) {\n\treturn (blendVividLight(base, blend) * opacity + base * (1.0 - opacity));\n}\n\n// Lighten\n\nfloat blendLighten(float base, float blend) {\n\treturn max(blend,base);\n}\n\nvec3 blendLighten(vec3 base, vec3 blend) {\n\treturn vec3(blendLighten(base.r,blend.r),blendLighten(base.g,blend.g),blendLighten(base.b,blend.b));\n}\n\nvec3 blendLighten(vec3 base, vec3 blend, float opacity) {\n\treturn (blendLighten(base, blend) * opacity + base * (1.0 - opacity));\n}\n\n// Linear burn\n\nfloat blendLinearBurn(float base, float blend) {\n\t// Note : Same implementation as BlendSubtractf\n\treturn max(base+blend-1.0,0.0);\n}\n\nvec3 blendLinearBurn(vec3 base, vec3 blend) {\n\t// Note : Same implementation as BlendSubtract\n\treturn max(base+blend-vec3(1.0),vec3(0.0));\n}\n\nvec3 blendLinearBurn(vec3 base, vec3 blend, float opacity) {\n\treturn (blendLinearBurn(base, blend) * opacity + base * (1.0 - opacity));\n}\n\n// Linear dodge\n\nfloat blendLinearDodge(float base, float blend) {\n\t// Note : Same implementation as BlendAddf\n\treturn min(base+blend,1.0);\n}\n\nvec3 blendLinearDodge(vec3 base, vec3 blend) {\n\t// Note : Same implementation as BlendAdd\n\treturn min(base+blend,vec3(1.0));\n}\n\nvec3 blendLinearDodge(vec3 base, vec3 blend, float opacity) {\n\treturn (blendLinearDodge(base, blend) * opacity + base * (1.0 - opacity));\n}\n\n// Linear light\n\nfloat blendLinearLight(float base, float blend) {\n\treturn blend<0.5?blendLinearBurn(base,(2.0*blend)):blendLinearDodge(base,(2.0*(blend-0.5)));\n}\n\nvec3 blendLinearLight(vec3 base, vec3 blend) {\n\treturn vec3(blendLinearLight(base.r,blend.r),blendLinearLight(base.g,blend.g),blendLinearLight(base.b,blend.b));\n}\n\nvec3 blendLinearLight(vec3 base, vec3 blend, float opacity) {\n\treturn (blendLinearLight(base, blend) * opacity + base * (1.0 - opacity));\n}", 615 | fragment: 616 | "varying vec3 v_color;\n\nvoid main() {\n vec3 color = v_color;\n if (u_darken_top == 1.0) {\n vec2 st = gl_FragCoord.xy/resolution.xy;\n color.g -= pow(st.y + sin(-12.0) * st.x, u_shadow_power) * 0.4;\n }\n gl_FragColor = vec4(color, 1.0);\n}", 617 | }), 618 | (this.conf = { 619 | presetName: "", 620 | wireframe: false, 621 | density: [0.06, 0.16], 622 | zoom: 1, 623 | rotation: 0, 624 | playing: true, 625 | }), 626 | document.querySelectorAll("canvas").length < 1 627 | ? console.log("DID NOT LOAD HERO STRIPE CANVAS") 628 | : ((this.minigl = new MiniGl(this.el, null, null, !0)), 629 | requestAnimationFrame(() => { 630 | this.el && 631 | ((this.computedCanvasStyle = getComputedStyle(this.el)), 632 | this.waitForCssVars()); 633 | })); 634 | /* 635 | this.scrollObserver = await s.create(.1, !1), 636 | this.scrollObserver.observe(this.el), 637 | this.scrollObserver.onSeparate(() => { 638 | window.removeEventListener("scroll", this.handleScroll), window.removeEventListener("mousedown", this.handleMouseDown), window.removeEventListener("mouseup", this.handleMouseUp), window.removeEventListener("keydown", this.handleKeyDown), this.isIntersecting = !1, this.conf.playing && this.pause() 639 | }), 640 | this.scrollObserver.onIntersect(() => { 641 | window.addEventListener("scroll", this.handleScroll), window.addEventListener("mousedown", this.handleMouseDown), window.addEventListener("mouseup", this.handleMouseUp), window.addEventListener("keydown", this.handleKeyDown), this.isIntersecting = !0, this.addIsLoadedClass(), this.play() 642 | })*/ 643 | } 644 | disconnect() { 645 | this.scrollObserver && 646 | (window.removeEventListener("scroll", this.handleScroll), 647 | window.removeEventListener("mousedown", this.handleMouseDown), 648 | window.removeEventListener("mouseup", this.handleMouseUp), 649 | window.removeEventListener("keydown", this.handleKeyDown), 650 | this.scrollObserver.disconnect()), 651 | window.removeEventListener("resize", this.resize); 652 | } 653 | initMaterial() { 654 | this.uniforms = { 655 | u_time: new this.minigl.Uniform({ 656 | value: 0, 657 | }), 658 | u_shadow_power: new this.minigl.Uniform({ 659 | value: 5, 660 | }), 661 | u_darken_top: new this.minigl.Uniform({ 662 | value: "" === this.el.dataset.jsDarkenTop ? 1 : 0, 663 | }), 664 | u_active_colors: new this.minigl.Uniform({ 665 | value: this.activeColors, 666 | type: "vec4", 667 | }), 668 | u_global: new this.minigl.Uniform({ 669 | value: { 670 | noiseFreq: new this.minigl.Uniform({ 671 | value: [this.freqX, this.freqY], 672 | type: "vec2", 673 | }), 674 | noiseSpeed: new this.minigl.Uniform({ 675 | value: 5e-6, 676 | }), 677 | }, 678 | type: "struct", 679 | }), 680 | u_vertDeform: new this.minigl.Uniform({ 681 | value: { 682 | incline: new this.minigl.Uniform({ 683 | value: Math.sin(this.angle) / Math.cos(this.angle), 684 | }), 685 | offsetTop: new this.minigl.Uniform({ 686 | value: -0.5, 687 | }), 688 | offsetBottom: new this.minigl.Uniform({ 689 | value: -0.5, 690 | }), 691 | noiseFreq: new this.minigl.Uniform({ 692 | value: [3, 4], 693 | type: "vec2", 694 | }), 695 | noiseAmp: new this.minigl.Uniform({ 696 | value: this.amp, 697 | }), 698 | noiseSpeed: new this.minigl.Uniform({ 699 | value: 10, 700 | }), 701 | noiseFlow: new this.minigl.Uniform({ 702 | value: 3, 703 | }), 704 | noiseSeed: new this.minigl.Uniform({ 705 | value: this.seed, 706 | }), 707 | }, 708 | type: "struct", 709 | excludeFrom: "fragment", 710 | }), 711 | u_baseColor: new this.minigl.Uniform({ 712 | value: this.sectionColors[0], 713 | type: "vec3", 714 | excludeFrom: "fragment", 715 | }), 716 | u_waveLayers: new this.minigl.Uniform({ 717 | value: [], 718 | excludeFrom: "fragment", 719 | type: "array", 720 | }), 721 | }; 722 | for (let e = 1; e < this.sectionColors.length; e += 1) 723 | this.uniforms.u_waveLayers.value.push( 724 | new this.minigl.Uniform({ 725 | value: { 726 | color: new this.minigl.Uniform({ 727 | value: this.sectionColors[e], 728 | type: "vec3", 729 | }), 730 | noiseFreq: new this.minigl.Uniform({ 731 | value: [ 732 | 2 + e / this.sectionColors.length, 733 | 3 + e / this.sectionColors.length, 734 | ], 735 | type: "vec2", 736 | }), 737 | noiseSpeed: new this.minigl.Uniform({ 738 | value: 11 + 0.3 * e, 739 | }), 740 | noiseFlow: new this.minigl.Uniform({ 741 | value: 6.5 + 0.3 * e, 742 | }), 743 | noiseSeed: new this.minigl.Uniform({ 744 | value: this.seed + 10 * e, 745 | }), 746 | noiseFloor: new this.minigl.Uniform({ 747 | value: 0.1, 748 | }), 749 | noiseCeil: new this.minigl.Uniform({ 750 | value: 0.63 + 0.07 * e, 751 | }), 752 | }, 753 | type: "struct", 754 | }), 755 | ); 756 | return ( 757 | (this.vertexShader = [ 758 | this.shaderFiles.noise, 759 | this.shaderFiles.blend, 760 | this.shaderFiles.vertex, 761 | ].join("\n\n")), 762 | new this.minigl.Material( 763 | this.vertexShader, 764 | this.shaderFiles.fragment, 765 | this.uniforms, 766 | ) 767 | ); 768 | } 769 | initMesh() { 770 | (this.material = this.initMaterial()), 771 | (this.geometry = new this.minigl.PlaneGeometry()), 772 | (this.mesh = new this.minigl.Mesh(this.geometry, this.material)); 773 | } 774 | shouldSkipFrame(e) { 775 | return ( 776 | !!window.document.hidden || 777 | !this.conf.playing || 778 | parseInt(e, 10) % 2 == 0 || 779 | void 0 780 | ); 781 | } 782 | updateFrequency(e) { 783 | (this.freqX += e), (this.freqY += e); 784 | } 785 | toggleColor(index) { 786 | this.activeColors[index] = 0 === this.activeColors[index] ? 1 : 0; 787 | } 788 | showGradientLegend() { 789 | this.width > this.minWidth && 790 | ((this.isGradientLegendVisible = !0), 791 | document.body.classList.add("isGradientLegendVisible")); 792 | } 793 | hideGradientLegend() { 794 | (this.isGradientLegendVisible = !1), 795 | document.body.classList.remove("isGradientLegendVisible"); 796 | } 797 | init() { 798 | this.initGradientColors(), 799 | this.initMesh(), 800 | this.resize(), 801 | requestAnimationFrame(this.animate), 802 | window.addEventListener("resize", this.resize); 803 | } 804 | /* 805 | * Waiting for the css variables to become available, usually on page load before we can continue. 806 | * Using default colors assigned below if no variables have been found after maxCssVarRetries 807 | */ 808 | waitForCssVars() { 809 | if ( 810 | this.computedCanvasStyle && 811 | -1 !== 812 | this.computedCanvasStyle 813 | .getPropertyValue("--gradient-color-1") 814 | .indexOf("#") 815 | ) 816 | this.init(), this.addIsLoadedClass(); 817 | else { 818 | if ( 819 | ((this.cssVarRetries += 1), this.cssVarRetries > this.maxCssVarRetries) 820 | ) { 821 | return ( 822 | (this.sectionColors = [16711680, 16711680, 16711935, 65280, 255]), 823 | void this.init() 824 | ); 825 | } 826 | requestAnimationFrame(() => this.waitForCssVars()); 827 | } 828 | } 829 | /* 830 | * Initializes the four section colors by retrieving them from css variables. 831 | */ 832 | initGradientColors() { 833 | this.sectionColors = [ 834 | "--gradient-color-1", 835 | "--gradient-color-2", 836 | "--gradient-color-3", 837 | "--gradient-color-4", 838 | ] 839 | .map((cssPropertyName) => { 840 | let hex = this.computedCanvasStyle 841 | .getPropertyValue(cssPropertyName) 842 | .trim(); 843 | //Check if shorthand hex value was used and double the length so the conversion in normalizeColor will work. 844 | if (4 === hex.length) { 845 | const hexTemp = hex 846 | .substr(1) 847 | .split("") 848 | .map((hexTemp) => hexTemp + hexTemp) 849 | .join(""); 850 | hex = `#${hexTemp}`; 851 | } 852 | return hex && `0x${hex.substr(1)}`; 853 | }) 854 | .filter(Boolean) 855 | .map(normalizeColor); 856 | } 857 | } 858 | 859 | /* 860 | *Finally initializing the Gradient class, assigning a canvas to it and calling Gradient.connect() which initializes everything, 861 | * Use Gradient.pause() and Gradient.play() for controls. 862 | * 863 | * Here are some default property values you can change anytime: 864 | * Amplitude: Gradient.amp = 0 865 | * Colors: Gradient.sectionColors (if you change colors, use normalizeColor(#hexValue)) before you assign it. 866 | * 867 | * 868 | * Useful functions 869 | * Gradient.toggleColor(index) 870 | * Gradient.updateFrequency(freq) 871 | */ 872 | 873 | export { Gradient }; 874 | -------------------------------------------------------------------------------- /website/tailwind.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from 'tailwindcss' 2 | 3 | const config: Config = { 4 | content: [ 5 | './src/pages/**/*.{js,ts,jsx,tsx,mdx}', 6 | './src/components/**/*.{js,ts,jsx,tsx,mdx}', 7 | './src/app/**/*.{js,ts,jsx,tsx,mdx}', 8 | ], 9 | theme: { 10 | extend: { 11 | backgroundImage: { 12 | 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))', 13 | 'gradient-conic': 14 | 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))', 15 | }, 16 | }, 17 | }, 18 | plugins: [], 19 | } 20 | export default config 21 | -------------------------------------------------------------------------------- /website/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "noEmit": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "jsx": "preserve", 15 | "incremental": true, 16 | "plugins": [ 17 | { 18 | "name": "next" 19 | } 20 | ], 21 | "paths": { 22 | "@/*": ["./src/*"] 23 | } 24 | }, 25 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", "src/app/GradientMesh.js"], 26 | "exclude": ["node_modules"] 27 | } 28 | --------------------------------------------------------------------------------