From daa623fe7350c67ce7d2638bb20b85bf7b44fa97 Mon Sep 17 00:00:00 2001 From: root Date: Thu, 24 Sep 2026 21:37:40 +0200 Subject: [PATCH] =?UTF-8?q?feat(mesh-bg):=20fade-in=20=D1=88=D0=B5=D0=B9?= =?UTF-8?q?=D0=B4=D0=B5=D1=80=D0=B0=20=D1=84=D0=BE=D0=BD=D0=B0=20+=20modul?= =?UTF-8?q?epreload=20=D0=B3=D1=80=D0=B0=D1=84=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - canvas стартует с opacity:0 и плавно проявляется (0.9s) при .is-ready - initPageMeshShader ставит is-ready после первого кадра - modulepreload page-mesh-shader.js для параллельной загрузки с main.js - пересборка страниц (build:pages) --- AGENTS.md | 10 +- public/assets/index/resume-photo.png | Bin 0 -> 991450 bytes public/assets/index/resume-photo.webp | Bin 0 -> 90134 bytes public/cases/ai-assistant-figma/index.html | 3 +- .../cases/ai-platform-primo-rpa-2/index.html | 3 +- .../cases/ai-platform-primo-rpa-v2/index.html | 3 +- public/cases/ai-platform-primo-rpa/index.html | 3 +- public/cases/card-columns-obsidian/index.html | 3 +- public/cases/design-system/index.html | 1 + public/cases/lunacy/index.html | 3 +- public/cases/manu-game-maker/index.html | 3 +- .../cases/mini-projects-showcase/index.html | 1 + public/cases/mobile-clinic-app/index.html | 3 +- .../obsidian-plugin-columns-view/index.html | 3 +- public/cases/orc-automation-panel/index.html | 3 +- public/cases/site-with-ai-ide/index.html | 3 +- .../task-distribution-concept/index.html | 3 +- public/cases/task-tracker/index.html | 3 +- .../cases/template-elements-demo/index.html | 1 + public/cookie-policy/index.html | 1 + public/css/main.css | 8 +- public/en/cases/ai-assistant-figma/index.html | 3 +- .../cases/ai-platform-primo-rpa-2/index.html | 3 +- .../cases/ai-platform-primo-rpa-v2/index.html | 3 +- .../en/cases/ai-platform-primo-rpa/index.html | 3 +- .../en/cases/card-columns-obsidian/index.html | 3 +- public/en/cases/design-system/index.html | 1 + public/en/cases/lunacy/index.html | 3 +- public/en/cases/manu-game-maker/index.html | 3 +- .../cases/mini-projects-showcase/index.html | 1 + public/en/cases/mobile-clinic-app/index.html | 3 +- .../obsidian-plugin-columns-view/index.html | 3 +- .../en/cases/orc-automation-panel/index.html | 3 +- public/en/cases/site-with-ai-ide/index.html | 3 +- .../task-distribution-concept/index.html | 3 +- public/en/cases/task-tracker/index.html | 3 +- .../cases/template-elements-demo/index.html | 1 + public/en/cookie-policy/index.html | 1 + public/en/index.html | 1 + public/en/resume/index.html | 1 + public/index.html | 1 + .../ui/content-edit/content-edit-storage.js | 2 +- public/js/modules/ui/page-mesh-shader.js | 112 ++ public/resume/index.html | 1 + public/sitemap.xml | 32 +- public/vendor/paper-shaders/empty-pixel.d.ts | 1 + public/vendor/paper-shaders/empty-pixel.js | 10 + .../vendor/paper-shaders/empty-pixel.js.map | 7 + .../get-shader-color-from-string.d.ts | 3 + .../get-shader-color-from-string.js | 101 ++ .../get-shader-color-from-string.js.map | 7 + .../get-shader-noise-texture.d.ts | 1 + .../paper-shaders/get-shader-noise-texture.js | 18 + .../get-shader-noise-texture.js.map | 7 + public/vendor/paper-shaders/index.d.ts | 68 + public/vendor/paper-shaders/index.js | 189 +++ public/vendor/paper-shaders/index.js.map | 7 + .../paper-shaders/shader-color-spaces.d.ts | 6 + .../paper-shaders/shader-color-spaces.js | 96 ++ .../paper-shaders/shader-color-spaces.js.map | 7 + public/vendor/paper-shaders/shader-mount.d.ts | 140 ++ public/vendor/paper-shaders/shader-mount.js | 510 +++++++ .../vendor/paper-shaders/shader-mount.js.map | 7 + .../vendor/paper-shaders/shader-sizing.d.ts | 30 + public/vendor/paper-shaders/shader-sizing.js | 38 + .../vendor/paper-shaders/shader-sizing.js.map | 7 + public/vendor/paper-shaders/shader-utils.d.ts | 10 + public/vendor/paper-shaders/shader-utils.js | 131 ++ .../vendor/paper-shaders/shader-utils.js.map | 7 + .../paper-shaders/shaders/color-panels.d.ts | 70 + .../paper-shaders/shaders/color-panels.js | 224 +++ .../paper-shaders/shaders/color-panels.js.map | 7 + .../paper-shaders/shaders/dithering.d.ts | 62 + .../vendor/paper-shaders/shaders/dithering.js | 271 ++++ .../paper-shaders/shaders/dithering.js.map | 7 + .../paper-shaders/shaders/dot-grid.d.ts | 65 + .../vendor/paper-shaders/shaders/dot-grid.js | 110 ++ .../paper-shaders/shaders/dot-grid.js.map | 7 + .../paper-shaders/shaders/dot-orbit.d.ts | 57 + .../vendor/paper-shaders/shaders/dot-orbit.js | 123 ++ .../paper-shaders/shaders/dot-orbit.js.map | 7 + .../paper-shaders/shaders/fluted-glass.d.ts | 114 ++ .../paper-shaders/shaders/fluted-glass.js | 358 +++++ .../paper-shaders/shaders/fluted-glass.js.map | 7 + .../paper-shaders/shaders/gem-smoke.d.ts | 94 ++ .../vendor/paper-shaders/shaders/gem-smoke.js | 585 ++++++++ .../paper-shaders/shaders/gem-smoke.js.map | 7 + .../paper-shaders/shaders/god-rays.d.ts | 67 + .../vendor/paper-shaders/shaders/god-rays.js | 133 ++ .../paper-shaders/shaders/god-rays.js.map | 7 + .../paper-shaders/shaders/grain-gradient.d.ts | 82 ++ .../paper-shaders/shaders/grain-gradient.js | 303 ++++ .../shaders/grain-gradient.js.map | 7 + .../paper-shaders/shaders/halftone-cmyk.d.ts | 105 ++ .../paper-shaders/shaders/halftone-cmyk.js | 292 ++++ .../shaders/halftone-cmyk.js.map | 7 + .../paper-shaders/shaders/halftone-dots.d.ts | 82 ++ .../paper-shaders/shaders/halftone-dots.js | 321 +++++ .../shaders/halftone-dots.js.map | 7 + .../vendor/paper-shaders/shaders/heatmap.d.ts | 67 + .../vendor/paper-shaders/shaders/heatmap.js | 385 +++++ .../paper-shaders/shaders/heatmap.js.map | 7 + .../shaders/image-dithering.d.ts | 66 + .../paper-shaders/shaders/image-dithering.js | 201 +++ .../shaders/image-dithering.js.map | 7 + .../shaders/lens-distortion.d.ts | 97 ++ .../paper-shaders/shaders/lens-distortion.js | 276 ++++ .../shaders/lens-distortion.js.map | 7 + .../paper-shaders/shaders/liquid-metal.d.ts | 90 ++ .../paper-shaders/shaders/liquid-metal.js | 630 ++++++++ .../paper-shaders/shaders/liquid-metal.js.map | 7 + .../paper-shaders/shaders/mesh-gradient.d.ts | 52 + .../paper-shaders/shaders/mesh-gradient.js | 127 ++ .../shaders/mesh-gradient.js.map | 7 + .../paper-shaders/shaders/metaballs.d.ts | 51 + .../vendor/paper-shaders/shaders/metaballs.js | 112 ++ .../paper-shaders/shaders/metaballs.js.map | 7 + .../paper-shaders/shaders/neuro-noise.d.ts | 49 + .../paper-shaders/shaders/neuro-noise.js | 79 + .../paper-shaders/shaders/neuro-noise.js.map | 7 + .../paper-shaders/shaders/paper-texture.d.ts | 78 + .../paper-shaders/shaders/paper-texture.js | 248 ++++ .../shaders/paper-texture.js.map | 7 + .../paper-shaders/shaders/perlin-noise.d.ts | 52 + .../paper-shaders/shaders/perlin-noise.js | 173 +++ .../paper-shaders/shaders/perlin-noise.js.map | 7 + .../paper-shaders/shaders/pulsing-border.d.ts | 98 ++ .../paper-shaders/shaders/pulsing-border.js | 239 ++++ .../shaders/pulsing-border.js.map | 7 + .../paper-shaders/shaders/simplex-noise.d.ts | 46 + .../paper-shaders/shaders/simplex-noise.js | 100 ++ .../shaders/simplex-noise.js.map | 7 + .../paper-shaders/shaders/smoke-ring.d.ts | 61 + .../paper-shaders/shaders/smoke-ring.js | 133 ++ .../paper-shaders/shaders/smoke-ring.js.map | 7 + .../vendor/paper-shaders/shaders/spiral.d.ts | 61 + public/vendor/paper-shaders/shaders/spiral.js | 81 ++ .../paper-shaders/shaders/spiral.js.map | 7 + .../shaders/static-mesh-gradient.d.ts | 63 + .../shaders/static-mesh-gradient.js | 128 ++ .../shaders/static-mesh-gradient.js.map | 7 + .../shaders/static-radial-gradient.d.ts | 72 + .../shaders/static-radial-gradient.js | 184 +++ .../shaders/static-radial-gradient.js.map | 7 + .../vendor/paper-shaders/shaders/swirl.d.ts | 63 + public/vendor/paper-shaders/shaders/swirl.js | 102 ++ .../vendor/paper-shaders/shaders/swirl.js.map | 7 + .../vendor/paper-shaders/shaders/voronoi.d.ts | 65 + .../vendor/paper-shaders/shaders/voronoi.js | 139 ++ .../paper-shaders/shaders/voronoi.js.map | 7 + public/vendor/paper-shaders/shaders/warp.d.ts | 72 + public/vendor/paper-shaders/shaders/warp.js | 132 ++ .../vendor/paper-shaders/shaders/warp.js.map | 7 + .../vendor/paper-shaders/shaders/water.d.ts | 59 + public/vendor/paper-shaders/shaders/water.js | 120 ++ .../vendor/paper-shaders/shaders/water.js.map | 7 + .../vendor/paper-shaders/shaders/waves.d.ts | 53 + public/vendor/paper-shaders/shaders/waves.js | 66 + .../vendor/paper-shaders/shaders/waves.js.map | 7 + public/vendor/paper-shaders/types.d.ts | 3 + public/vendor/paper-shaders/types.js | 6 + public/vendor/paper-shaders/types.js.map | 7 + .../vendor/paper-shaders/vertex-shader.d.ts | 2 + public/vendor/paper-shaders/vertex-shader.js | 160 +++ .../vendor/paper-shaders/vertex-shader.js.map | 7 + scripts/serve-dev.mjs | 2 +- src/pages/resume.en.html | 1263 +++++++--------- src/pages/resume.html | 1265 +++++++---------- src/partials/head-links.html | 1 + texts/content-edits/pending.json | 2 +- 170 files changed, 11582 insertions(+), 1496 deletions(-) create mode 100644 public/assets/index/resume-photo.png create mode 100644 public/assets/index/resume-photo.webp create mode 100644 public/js/modules/ui/page-mesh-shader.js create mode 100644 public/vendor/paper-shaders/empty-pixel.d.ts create mode 100644 public/vendor/paper-shaders/empty-pixel.js create mode 100644 public/vendor/paper-shaders/empty-pixel.js.map create mode 100644 public/vendor/paper-shaders/get-shader-color-from-string.d.ts create mode 100644 public/vendor/paper-shaders/get-shader-color-from-string.js create mode 100644 public/vendor/paper-shaders/get-shader-color-from-string.js.map create mode 100644 public/vendor/paper-shaders/get-shader-noise-texture.d.ts create mode 100644 public/vendor/paper-shaders/get-shader-noise-texture.js create mode 100644 public/vendor/paper-shaders/get-shader-noise-texture.js.map create mode 100644 public/vendor/paper-shaders/index.d.ts create mode 100644 public/vendor/paper-shaders/index.js create mode 100644 public/vendor/paper-shaders/index.js.map create mode 100644 public/vendor/paper-shaders/shader-color-spaces.d.ts create mode 100644 public/vendor/paper-shaders/shader-color-spaces.js create mode 100644 public/vendor/paper-shaders/shader-color-spaces.js.map create mode 100644 public/vendor/paper-shaders/shader-mount.d.ts create mode 100644 public/vendor/paper-shaders/shader-mount.js create mode 100644 public/vendor/paper-shaders/shader-mount.js.map create mode 100644 public/vendor/paper-shaders/shader-sizing.d.ts create mode 100644 public/vendor/paper-shaders/shader-sizing.js create mode 100644 public/vendor/paper-shaders/shader-sizing.js.map create mode 100644 public/vendor/paper-shaders/shader-utils.d.ts create mode 100644 public/vendor/paper-shaders/shader-utils.js create mode 100644 public/vendor/paper-shaders/shader-utils.js.map create mode 100644 public/vendor/paper-shaders/shaders/color-panels.d.ts create mode 100644 public/vendor/paper-shaders/shaders/color-panels.js create mode 100644 public/vendor/paper-shaders/shaders/color-panels.js.map create mode 100644 public/vendor/paper-shaders/shaders/dithering.d.ts create mode 100644 public/vendor/paper-shaders/shaders/dithering.js create mode 100644 public/vendor/paper-shaders/shaders/dithering.js.map create mode 100644 public/vendor/paper-shaders/shaders/dot-grid.d.ts create mode 100644 public/vendor/paper-shaders/shaders/dot-grid.js create mode 100644 public/vendor/paper-shaders/shaders/dot-grid.js.map create mode 100644 public/vendor/paper-shaders/shaders/dot-orbit.d.ts create mode 100644 public/vendor/paper-shaders/shaders/dot-orbit.js create mode 100644 public/vendor/paper-shaders/shaders/dot-orbit.js.map create mode 100644 public/vendor/paper-shaders/shaders/fluted-glass.d.ts create mode 100644 public/vendor/paper-shaders/shaders/fluted-glass.js create mode 100644 public/vendor/paper-shaders/shaders/fluted-glass.js.map create mode 100644 public/vendor/paper-shaders/shaders/gem-smoke.d.ts create mode 100644 public/vendor/paper-shaders/shaders/gem-smoke.js create mode 100644 public/vendor/paper-shaders/shaders/gem-smoke.js.map create mode 100644 public/vendor/paper-shaders/shaders/god-rays.d.ts create mode 100644 public/vendor/paper-shaders/shaders/god-rays.js create mode 100644 public/vendor/paper-shaders/shaders/god-rays.js.map create mode 100644 public/vendor/paper-shaders/shaders/grain-gradient.d.ts create mode 100644 public/vendor/paper-shaders/shaders/grain-gradient.js create mode 100644 public/vendor/paper-shaders/shaders/grain-gradient.js.map create mode 100644 public/vendor/paper-shaders/shaders/halftone-cmyk.d.ts create mode 100644 public/vendor/paper-shaders/shaders/halftone-cmyk.js create mode 100644 public/vendor/paper-shaders/shaders/halftone-cmyk.js.map create mode 100644 public/vendor/paper-shaders/shaders/halftone-dots.d.ts create mode 100644 public/vendor/paper-shaders/shaders/halftone-dots.js create mode 100644 public/vendor/paper-shaders/shaders/halftone-dots.js.map create mode 100644 public/vendor/paper-shaders/shaders/heatmap.d.ts create mode 100644 public/vendor/paper-shaders/shaders/heatmap.js create mode 100644 public/vendor/paper-shaders/shaders/heatmap.js.map create mode 100644 public/vendor/paper-shaders/shaders/image-dithering.d.ts create mode 100644 public/vendor/paper-shaders/shaders/image-dithering.js create mode 100644 public/vendor/paper-shaders/shaders/image-dithering.js.map create mode 100644 public/vendor/paper-shaders/shaders/lens-distortion.d.ts create mode 100644 public/vendor/paper-shaders/shaders/lens-distortion.js create mode 100644 public/vendor/paper-shaders/shaders/lens-distortion.js.map create mode 100644 public/vendor/paper-shaders/shaders/liquid-metal.d.ts create mode 100644 public/vendor/paper-shaders/shaders/liquid-metal.js create mode 100644 public/vendor/paper-shaders/shaders/liquid-metal.js.map create mode 100644 public/vendor/paper-shaders/shaders/mesh-gradient.d.ts create mode 100644 public/vendor/paper-shaders/shaders/mesh-gradient.js create mode 100644 public/vendor/paper-shaders/shaders/mesh-gradient.js.map create mode 100644 public/vendor/paper-shaders/shaders/metaballs.d.ts create mode 100644 public/vendor/paper-shaders/shaders/metaballs.js create mode 100644 public/vendor/paper-shaders/shaders/metaballs.js.map create mode 100644 public/vendor/paper-shaders/shaders/neuro-noise.d.ts create mode 100644 public/vendor/paper-shaders/shaders/neuro-noise.js create mode 100644 public/vendor/paper-shaders/shaders/neuro-noise.js.map create mode 100644 public/vendor/paper-shaders/shaders/paper-texture.d.ts create mode 100644 public/vendor/paper-shaders/shaders/paper-texture.js create mode 100644 public/vendor/paper-shaders/shaders/paper-texture.js.map create mode 100644 public/vendor/paper-shaders/shaders/perlin-noise.d.ts create mode 100644 public/vendor/paper-shaders/shaders/perlin-noise.js create mode 100644 public/vendor/paper-shaders/shaders/perlin-noise.js.map create mode 100644 public/vendor/paper-shaders/shaders/pulsing-border.d.ts create mode 100644 public/vendor/paper-shaders/shaders/pulsing-border.js create mode 100644 public/vendor/paper-shaders/shaders/pulsing-border.js.map create mode 100644 public/vendor/paper-shaders/shaders/simplex-noise.d.ts create mode 100644 public/vendor/paper-shaders/shaders/simplex-noise.js create mode 100644 public/vendor/paper-shaders/shaders/simplex-noise.js.map create mode 100644 public/vendor/paper-shaders/shaders/smoke-ring.d.ts create mode 100644 public/vendor/paper-shaders/shaders/smoke-ring.js create mode 100644 public/vendor/paper-shaders/shaders/smoke-ring.js.map create mode 100644 public/vendor/paper-shaders/shaders/spiral.d.ts create mode 100644 public/vendor/paper-shaders/shaders/spiral.js create mode 100644 public/vendor/paper-shaders/shaders/spiral.js.map create mode 100644 public/vendor/paper-shaders/shaders/static-mesh-gradient.d.ts create mode 100644 public/vendor/paper-shaders/shaders/static-mesh-gradient.js create mode 100644 public/vendor/paper-shaders/shaders/static-mesh-gradient.js.map create mode 100644 public/vendor/paper-shaders/shaders/static-radial-gradient.d.ts create mode 100644 public/vendor/paper-shaders/shaders/static-radial-gradient.js create mode 100644 public/vendor/paper-shaders/shaders/static-radial-gradient.js.map create mode 100644 public/vendor/paper-shaders/shaders/swirl.d.ts create mode 100644 public/vendor/paper-shaders/shaders/swirl.js create mode 100644 public/vendor/paper-shaders/shaders/swirl.js.map create mode 100644 public/vendor/paper-shaders/shaders/voronoi.d.ts create mode 100644 public/vendor/paper-shaders/shaders/voronoi.js create mode 100644 public/vendor/paper-shaders/shaders/voronoi.js.map create mode 100644 public/vendor/paper-shaders/shaders/warp.d.ts create mode 100644 public/vendor/paper-shaders/shaders/warp.js create mode 100644 public/vendor/paper-shaders/shaders/warp.js.map create mode 100644 public/vendor/paper-shaders/shaders/water.d.ts create mode 100644 public/vendor/paper-shaders/shaders/water.js create mode 100644 public/vendor/paper-shaders/shaders/water.js.map create mode 100644 public/vendor/paper-shaders/shaders/waves.d.ts create mode 100644 public/vendor/paper-shaders/shaders/waves.js create mode 100644 public/vendor/paper-shaders/shaders/waves.js.map create mode 100644 public/vendor/paper-shaders/types.d.ts create mode 100644 public/vendor/paper-shaders/types.js create mode 100644 public/vendor/paper-shaders/types.js.map create mode 100644 public/vendor/paper-shaders/vertex-shader.d.ts create mode 100644 public/vendor/paper-shaders/vertex-shader.js create mode 100644 public/vendor/paper-shaders/vertex-shader.js.map diff --git a/AGENTS.md b/AGENTS.md index 1bcdcb7..06484ea 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,13 +2,19 @@ ## Сборка и деплой -Деплой автоматический: пуш в git → автодеплой на хостинг. +Деплой автоматический, но **только по пушу в ветку `main`** → автодеплой на хостинг. + +Пуш в любую другую ветку (включая `dev`) деплоя **не вызывает** — `dev` это обычная рабочая ветка, в неё можно пушить свободно. + +Правило коммитов: **после каждой правки делай локальный git commit** (без пуша, если не просили). Пуш — только по явному запросу пользователя, и для деплоя он должен идти в `main`. По запросу пользователя «собрать», «билд»: 1. При правках `src/pages/**` или `src/partials/**` — `npm run build:pages`. 2. При смене шрифтов/Plyr или `package.json` — `npm run build` (включает `vendor:copy`). -3. Для деплоя — сделать git commit + push. +3. Для деплоя — пуш в `main` (предварительно сделав commit). + +> Если пользователь просит «влить в мастер» — см. раздел «Влить в master» ниже. Это не то же самое, что пуш в `dev`. ## Git diff --git a/public/assets/index/resume-photo.png b/public/assets/index/resume-photo.png new file mode 100644 index 0000000000000000000000000000000000000000..7c3acfef432b4c1ff959bfcd23dd3c76a7834de5 GIT binary patch literal 991450 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
  • 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%0ANupj4G{d;*yz{E zDy5nNxSbP_-J#Ds!y{yP7`|qH)ZUIz6gu-ZljF4fXvBfs^5dTV5gfE=l?(`rSKN@` zLUtW`zkk(U1V=X<%2G9lW>V*YFj}1HKua~pzDJNOW`|Is*fZMdl_P$Q{-N$Q%n!vo z(V?e=sb-}aojX#A;Ik^}VR2lJ^KqOJE9ZttV$~Q32H} zdI`Dx=3muXkgT;B1MqpiZB&3|fVx`15L4|DY=vrYT6+Npk(L>-n1MC7TMQRKbo>G( zQFXz;xkiST?_Ap4!o0fN%YpM-j-vGp0@bP(l{L$r5xK^61JDWm&hmiHNJL+bfBJpmcp zXUHQX29YV-ly!nB!Z5%Fr=aQN=aeebl^7^ODWAe^hgzDOV<*?43sFjQp1jY{_J(}+ zeUh|L?$Uy|z8w&9&u0{g>FA46Y{>L+h3dyeaxVr&F2(0-pU|YP#c^)$#8{Canx}P1 z(&MK^1De7l431EzBOj8cgsieZC-VHWrlYWm&qSdFDlfJ~ZEREvy znIf^U9cE?=dy!;e{WrkQW<@fL?;6)6<0&N3QW+wJqX^(yIlk){4?80@dhu#7*D zz=>mf_XHM-G|Du}GK$92+j#kjb5y(n$*E!J=*M$BS&wpCkzQO*+bWz%C;m|iS6l&4 zYWdaW3Zaxu+%nWM-Z8<3u)k6GXYzOssT3Y=y;54I-(1$Mpf~}o1X=dz!?XmW(qY0T zrM<0Tut*4#ZuC)ZH(w(70q&x#ePbgPD?}Q;5zSKSH2;Tu+E_>n)fI0vQ!vUZfj~F<#nU!1Xo_+us`WMRCZr%J1VFvRWgDB#<-V4G6H&1 zy;8I5bqoPYKGnhsKL3b*SE#$4JFpugy_HQpuUe^BxU-|UZVU|ZY-4awIKleGDtVq+ zp_AJlI(WszG_0I+CP%e7UkxU*k*xgt^+^;DG=k*0xEWYx)9p1gS)OY*U$Gr`vW&ex z$dL{kpsA>#RPoVRJiJs*0CxkLY~x))Jz>e&h>F4BW8gRKqa5Pup~=0?i87sAr{Q8G zsSbMf5$Q{IDEetwjy(fy=hoiNdW|lMVFp_oltdnNmf=D*jnvJ%$*c;5*+a=-Qy>Qa zbep?QB&(NgBj9^nDP0&UjK-FyR?MJRUb#eg2+`HQoy-xZK3$!`EI<7cz}%uYSl-?r zRyle%C0w0epY)Kp{h~DT_OkyhhISXik{3PnRix!t2>{; zzS3C2z-#x_P5g}Okx!8WH*FYY>scLLV&rH<9qQNuDRX&7^MgE73EqV^eO%>Kisr;H z&TZP4gqFmR)dA(d()C5Ln}S;9k;1QRLK16KwNRV~)2I~0(Q!k|M9|e`+sNrkQ&C1= zuu{`B1@|8~ruL`YY}bz)SR#kY|j-oO_5cVd|L$GWXA-ZpNLp&2zo@c2F@E8#Sa) zY(o2@QOkdv(wNi)1=0m5tZ$x;9BDSGB{acx=_N-s7oO_NDj%1C%Pv^IJZ2eEOT?*y z*?eFoS$}-9L}Yu;LIoma?z8Vi)e$0w@1mnJ@?$h2Y(A52iaZNjadlnVBn)CecTq8^RdV}qhU1x>f{B1$IcQM&E%{?g-{0_;!O9-z&wRy|a;_qd1Lng-omVId=j zTpNYN+L@nFgq$Rw>@MiQv3Dx}^ES5yJ%m}jy`k#nBis>-ZaV~0Z?4U-4U&s0%3l~V zu_ME`-0lSB`svD6 z;_vIwh2LSBnmbT^^qyp0Dd%~|8u|u>TtW8voBK;?Gt#~0D1BKOFF5wV*-Q9OjzDGP zoL2+pTeMUs`HZ%rY3aonDBA_ZgG?226o3qK7P;zTmTS9@tCpJWbawxipn|k7mc9ur zp~S2FxTrU63VP(#BH%{%4GAkAc-0(BYMgz*Oc~s7Pw1a&L(Lv^eF}hA_F3Ps8J-1! zQ!y|*mb)pL84OI3R=K-F?zmA~L1G2Ku5NCW1NpI1n$C{LMATS6R;Fxo;zxfZW#^WX zma_Wjbl*_Py^W6&^;R~mboP*276q5PGf`_7-!?&xjlSD#C2kPugI+l|Dy1_tu0>Jr z&!Wt}$pG5lubx zEec}-Ep089<~uUwq{kzTE8y99Icnrb0RF1ri|@`4^PpTO8Zm9CYQo3cp)}dCK#*Y^ zPp%sbcZnaVl+*je7ni-TkvdAWp_u67MVzf{&+NBVt>9>o>5q&7Z(3h4s3*PPOVDIx0IO$%t5rhp-|EkArI27l_%UZ)=zbU{#ZQO-!__y8k8+`w%^o@Q$#4^wT0+!#IXNy2en zI^ntQ#NXywJ^e;&086nVxBm`RPhX!=aprZCkNs}yjdsG8mjUAn-<_>imeC*EqL!dH zW)6uVx7FKtRU!9kS3#3k{}oE6cc)k)WpwI8LU)XJ;g}O49_>^>YUUaR4Bx4YsY5<= zhR}7ht_Cy5k}7U8)$jNf9Tg!;9iwFjTC%}iCJ{$($B#mBI=fE97jCQeqoXg4byFWl z*2jpQQ`JLhn<(C0XSkWviY5Db;u_nFjC&+O1qs$A-zkk36huf{WRl4Vt<#h(#noay zOA|_!*F?r9`lF1#RLy}KXX9K%fPlPsLas_p<$O{if?_i8_MIn{!;Mp*XN+peLIz5H zZ&-p22{LY{A||r(ig(<}nK-Xa0VDU^%zM}Jk41D8t(^|!7?DVj~@$N=3;r;^mTKSB5P@sahg77Po;FpK!`^I3^yz>jNy#_v0Ew1xOm% zGXCbPYimT&-5^xOZ%GuZ3Bjg8TFmo(iI)5L5+}8}`x8Vb^$;F+E1%B1^sl(5Hs~{^ z)HO0n#&sAEya#1aD1!z>p)1ZlrVG0di~0gPR9C$ zMCrc`X*g~xoELBTO)j^|$paR)zqBVoM+gn(Kz-l@?HeeSSWk^N^TO#QHZ>7#+)*9D zgfeduYItM^@|rXU;@kA= zDF0^D;IXp0KTL7Abo4;Z%gcMUZyP{RSPIvgeZA`LbuC zGu292x#5w-YwB)B5pwH?K_gwv_17r6T}VnI(xc|qoY^|7HWBvy%`thwF?jEak43G} z(|H7MkG-Da8N;HW?~ zh~f0%{`52s!Qm0)$CyR_Y4!eXbmJ6Fy7d<5sJHUQCrD1#HCgj1*_Ssk{K+*Vd@3b3 z({Mam^y<|Wp+~Fvcs#l=#1dvy42x^nKfXAXZ#UVE?MSGOB%p_7fEPz>yX3)%9oHkN z*_uLuO`xGLpSw#;%h;YgwU7D7&Kp<7sNO9aVZx3smkP^T$nu+zr^CeBdjUfT#XLJO zlIdzrk#6s!oegzK=kXIYijktt%{ESP6T*emzR=};v1(8YTdM5*_u6KyNZ1RD3Ih-( zjts#be{g|8%P`9rC7Iq2bQxGW)a4iTVFe&|_qxq=_(!)f9E0hpLeRp%2$+_YX^@b4 ztEzP4dNcQj{MV+*8uue#tGm{e<8O!^ztjcl?wZdJMlBLRpsqYrWpzxHtD8i^5#P_z zX2ZoMjgyMbtPG83X#)!~AYm!VWr9l9xEG`C`~Oh32lbPgzsE$Os3Y6yfmT9)Ya?Ze z(CW}w5$dy+4(j-?(37iU_|jX9?YZYRu-U8K?kSA_EGwAw;9&WA3d^Fst(p^8)g^%9 z`06+Y7`8I(dMjG3DFY$><;OF;79c;Ll{z{r5S-V~bM~!6-u?sYPBZ@2r@Q@-dowAu zbdiJRj1tu;TqW~-D9$f~*ituJ{!I=I?FXTP3W|2Dpn+!n%z^Nv_wi=}!;NsU?Kxe| zx~YdHm~6+8SFkl!+Vc;L{N!KWXN^oKWe(4ek5WZvU7`s`b^9ch@TES8!izQC zhEc$V7-~E`e~5^Vyr{-za<1m#tS;kYv8D_%FEV`z2G6Q9|$Wx)+bJhZT4 zzD_Cy!m`~3Y^8X1`h>cJwWh(&FCESkmhb5OI7Z^Ge%F)@N5j2Kcvi$N#-k2GRvIwr z>k3FRG`Ufn!$c?4h87`Lm(VehcB2YX#zbG2LaTD?RC+x=MtvgQ`8!VZ%%q$fF{AhT zpt@d1hXBCl2i^$SK>UL6e}-}h40jELrDT2D?3@{B?&yP}$`vaT@^$4a%Qo2~eOaE1 zku3AlKfco@)kgp#}6i$psQDTBL`!?)D_#Jj=as14XuqyQWVdaY! zU~4N6;GtnsCWeN(NTC?Bs4iW^`-b-1Rxvt-z}vT_E|E}d-agCZl;c~`s2mjciT2{J zUX={s?eq!KkDE~v2u0R`>=6k{Y@hgiUu}OFai1gN9`kR<6#KM%eA|9Y7ggzyV`Q>h z>L0beO_0SNP};zQbJh0tKJM%vE`^~Nsx&;)Zf-it(1e!rYMauMV=#b2jX+^fqWUoM zC$ajocwdU0?*|35b^QROV*cVYlroO6kI_%GNW|ERBD8<;Pk z8a0(TQL!T&NRj^LDR$5V{rp6BHiaC7AXXEpBR|#ybv|WN!bXB;E+4L~meJriz!7!7 z#fX5n?XP|820Wg65N{!KN?Y}ldQdC)eXZHhRHp7&0jf;{PVn9a1r%q@28v8!B9Af1 zFlq=UNSnz6bM#(m!NW~J?|7qEHdY=Y@^7EujILoC>mmk4O(?gzNQ1Ev#s|u};OI){ zR9mckq0<&cgXsl&p(?>Ns8Z_!3nmj{;ZXdN)XdTC5DnlNrsqdOne1^<;QpHqZxT}n z9e94L|1&4mC*d&tmGYn%)7?xuq5kDjr%jIWd6Nt+5z1I4bXf1V@N}fu z=SpYKcUB7D8XE=alasHuKIj}96*tF2Omyh z49w&}rOy_GH2l4B9wR1uA-^V3vgCA^dy`7;eBaOc_OF(H2Bx z?bCJb#nerUN0jipS}hJbqDzkU6`=?tFWV#bRuflFb4e`?Gwz zcvuZ{Oh6-aJh6&e$1hQwp$v-RxQF2c>_Hb;>LBZrRLrcOr(B8Hxh$p(D4lY)X|2A-6g64#Z9_ehr@hYXSzFRQ z3fT%zFp3=0H>@BNgHeQ(M?EXC2u#ku&*M1lj&=k0MNOe7-!RMk#?h@U39t|Y4_&B+ z&_9e0F`0q5rzQ->3E3v-0ogw%6#FI>zX@wmDQbRuM^)^iq_)}ohIQyA9o>tlZ0BdP?(TtNXXm2 z8+J?u--=dZRZ1ZHoVpVpW5vE}<=ah3%)6u#6OhZRa8MxRecS31K?pM))x(V0Y9G9H zx6G=-5+JzmdpYd<=kiK$s3~FH;LID*uwut2zuHEIe8Kgw@l5y4U%J+)jazgly)j|V z7&FhQe~cTn&lgNkI{YkB=Ln9BU6qRANUPJevPVGBWkUVsd-b9H!TD}!X3~6lVlKX=zNc<{ z)QKm87{Yz}ci-1L$qd@7HqbB4gq|x9ZCzbxT_Nwn%C;&tDqeZSp=6y>S$G?_?qK|( zkc-O}>#+W`9R9w>9!**@@l}NrlZfEi7Hf==NdX5obU4A2vT^$*srcbsGrqdqsMs@S zo{@UuVQRF$jlj(?kFa-A&(27l$Ekp^SeM|{5p#|;S2B;8OwJ!scy3QJ3@#&!m`!^}%o?G?Mfsm~;H^E&Ya2r(-Y8tDRp&X}>7LSdMhtx9CJFWeoy+#PQCQ*@Gq2)W!_}q_%r!By;Qr-;3`J*KFI4>k;Pr{mJ z@31ZDW@4gp5gxsWh+$Qz8;<&W zU!b~X_Rze}M);$cW{}AGaC0d3bqlN79J8dIilSr6zjqfahH;*xvwJxgfoUhQ@Fpb| zvC)FnQ0O4Q+CtE}Nq@Jj&iiDQVwuNP1Lm7~^*6(e&4DzaTBojw6lSLPkPb=RtdMn*0+{3g^Pl1B!u^d%> zklO3Roon$&V)Ld$M$+mBp&qARStrBqUe|YW0{psL5fd z@ChI80o)q7XvlldN7j@Vd{K-aZn2)X!oyHk6-x^?qF7M#g?;r2;7&5xHaS$SSK=;h z-Deo9w-{K@(${a)amP}6SX~IMIK$(fB4dU&_ZK3Cfj%-gRD&P4^_QnEi!%wTY{8MF z<`fdctp6MGi(uH3zZgjeHfi?baprq^?XYRIxU`!|Aan|obtX!=AE74HH6`~%=zEP! zASk$duQyx!#qf8Ufpcz}TCB0F)GL(o2Kn|Lj2DHj?y8fd$pp!K^MwPig|rgE@bi6H zcZTg*a6ptVedZKQ$`MQG{q%ZF!SVSy^1LG`7kK$}Mhl$~=j^Gq!`8=sv616%#vF0m zEm5}lJmK$q?2Wg{3=B59qmwb2K;01_nLzx&DF;lH+f+#82V4G~f&T;nG9gGwufs9X zf9vhbKi{uJS5Q;ItV0rC$bpH}sv<+UNUd;8QH-pTYIpo>HRzcfr;@n&42W)7o0I2` zv7ej8GdpB9eXaby5|GSX6#u(rJdKy*RnZhwVM^%gM&5lLl&avnWYbp-1|ohh2ePhD z<&~!Ii;bC+fa-z)1n#tB?o$WW?9Po1)cFOxGsXSJv)zQYBBPT%a=?BrAhgJW51_<5D&%A=D74l`{|IVoG5Ti$)(mZ3S^B%S>*GgAexUMQNK zuXklv4DA=-F{Wturujvj#icY;=y>g;bv8vuZpyOu@1FDulzc z-bdXN;A94?`CbVOSgi{tF9gZBSJuBd;{^vz3AOHbCVY#_@X{^Cp6`H_^D&l119 z$OWbVAtTIl`cgOD$?y7ft)cREJJ+pHKera)8&O;KC=3f8s_t}ruy2NGyU#7M zC^*+Senn$+wsJ|ZGPPBg`y-seC{&}I6RVS*;>{YVA5RP4~3-eCmrh ztVo_X3*MFA!Y9yS8G@=LQ7X;?sp=mp-t$nI*^{jcjtSVil&@Kd#M{5qBtFCrKKG7- z5DFZiJnFo@jmNs~TO zBXfRiJINKczxI(i%Ns}2$1t7iha7E4nT^KwTR>Zb zqbwMI8vR_6nnW=c2*0dT#c00pS^9d)H0FIPg_T~vHN?)+UHFQe>5WYM(eN17ua04f z-%=+H2`MBR&mN>kKT59Rs~-^AxxLobnAQkdV@X9It68ycc(Z#};cL#Z$Cex+%9+Ak zhp^%c;l#?GX7-LH{2K4FS?yXo$1lOdz>5RjPuSlas^!y|>-90qlBjaj$zVOmib4YO z#%lG7ySB2Do-B8ww^esCYfaf#YGmvwp-vNxjOPPnNB&8D=Rz|a+v7s-==N`tsJM2Y zW|mS-d*74vy=iw|1uOM6o)1gjY)iCKAz5iGc{R9_56_JKbOFE6%$GfW)C1mND|t>7 z)LDiRqT_ljwZ8ceZFoqT!i3Xawl&;TIxd%|^1c4?q!`;Pn~eu+sP_<(OvNy+Y^|sv?7}I);-KG0M3tPWkOW6G|cpcthOUQIP=fWhw7r3gl}`-9QK=TcoLx z+zyui<&`>i6u^KX>vkZ@IpT?@6lD&j#`w-rbDFp2gcE`5MA0B!thE(f1fgfl+NAid z8e_*&!>d8Eu#Ep!S5=p;+MOmCX+-yKoFG9~y`BvQ3JShst$X5?Mx<)%HZ^D?U%$Kg#<608;A0&IuVs1fVSoaX z*h(qZ=P5M=2Ita?X8dQ6bpKe3;9KrzwT+_ZOYm)-mDQQ{2jQ*kP=%GtgD-rZZN;&` z?-E{5{;55v?}J#YkXAT!WEHg)z=ZFy(N-DmuVuonKR<4*1gk{7gNqLfAP+)@mDKoB z?5GGrP8N$sX6bAP`F&)FOUhoslzvD}P!IQ3>gqk;CokV;CdNh#L!NO4tCt|9z+;qN z>Z%91W7G){PVsf|;Ix<)L`;M^Y;!lBnlOJD;>H^v>cGYUW~w%S3^fvknl~Q}siW9M zvY)C+2e<^b(S~)&a-y+)oV>CjNA8oCD=9=zW_-$VBSB+T`(YG- z)+Xu|8S+J)X0sAeCHkqIJ-edyU!4$rSGMaG+OL;hL+Ufz$6Vw~j1m?@sku~SSh8b) z=a@CJj05>OsqSSmfE~(*eC#6lEUC55z?V|_)tCL|F1InfMOmiIjQPGYEf&0Lu4f$z zup1p`n|x^fr{QMnxwu?K6Bd^ztii4&S5QnzoeY66!7yGMTpz8({?9737Z~YENj)Z6 zVj)7EBLDuPnERhWT8?J#uE6a-Oi0N=Rh$@X78g%GK%!!pHYL^GMFy8MOL zm+u&vpU<#>_q10i2{bdxJl>H!TwR7JE;LZGi@bj2E(#sSroc>E;yNYVjiZz`3rhLx zNciDP)1?xh`b+Mcb&t#s5n`edNXL1svC+1v36YcfM}&nhLPK$+v&6Go96Q39^Xt$mM_#Fv28z+s1X5Aha7SCY zGY6T+_q+m9phcJ3$KcQYW=ba#Q^ ziv{O!T#l8e%dQ(;bH?jW-fY~DyVoRcjreB6e>!1qnyc*&O5`a1(}HQ0 zIgW8@qv-$Bu}-gXrtOq!C0C8wZ}5J~-1|O0NU~kLtXZuZcmp`JQ0^28P0?*wpBnG{ z<}VYJbmNF8>=be=qB}~t{Fr+Yc0S*-VtGF(AQKRW;e_#8aaFK+q+@TF$wZ3Ty4-A9 z5h|xtyz;kHB9DI8gEdTD?{$I{$0&|4_q0hOj>5wq;OPr@CsNKl5R=hZ8|9)wo;y+{ zZF5h5=7?JH2Pxr;VMT9-R?d6OagFEdFN`qTL2*j03g2s|Q(+okti4^K z@kCXX$s+^N-3&Q{+(OU248ok+u?9-%(#CKqeVmbg5R_$&6wam}YW_vAWr>}sL?p6=oF@n-DmekGWfaVu`>8gEL-U7*G; zFS|44K>tp&V$LISCU8u`aqv&iZ4}%L{t(}zM0rXb~-5z#Kq%c_JoAt zq(|Q`v51KJwFmpYqxF4&Bm}DB`lNTEOI7e4r|icm#`FK2OpUO5&O^VK0n>&E8H5Xs z@Kt$r4HgR@3nj`E!nHUJ=iOlMQr>?uI`9oVAixkP!sa+d+28BIcO@txjmn73bjo0Y zzwMULEgIUEC04`vHuh%XM1o{~sKlwkZrpk#Olv2HR0@^W(Gq5VZbqC2MxpwouvIQa(^idsxBdhfm+QkmyF;&jJEPeCJoE|Kdqy^b2PQ?x(e0=c1QS z3JZ?D6Vgbv!&+=+yn-Xj^$dkey~#hP&~}e2#NO(d)yVzi`m19HV;b)1l#{sYD|a#{ z)m3*zi~B}O{)`q@EHZ`@*U}@V?dVR&hS51yIch>nfT1}R(cn7q3plzWJt>cUBv?|F z6*3pdHahw^m2)MCohO7OIeN9L8yl1iruq7;bCdzH0nm~!F0hZJ>FGc5Y1e(Uv1AJs zo~83@T+m3(QTY7}@gQ76*d4>F#?Q+Qf}d+19sjzNf#)b4FmTF-h&P15UF(GbDlb|% z5@u6DwFJ3?a$svA)C#(d&?1JQarS8zAUA>jVRA$jH}q}q?xB`|W;xpr^Qx=UO|%Vw zgCPNPa+@=oO>YOM8nLYtK7&-9Ui$n1y=MPsVADWP?kFFrTYYWM2h>&fs)NN$R&wBu z%X0@UZVD@F|J`Qw_!5pSSw6`;p0&&BWk3gbxW$ej~g1 z+}cO?I6`rF$aS^_a{{6X7-X#57dr2zLe7rb!wq$nJBw{mr=V8p27i79sd;6wVU?#| z{N#6q(tM_UemprA2;=CW@0V*X;y3w_K~@BJV*lNC!uQKWZo!zN-@3hQseb*;1y}UI zDW`F7-k-K+6epc@+0RKI3Asr-ZkaLKLMkOa%`5N4p^7EtowPJ14oDRo$K|Y0iuYqx zF&a7)et0qA{36SlBN2(m&`i&e5jS5Co^i1>DLjUGJLHba9pJ{&@k^xwapu9@N|xzV z3bo6th6>)Pf2$=#;;r~(v_0sEZZfch)8eP9XGBXUSE!U*{Z_xM30bncPhi?a*8($Q zpwIp71g>9t>0&3#khyi-{?&B>^6R@cU6&lZDzwDEKOd4$T8FTs=Y+FIH>?4YexCfpvM4d45nE!URNjsX;GA>1^1f;;ho zSy(#!`Q}sv<)T7Q!-cKhR3?U%YL)jOa0ZVdYS`KXZmLaS4CD4O9`j^H8 zZ^I{??kfKg&%a!{H^sk8?KY0!HXW;(F7+Ac0;Ub&pCMIpD7Ga+FENd!Lz||lm0J$$ zx9Cv`kxc38+wy(}=0@w&R@M`(hgrydamC|Q`q3}NTfM??TrI=+J_-jLsyd87DXFt~ zW->Sg=@Ir>N zAL~qW^`#+NDX2%+J}7;{c=_6nXy^KMUvoLfx3mK@>xo}vi+g-tsH>=xta7l4-a=>h z{|HiP%p8$Uwx#dhUO>sUSO)|oIv+d~&HtDZEuHl{AWo(dwzrdKg(YpBu#51X0<1`l zikT?K>jn;nX!jOs`FR!wl6PXBJu+dr<|y6M#G;# zTE!mQD>M}tkmmq^{C0T-Le+lFr?mJ4v+=CT+>w<j$-3jxI|`8<1HqqNSU%ssAW_|INY4xABq`SCdTWG@)28$M)*@ zJOQe)b{8h3Htxd%K3AMPs~quo$jv#{NM+~x_eV1SB&VF?&3%WvyD8o#bCY7HB!V%9 zlf%Xpg#FQ{yAL6^bc8!4xlaZJ_M&SO^b@4mjqQIpoBUu)jZH61AcRRzu<`B>MT;WV z15keovXQvKL}jFpuxzn1{F*r?%7~yOFSB<9EOB#vcQB|;e9eZ_6Eh1tkvOjc#~_~E z1}GUUXWvLM|NQZIU!<8OA@Dq>g`a?m_b=%%f`8n%gUnRt?9G7wAX78HX^SX}!8oJ? zLKt(SXr;)qs`=bUU#M%mGN~f1C^vF`6V2_32PjE(Gl%au?{k(}7^+)12KNRg&XBFo zx{wDFNu6jYX!MJwDk3p6@P9aY7Mewya(aoGP>{8?N@*$Sc=VIMKW-J?tf0k;x@}bI z#f%Cyp9<5sA}smcBpeGDp&yM^^|Q{IR=q3-B*H43mO5_39Qtv&j_&4TLIS-vT;|hG zIfZ5F0bC2DnCkO>!~?{nB(yz&=9%yD`6ty)Y0xi!QK*Zhnl zvhAp*9H%~g+M3$oRoXu2N32D4%jgtW;SaUcbH0p{fU!XRfS(A{-6gaPr8m{ag znqdK8eNE_2u%cbd4cCH#{RY%=V>|9e!E0#p>-v~SkJ1~{Alb!EEr15;^^+6elw9A>tkT8)??GE_RS0xmGm0*Cs+K(P{B8~oYV=72 zJM;JoD;wQsEWrg7_MDRm63!LEabLqOk-@Ag5;cNvrt+h`^b3)^?1KK2=jr0Xjji2> zK1x%+vQ(_|3oUO?!Mkz3h6N&NB1Dqrb3cA$$m#2m5;w6s=Fm-7@O%dW2<{eNj(zHR z4)E6cZP%;_8!yIXR`Gg_7C_ZOor$*@F#dUb*G+r=C(>3i#%wxLYvAiwW%HEPxkDdS zee$`6!Y`wfxR}U|l_e{uU9~gD4d(4jv;2Ho0^kFdCvD6OQiC&yI;RQM7>S!}w4GI{ zy_r#+s0sS(C42xc{Uw|%c;m*noTUQt#FNl&_qS&R9%8hXiB@!TG9XGb>}%pY+rv0g zOat>8QWgC3h3}_Y)UVQzc~>1T*_07CvW|m{ALL%NDw9n!2+}F7AT1pdg3=(}3@KgG zC?YYG(%lV`(k&t>AR*`d4!^wk<6N-W``yoT-)m{K>7|+zx#?n#Y2cU$49p!7b(}h; zr=M-^>rzP2C1B3BVED4(y|uaDUZg^)&fO!~AAC?w^22n!o4v0G?ws6l@*En}?$h z%qN@Yi4VMTb^L`8@#FCL1Z(+t!N=Zj7JQCtlO~={3H}T3OP4j7dZ66o``tCqk?h2X zYH#G7b0;6R1`?2;@n8%VjVf`c0Ysp~vNoQbZ1N7tKi%Pc#{bcnE;?sgxB0bPPh z<9X!3(Hs*06gj!W_*6if+1&i4dwcG>G_HIbGcVY&8k7*l39I-@J&{FEtU4@+@8-YQ zZvg=_m9MgF8H;A|U~4c|H|s>kAB%61TV5Ao;M}_LPWHR74&(ZpHb$rt1V1Vxqx$4? zk89JG{hxb^+1~Ct-z+d4|IxfT@F6JjoZxnazzpyK{*e3T7s8*KYO#-wAQC6&3sd_K zE+QSNb>~H%1l)i{EHG%Ep3bn(ddAph)jC}QJm-;zy#BmTfOt`x`BbAAn9PGF?x>Kv zrjbFas5-mpu@A!O>Ov_! z8w@O&g$m)twkv{~KK`Yw%Ro>9XbC`dfoCmp_w(c?&2KG{UIu)^|K?>ke{ic@Mx5I+ zRjOEV*kPa|kji>=_$A!qe!d4!mPVXXGd^q@U?BGY4Rw^dmS zk}Cbiva#xX8KnJ=of~e7Gry8{{xhUW-H9g7urMZI{r64%WXG4ZtcG(ijve1_{eCH&yM_~B(o*k+OH44F}K@t{zuQ4Er!L=M}8h8;T(zcOvy@eM5b zTXOnjH|n^M=SU7?t2iN1XUuCyjj;au;u6jVVhnWxvM*^qGIc4_Up%-AhW-S5vdvI8 zKIhJ3G^l-nJN+jL@1yfdt$T!?-gW<>jvh43=X!_{&2qKq7wXTvptqILlt%{`qT6&^ z@A|`54X3hR#TR_~gs)C8b4}aGG~%CH#$;jsqA@&GE6|P3{I_S8eI+g~c*x7Nj}M6U z9m}FZ#hu2&Ok$q1pknhR`*1lTeO`m{x9B$$NdIXxdRVff6_G54@)MZxQ)2pXs#Gfm z)!~INcvVGsjG;X0Zx`+bP)`jRu*qra#eI2b(A>fbcSU8lsbe289gns>mOkkJ!fbY)QM&%?}O1zJni_-PlfulyyAje&BBU#ZxgNr<8F< z8zpF8GOyv)uVJoqBS$t`P-eHQ2qP;!S-X_+V4H1k#|PeNc}$%C6Q#uR3P4z7ZPC3% z`Rj~bgKpC=VqfBueTMMSX7UBIHkvqB*oj!jJ%ge$mrsh1s<2K5>*Vvx_qYFk zf~xE753HwU^&`J!grye7z32R(lg}U$u5Yvc#g_c>I1pF7Z|N zUJ&=jjb19Nd?A)z352#Vi&j3745gCqN*n9i;@fiR!&R}Hhow)umLs0 zztFB{BX~7~N1!yXUU$9#ijN>Stw*bZ8QJJ^@IBYoVVUOHR?$#|6-qH`P9V%ljGd)n zk;jir;t{!3Bc_fjPhND2upHNynBvA+iDo?U<7AlEzKm>$$Lt{lkv@%Z+vE zn-IFOFe1bALHVDymJoX$lvYwTn|$4+#$j{yMfM}{8I~^o6oIM=92A@Jy4)w{;}V8B z&JzT|^=$S!$+i**gTXUewUi-6oWU8zOnYj4&~bp5dwcP&#Lj!B*$LPG`usWN;Laq< z)(o6-&!l>e-pCnIT>p6;$ZQlt)l$aRl~%|7!2l!Z(*A+Sm=mujcx$8cdBfe@i!5Qr|6o3*XhA!NbBan`pdPf`O?%(6F_(=huvm*7Jg`NXOcS-#07RCtp#L zXa*=rW>2&fp9P{1p8tK0?F0peNukYq4t0Xl$w;N_pAsxNP!LrSfMS@f(R$A7j;`ja z>${y1JKb+p&=XhBUb`(ty~DiE_#a&2_x9`sf5qVmE;K~0c6xUFbHT~wO=Q#j3+z-3_&K7{i8FB;=Wuv#4X2>od%n1e z`q!1e&9p~l#Z$X%P@}&kTw{bt*47w>vWz8_Lx-~#T5KIdHJT@MUuc+7$?03X(lea> zNSJ5u$^m6c#es9XtQoiu>qPqr({bR;N^>dn8;vkJeomGA%u|rL{JH{Y`E+qL z-!<}5JXzl}_UR}8@$r^bo}@vEASpx0hGuKiL7`CdOxt5=1G&jJw|C$8^=8GMy`+V* zSU%<#Ne$Vr$0rgCXr~!?@oTDa%=}{1*s%J$1Y$(KQFod=u=K+rGJ3wj!KO{z*RA+O z>LZielHR!c+q9s$g-&AViBj1z%E9aSh|!g89n{> za$0HZZ?LcX$yAvR_SaczV=7c~Umh|YGAe>7wCu=qsZS-3(~1-$gkDU>#r7EnOse<2 z;rGphe2X?fg>n4*gkbP;-+sG&>kgM@di&{j{=_LAOEGa*xhdqs%T!M+)vd%Lg2#av z)!A39=4)qk>ZsB@8WQ)x%wN+VhL;lj)u3}p{&**?gj8Wf11eODi8g`Cdl*!Ld|5c; zb-Je&Yi2>Mkv?n0tsR8UOyau>Z^mE;H&kIUnK7qy*Z+>&2af;Uymkw`m#^Mw3=@G{ zJ#|Jc<=~rMV$gic;gq?NQtz3fgZ8mrwNsdoCb-Moh@ut4v70n3kR3@TOQFrMT%207 z7`a7G+i-6@(7^X^wOimZpB6LfL7umcWb}oWAlb5Hj5X64PiZ5Q80EDh2dRw<{*|iW z$edw`s9f?M$5THB1D9-Ejzw+ zmKfnhEFfX9*)(aX#4UZB&x<}X3V&Aj8O6ur9i}xYxacp?L@MWCKO`l2$dtaJH;AhB zqQsbCetU2aEOi|2CpE%`)^rN_z+4<28l5Z}$Vc>57?O=kd~uE+nHgaG^gc8TtKhXH z#mHnKSr~JHseD}ruUGEhOhFUA%vU~rhXYA+-df<4Ww16EK&EL#k8b(n{dO70r;P}e(J>1)-sRcb9)NP(=|fC zv;cj)bHPGVng$lNLgCDGdKDX^@$Oy-Bvl2hL$@}9?OtphMF@riH1DLBSmj7)*;3b+ zdQQ;md(HQHw3lmrB;#cbuMp@W9eBv)@2MimWFF44mP}Y}5>R(-BWh=R?2Q`L-hsAR z3c_f*>TumQ=;tj#Vj`hKcH~~3s{T@Am_A0s*U-wY8FHv|dm2uAroC4}Zn>?K#hW(s z%(0I+rmw|Hz{+u~<})`-45)Vjz?DxxK=2g^ZJ!A>H!5Y@4UUkU*ALE3NJk424Sz|` z5{G90hS}=7+Jp7Z1YIe$V@lDg$j3t*bxgz-WG@dY_ao<0GtB+h>E#(J^rpw&F$5Sg zE1J6{tG}8Vdo&S%lrN=3eXZNHgkg+_UI=o?mJzEXcS06INB^N_`S|2+16yC80n5Y% z+}R!o*L-Vm#MOLj1#m{8!gWH^ZHKGU?>Lr(lBLBtl}#x8P_$=MkB8iCmSmR{Ts6Ws z3kT8C;Mz9NHp?J=s)bzK&(U#-=hBi-kGy)M5>BQBU1yF+3SJ*yKhS4Lx1kYJqXngH@C-}Ru&gZGz zPVRR^XnKM&FgeFMRcYL}iOYk(iaBYzyv?@-aIqSLI2v@h?dB?2Bpv8MtECjUm~fPe z;-9vTYHavL1v(HDfjoOE>P^1iJd#5|TL`zZZGd0rmZr0xG*x0!Nrh8gsG_2T#VWhe z{_^sMtt$>7;Z{sR7+*elZ{e8ZyW4oOC%%WiY6|qTb)lgL%E`E#Nn`vII-?&jsVhmI zF1_UUjxSV`Bum$++xmH`hDPwfshgtibC87rC2TVph~C6@ zQJ!gfx2h&W1RG#40DK5g-61Cn$5-_(hmukAr6N``?i?D6)t{RLYA~E$wf{!{NiFS#T6Gcx;vY)>b0c`wgCxgxqv^ zK~@2WtDVgY>yX*zs?D}h^%*s(OiBURm0WanXLl9Eor9=xMsciU*Dl*$;%9|?KINox zoNwbbUm|JfTlfX(WUH%^`)B^oHkq(m+!nHhdDEC2R3lZ_8)B^MPNz7U8WNTxG#WJy z%X!lulf_S?Xsd{l3gdU#=m{Osp*85%Kf*Ur3L9A6D59``678H^X?RXuYLrlp$g2$_ zt&$^AxrUWx-`Ps7Z=x0l$ObB3phes=RSiw zUN1?@f|7P5ieI7_ z5x2^rV5NKufqZu%;Cl52UFD6&7QO8wur=ZE>!(&yPQff|)$6n(%fd7=QJ)*Z5ba}B z4pGXJTV?*3Iou&MX~Ra|V(V&zgHlQie-JAWTUEU?MNbyPQl&(UtbM0Vye2nV@mX`H z#9GfML!Fs8Ek}X0hDNGlD=HIpSWUvJSut>fP!T(wsI@y@d9Cx_vPNnG_2N@^8@Dp+ zGXDl1_?`s)qZ*M9T7r)i2=ff*mbb*}5tSMBWRuM)J{^}et1W-3$n@mEvAc)M?pdnn z2@~d~%XxO_;P2MA{E>L}(80jvXTC?{ZBEpGeoG_lralU!;zEg_Zz*)Z?OlI z<1Sb=)qe74$)yisims`X{6+&o*PnuA_IX!W2|N{P9zhBaIr~@c0Y1G_V_1xneBSw> zyM=KqMVCm(zhsfCY^eEIqmhuFLxM=+{acUKPdOOsj&Px8JN1sXx0~(9I_czKKC@J% zpmV`&K1XFFcR1&sDZqz&*1CBM7Yen8zEde1EGJ8Lxv!{)8?cacL@vUsZlB{PQTzsob%9 z=S}H^4?yQ%0GxD3!Qo@W_v>!rOq$O$n3v1_q1#FX^r%%CxK$Z6tE;?#RIWTDF~a6? z0xGZoSu+6u)JK2tzTkl;%jVWV;vm%Y@t%cdX!9$Je>)Fn^zG-XDA`r0j@c;^WNTZ( ztaZ6;-cg8;9a~IHkdu^4@9~)abOWCE(bFmiboJ3AayEFOHDy0o$L zYTcNjIQ`XTagE386t6TCh^i+H@0xt)hi{eDq200fO>li1!QM#D(9t7?XEwF&e^6wsN+x-61s`bsKJ<*ceK#<+L=GQwS&9fEntRuEhYhHS? zRN=OS=Dk;M9*j@J-VqH&4_YyOoidhu)rR&wxl7>Kc#T?N`Elc+T@$_F+c#tBk8rG; zGmbfB<#glrrQ(uW-{Tu*&Rjcl9K#=$TmRQ@!G2F-oN4xQbU@#8%m8%}V}Mph+dpvP7wg?3>zZr?}5Kg(`5{@0-) zi{hW;+kTH1>Mm``ERrmsP=IyD#G#L)?)+=B)%T$eE1Y?TKsD05o#`T>qvMO3rQ6@Y zvzLEm+H6BN_fFaxDkc7z%{8@R#JZV1dG2Zgdy0M6bg#Ot@9u(nX0EHucor*O{cvF% z?wBxtPQWlQf7XGVV-m197AzLmI`!T{zv>C554s6KY&8Q`45+?h2N&PrgV2VVd#;J4 za4EL(r!S0v=0EHp=oP7jA%_E6K(>~j>_ZUgc5>#yf-$Jbw7Kan^l3L1jL0O}g%N)! z=O()90Y4VQd#cWNZ`1By(J;FqP&wil^Me)tvc+v3} zzYcL2+B!NpD?*YJn~+`wGs;#=ZtxH!dwtBrXVGh1!}0W5wm+z2Iawgj9=tDee2Ez4 zUl=;~o=#~#Zsu8NHlH|oV$rcycw`K70;K}x$ik?MiLa*PSRo(YN#+r;=wz2+6A~sm zR8W_nqes{TgRn(1CDjk4)xKYV&p%apHYm9Nxx?1Ud4A7*FRWUST=9?E`WFm%8D~rb z!U(W0HRc{2K}8o0%<3oJBW?N3`6Y>sGXM(~iDFDMs~O)~QmkZzOjgTggY~1#!DjXG zt;xJJ!&ub#@z92mo%~bX$8J)S(`V;=pqx6#W+)AgVaPo|pC6%4F#6|dREX&3qKX5* zhIqL(!jny8?PqV0-$3zA2E??oPZss16$S8Q7K$k8m4b9z<>fUZ)VP!nA3mHOzI=#$ zlstnMwH0Di$I>Mz6z1#_3b=3i9~{M^It%iPcq71;xoIAlb7ITO*`=OHF{!Rhi)+#Z zUyXO&jXeC33E1n#ap)|ob z;BP5QmhI)4m3U0aifZ#OmD1~3r8XMG=^4BCeKCV47Nk{)&Q$S3sGN}bHku8Vtx3S+f~`*@A`z zVWl}fq8h4quiYOR(UlRF?vMAQ%1oJ155p@h6-Yx-kh7m0*1^jnf!kqh-;_M3Pc0g$ zY_qs%L;?wF4)%apa&gJ?xEuN66nv`#r|+ zsT{%cA!KGqDaQONVv%C?ls<>rA-=*D1anv%$3?#(lS`TGLscc@u{`Yfsg*r$Y&xz3 z+6X~eaMgX&QHd%vR28vHekj=E8wJ+{%;+g$XVa9jSqI|ql@A#S7UZTch!I1x?>!kH zS`hrbh+q?XqV7lQ0^*xKjwt@QJw<=--#aJVQL0yxQaSe$$Gap@F|1`7C{7OP_wk{a zqnO6wFmaObl3bNGAB5oc7%4^=d5iW&VzXOAKd2r2rH?AeWj-i zTST-Cega3WSUUVM^@vDiu0NRL5^&tGg|Av)%h90+?VpN9LP@pl)l^`~xjrh>3{_&| zly-)#qcNFfJH~`qA)S1IrgzfC@rWeQwJW zWglAsw`6&oY8VFJ>dLd1*aZX#M2`8lLlYZc0*?5RKd}&sv@dlE^Hamm)tVMP8GT02 zQKNc@fvWu+fvi|p=mfDe*Lj_c3K1`+T9ESv<#gM8Y*XA&uhNi;Q7Sj?f+}@rvK%-L zaC92SLn4$e|CTxa*8s(0AUY-RmGe$&cKyn3@{~Qnw_9pVHH9p2=X@F`v)|o%yWE!u z!@n@_dFP2RiD7~QOQ%nJ^*AGx72FN53YUfqG-as59r;-!zU!Lj4OUJH^Va5e;s@$#p?!>MhPnAHvzOW<2&ZLKoxwMv zjz+uW`bIt90Qv*n)(8aK{xj#8p#0gJcq!_gQ1}`+96{91zeSxip6umI^IAB;z*d+I z?32+|N*31$su-vFGYg`3VDUNll%w>-O{yCP04Whu_BAzYN6MEaT6J3$B|jM(~9PyXOm3!&@hict$C*PNL2dzY;m#8h0Ee z_y^n`H4Q2~Nr%Nr@hzkw+q%^7XIg7s_cp`9Fk(wKBQaWtZK|dmS(b+ji^N_P3hV9+ zX>bL}6`<|*keuQvJ3Ix*c)YFfm*7R+C-5J~LYy52=$oeI!QwpgE&m+_T?f6}lV&e6 zpk}j7evwiJzj^;sgS1SNuj5IVJ2Q@S~CugfI{P0{hvkwH0ltJYT-q z1t>~EQmrln2j$MaSLX`hFYiwV5%{!9%1;6t1@+vRoj)bq^b0HTI@U?O7xwSIibd(< zY9Bcqt(aZs?7|waGgNi98nE{80GFlp2|1r>Cy zIWaw?WYac6XbD{t1ll6L)GyBs>riZE^9L*)}~p-{~FlAqY=3s`KSe+J!j=SRP3FmyZVsat1BT-Cv& z3~)x|)A=;vxL9ZbJ-u{Mc>{?wBpD(dARQuNh6B~yv+H11nxup@(=6Q8M3Aey*?4WIB~yb8Fy zy4?DahM|X;y8ZzoT?14i%4jfzadIYzZ*WQ+VD3vPj(xg zKCOurTaM4Py^N60!8?Z0ee-AD^AUY^%V?=~Ql{R{zj`!ij{V=O4*8$t4+YAHUaw1E zg>&%f9#=MQH*e+E_eW1uD>JUv7-a(yD99)XYho2NT?kLW%CSB5i;w*-6gmzZq@{i~ zcZ(x{Cjgp{pQGGc#%!x=LCbDh&6C2SWcIygu7I>W)rs)y|Fg^p? z7uX6KWiHz?x@o;9Gn+sawif2iz`g1e?h{X#1VJ@wK$RNYsr z!u2354ha`!k7H4DlcIwpTW%|b6mem@D!#}m_z&T}d2JT)7QnL$+kFH@d8{e|{4ubkYUyadCl3S{peubw~3 zn!d}PlS`X!;uh3kuMoMHNPmFxMK~dfInq)#fA9Ko`8DU_`}KVfNyewoz^)U7I>1j3 zbff0ek@!xev!3w-11j|{xK5z;7iQw$^IwM(8#!|j?wAki{y;-{5YSyEQ2^%#A1*l9 zlm)}p_VXo>B52d++qC-sEVaHeES9bka`tf-VV9$HYG9h_N{AITkG{nge1$GW<^LVI%0l^^a@ZbbYy|3kD(pqhqzx^#eK6x;lqoc5%76@6>sX@N58v zq6ayCjdt73LZe_u_h!;x$&I9x%0?Oc2SU)KILD`k6JJ)?JxQMNbA-Td*2EqgoLo!; zwSnO`#Vm%ef6+7Up6MNq>h= zT$g%S*-NRsRO6Pp7zk#<47jH5@y~cAZe*?*ib%1m^}fkxC4~ul4un0_XIXWvW7Bw{ zz9l7=&|LE0(0QC32YuP(_heQwj*-r|bAsT^SBhS`p-jM`v3r^)Z0}DRab&EYs;r9@ zS|hM@^?K0nis{Qq{*%>!oZG-HX*6;Ses3C?-}b3C?o-h$UC&;AwlUqIfb<=DuBz=x zu9oT@UlP1)YCu%Brmq`4EqrOS@K+LBW7FR;!qW&CO2E~fs^|007bu9a;yh$hQ(aHY z1O6NwJhH;ki-z(&JDW=2|oQ>!V6akAxbPG?dNsNJsX}EhXq(;>04}A2j zn~b{WN}#`+jRj-wyLH}&3g@U8lF>)Y;| z7o(l%ggM5ux74Dw;D0`p&uLOk0Zj`}bN+gsIp40I(i-Ya7{NC5-+0AIzpag(BLMHM zloOQ0nk7p(g$T^%3m^G;gw+5{S|WY^#*f&h8Ekr)z#qY@prMIPvX`ai=3K2=Ft-)( zq|lXmm^PAN6%%A!=lVbxm}=Oe#5eYSBf6cQinjE?jwb^+Y?ISniNr|g4Ssp~Kevql zZbRYH58lhQp5H{NX9h(lW&|xgJ@nM-Xz8B>${MA?%96*q$1UBtZ`@^5+$+nHBMu<7 z^QS(+0vEh%BKW(uz@JTy{S2+?jVah$mDwum&+|v3M}^>r6q50e;TllRBl>$zQ2;2a zsAB*5S>nGKHVVJ2UZKPs4r3C9ZNwiZBN-Se36K(&`tjy zNgr3)8Q2t6OYJgWbgW!r6k0S&jJoHVUV5^+wKMYKKO=2HFyM=VFU=~X(*p4%dX)Rm zQ_ygmc$yh>+i@S%{`QRy$CrX<%3(S;rmwBQgOQ`-Vt-yPhZ*3vNe_QN(N+LEA~-c(q{BL+{7QGrvbVkHTTtO9Z}!w z2yEyXqk+lmPu5B^H&|Ry1d6V~8+&oG2AVVeP(yzKY4R=<#U70^(oYpa> zojYSNr#p9dvN^^|P3Z1kl+|O0kcrg|LTjn#_%001DPNJVG{32w*EhD5)FQ%$Y>KQJ z36zP|vG}DU9q^DF3|_+|ZqD`S!XnF%7mp-2`(rF$MCUY zAeEkYDL$br#1Qo{ZGsT4T1J+JTR{6#G)s@pYnz6MX=;Me&`Lce+Bj^9NVt~S3qRh8 zqS_CN{`AaizD7nhEGQW(#tr9?cv)nn;d&kKMQbiQMuKijKu3@uCv?E(h#`AraKR+G z5%$R@(Rqj~BDS9zJZmesl6R<5Si%}K)QnDhc4=p^NGcssgx&M|_aX*GKZ`FdTU!J( z9jYoNvCHA3e1r%}lx_04PUsB39x$hgJ zlnxF2XYDM0#y*Y1+E?;K{p;og)8y{bshsn+tX+V~`5QjDg;xy%e*+SXr9ONi_nl!I z`bIgZZ1+N~#s#knN$G238rLKKUu3kK??cDtpF`Z6s<4+s<7|$@FZ>dv_;g>0)aw~i zHlIMGoOeA7p{lPmQ%w(>)kErqjj=Z;_H%(-7ZZ>U*dd1TceE0{#ScotofC?;h^)I>d%K5!zY2+ z%^>F>3wa#;jcT&fbwIwvF&|hufmREYs0#+)*qPUn8RbuxsmE@`Nm+MB1V=@wuwXxq zenj9;F-ZwRp%~TG)gF?AZ^452As~#@B&kb%BfOPP)q^Rk3t!$oa+%3hNvXl&)_g`L@h4wbG|PswUJrIF z2it;f4gPZb@hsPSb^-?*z0W>beO?Zt`kq!v_k_wRzNjcio@?a_q=;KbbtXAtakLY) zIbu=wX0X+{g~#&y?Cv303hI&XArcTntEtAqR#i?4ufj8o%Z_HXDEWQwX@{b=Uq6{9$p*aM4& z%NA*p91B{&cS``rAzLFLA#@z^E@fTiC#cC@Ou3xvHjZnwjk|5GB0{ZG>iBp0;$sEQ z{2>*XaU<+v-r9DF5^X(U`tE#Me3Z#Ks z!r&=BDil^AtX2cZU0v1kpizUL2@go}?fX-tMRrEm2;W(iOB7gcZ#k<@*gJM!!M z8&Fi7sJY%cFmi}n)x>@GQ{X~+&J(4+TZ&ISZz6M77Yj*lWWMR+(^;NKe|mC)bq&eU zi6qx#YY(`O1-pyyQ&lyGgGt&m;Z=tv&o1!Kk?TNl2JWJ2USU+}47&t#HOB+49qf(Q zO%JyZw=G!wg@aF6YTcFPIWchmalEWCer;@t`uw2sN~=Rkd!}vuH8p?yFQ?xbg9f^| zlq)OUqG|x`Go&N4oWTR~=d5NtH)@Tss-jD?@COf z#J?kAp|SP}HbJ#3CF5WtyVOIAcH9;xNVy@Lbz}H(#0q@(zY;;Q@StpQcajDE=my zMEos^i`2u3(fo9j0bxd(X&HO7$AmOW2{U~zFG&&_=54Gugcxw9$G-fTCqnsWE7h$s zq4QlbWQaPxV$|V*gB&pTBhsEv4!2v2L`0CgR8AXrzaN|ob+&57K$!{#F3($ap#?;j z{SQO~RRD@ z5A2aBt_cXguxlI?=6=|tj z+-mj9er;^DM>IZeC)f0v5(CY=*Z0Rki4R*c|LDQL{!xtcRC=qDawwJM3c{n11$kd%|w2vH9!tn(dz8_(E#2ML|U3cCK`=GQNGw<*3_Y~+lEm?D+^tbY< z>$G0E33|y%I{HpdG5vmv0;jfd>0R-D5q3rtZ2e2=TqCJ6nUymZzL$yaCs^(n$;7Ao zl)aio4J4sb?Pd_dYQ2^Y%GqTnC$KV(g|W$WJ`&w=2wVeD%Mt2tmK% zFp?251!IMDG4(J;ZzTE!C9>G5jy{=@W~!{H^5YX?-mGe0?k4mbW#%$Qa=)~J2i|Ar z9849fcxJmvJxbm~z^}%)rli-?sa%$sdQ}}0b{2m~|8}6RYLenRSzfy{SlD^2rSgx~ z8V(klh5jBs9^QAqy*qkbTa@rRU7HlrO$eT0m}}?nEx3AT?g8z07mUIZ*s$UGcr9PE zY;*m-i#p_B=wdvLa@@X8fn>t%Gi1?+g}^V5?`bNzLK7Ke50&CrXB!>7W*>6fQYH?d z1^qk!P}oc7?oQCN06rSOCc>C7q)VC?|0ga%th^tPh5wr>^#2i||Ab-U=|xX;)!xLU z;Irps5~*{U<>(p9RI5B3$Xx8{nb0GzxD~IKrFJD9j5D7L_$zr?bGv%M^zN#`rwk=d zL#Kek`g*OyvSks}-#+N*i+C+R(i&h_^nvGVIRjX_Kemn@&My7Ewcx1S(pA5)jZ&mk z@qjDqIF)ZYqZlm=n?z(x{X@E|+;l(yRwiZRO_^h_FhOQH^k<4~riNu0)@rQMBWM9v zjLCQ$s%A@<0Y;7mS)^lc@i8!cq`S+XBvdAr7`d-&rW}PDaxgxMe)EwN%g1hbb-)0= zn9%#%eLuF~7_GSE0;lNR#bJ@Eq?QZzTxCt2O=?LgJEkM=v)v&924#r4VJ0GQRBC<5 zqn4i$3$Sly2E87YQf=y_6d{Xgb<~Pd7IjGthIm%wwlPKe1 zv&1yj2ncep&|{~bn4iA0je8v8P9a7gwK9l-R8nWiGxT>Hdi9SFQX)4D)vL#2WlLv% zZz=GVGZ zk->s<6T&!;!ec8Ks~L9`*F^td6*|Gf$0y59UVuz0aVR11cgHQuTA}81nJIJmq)_>4 zn`-R0rq0K#n|M6wd=bL#P}=HybA*FIMMe_x<> zc^^cK{Ee<`OZyru+*kHRy zoB8SeviIc^<}i#K;DRDHo43rj+m^6r>bC@=B_FBZhn*iNN0jMN8HCsw-&B}Aee7X0 zC|vh(GYLKqkJHVuJv3<@uZwP9fz?qAbFr!6$$2X_zi5>iZly2#bsfXAnY}RJnPSI^ z*tyatw{{iEx{nrgFnmsa#WA+sDm9U8Rqc{K6|{Jcmz_?f&Z&`-`wbA&2$+92Jx(ZR zE+7X3y(|&2;*{rO%ke!X+7sFiIrvo>+_`VXrKM4HKspU;T%fJ0^5m-w;9Y>U9zx`+ z4Bd3>MDJUP0oSG;aROL5x^}repn(L^!W5aSPkki+>rL^!c&-_-w+G5zG<1ZLk8RS| zUDJidpsyMl#6vZDf(N!jj_ksKKg*+6_qH|3lY5xN*WAJjm*P0d*26({98*9U9=EkL zE{;`32HIKK6>^-@WY$9UE=}cPSK9NB*XjjdIMM#vBH{ei}}nG*DN;YUe>KCZz~!xYg+%R!q!gl z={LN5IIV4Y#PXe9b$$E60 zr214*s?GNp;jufWmdavWBzM8%UbO~1u z;_K5bbRY!sO}S{7;+t&5r&~emxI4pbO}u{jQ2td^ZXQ4@pCMN2 zlIsI~k#nhTFeH1EaYPy-sRyr_tkR-;_K4kN@%)4R~4ST&*vs~nwdY`_yulig;!@{v0Ex+d|RQv-QL&=r?3 z&&QPKW1n73D+>*mLhJ;EpC-)Cs=Z1Ru?b{!PEAj5H8!g1?M6{=S9Q;bO1UKX)12*! z+dWKmiqkNM+ATR$OW;7{Y)?YXWD)kOhTl$bRxDm4CwAy_<^{a#9ZOtKk+S*g@LB&i zeQ$zIIB^&hBpsuLLYTj>q<@F`68J;VEXqD^aaVj6<))TtvSETS=b?jP#@PNVoWHPrTo&n*ZS8f%x{$RkzlJeV=4KL zjD~wj3CDG3l}bs#U_^wzGmh6(fTmnzQ308-L*2FlxQ2AHF}Lr%dKMC=8=1t11e@Q% z9H1&AjaPc13PG}O{xM9x<+aGZHr1uK3tx25$zVN8A<4h$#7l;=97?jnYZw%fz4Wn3 zgq>7GvYZc{@^KR>q8ghls%ifBA@~OLo4bXJwW>0N+zwVFaeNZ;+{kP7d>IE>N27Wo z8o|X`Up4iMh2uUjjNZT=I+T?D5IgFK+I8ToOAk4_3Fv!Xb8@qJ^X|Cd@x6Jdbg}^l z$|OCGtKilQQ(%S*AG6B6(0@KjqECPFB=u86QRj$?4O<54O3|pggY9~s zCey^5rNNNjLQf{gE8tWHHOogywiG}J{3%DoU7Kc{>Z`5gt$A%-qoWw`qyQXSj%Hl@ z@diaySy_wRymUc>oSB$goPrEdt7{_-Z6dqR9t&P*3Mg74;B~;J2UGFGJob8Qh`kyt zxLN=Ht?JU`;bIh|7;pUb>l%ZN>W80AZgB&^+*et<@M~~8-4@^J;{(rU5(Sh*aVD!avgaaZFtC?}bNq`JT30Lg2XOvkf0fWX}PWbgrb|91KkEEHjB%hkZMi zi>h!!@zvhul*w(&v4Zhe?aC36lIx7H$Ysl;`b~=$`58WvkBF^%kKB8N@i)&$nTB8y zt)srZ63G7LdjfUt+=&-Ij=c$*>^+8I>?zEQ7-Ybldr*m9x^8BOrjcusw1~IYB-9@C zfZ?>rBk^I)hOdxf1$J|zeU4`h7tP@bB?PwZg<~&}NtyT{V;v-3a4ex=M1~G}6%dPD zzt+|}!*|gyUuMC4{QTr~pTh=#W5&&bq*FL?|F>AZCfb*fksbW2<#+=t(~DG_W+-^CD8~WB7!1mZAWVJxN6UAx ztZ%~yD0}eir+(GnL|l1h55fJDeR)O@HThw^&P9l#RX;noiTP?7%eqDIif=k@kC=&$ zj&`R8_ubP~nu1F3`!5jooU-`*kG~^UOA5fZ*Iu72S{U?q9|9|1Q59F@;iP!v9$M-J$FqH^A891>RhXf zk#P3+1~#d-C)yar4%2i@QHnn6gIBQ$SzorY;tVcEw74{z#C;}Gh1iiOtWk;@8Wamw z+IZ)7J(pTpFQT6m(PM(EO*ys>sp|J7S?sXULn5LiFdWuN>WE_CQdYOH zn_6JIHz2de;`vSSWcZLW>FE9L4cbiqVS1Q}akpGR{>(%Ki<~= z&KX!$VD>`rnV7MHqvcxoSk&`vQxij63F{-w{=kSB!;-h8sP~@B6?V3~Jpu;P;_)6T zmDl53C~Nh5>SriC0&@Yc$-inbq6=hM8s!MIDd=?$8f!aoej(hHL1lU3k1C1cJ4TPP zar;n4j$PveUG0#l9mYX5_FVFw78;YlV%1>RE6l7=^c}a}=GG*651k`nNSKy?K3%4z z7o7MKvzBk`Tm$37)jG2w1rbkYmftqvZOjj}z-qFMvp@)wy*hT>`qN3{t$=UqAMWdd zB0KI|9)iIgZ{w`Le>20tnKCTQrgCmAp9%rI_FUf~RK( zxzGWOTxtS6X*4?8dCO$UhLegRJXSm}A(OJ%GgT?1qT1>ZU) zZ4M?`Mn-|2)o5GD@}+_sWN1eIV9>YX?Ve^$8W+-F7+Tk^xXxcyaHzwcQX))grK}Ji ze^MJibDa^zcLuK#^8ypN0W20YDuVOALtovk@m%MZsa;dD@YJccnXrv$vmBXMNC_T| z2YbNkMcssU3J%~9aVTByU)#FHB1e;EmN6kjrxg zF5@kLFIIK}rHkXWc1thZ?8d^NHx^cf6zmm_w5NM7{~E&}-vZiLP-U?N zk1xcWg9&oxTp0AGP*Q%8^ucsf$$wU0Y<~lQELpH~uZCfGu{5G?hj|pbq+2$vF;84S ziP#RQ68V8Fs4|pw{4zBw5_&$_Z;{QG`|{=KWq)^J#lFb>)&ODt6>7k3psZ=jeD4dj z)iNa!oo%>598%Wq;FbFVea*_RV5}dny#W=VXCt_%lK(%-n9wIsJbeon=&1 z@7skLx;uvMlJ1ahkXDpIx{(e^>6Y%4E)|dl=?;g+AKi^~iS+yY-?dnLVli;$%yaJ8 z``Tu0O8|`JxFO#ys`9$N2^aXB$|=g4l8! zD1~$8bG0iqNtFzc<7F^5UHauyX)!%stAyHr{sdjHK@T8t)(_fUIQpKwRg*_@HncrR&C#sFN*@+T zax2LLdrX7kn3{x0}>$idj9 zMFW*eo+91j$PIa~rFNVsT@m$O0u7Tjx`9U7fPf2*NK0z=`hXOl0VcHmXgn`Lq?Bs? z2SG^7N>TWib-Mk0-43$q^9&I5`t-c@LgY}BsIOvTqA=Tjkh24LugbR|Qs|=|BOI$X zz_PYLNGNI~U!3m?Mv2>TISS8&a>0^{N~@8XKAq`Qd8XS~Q9}3mmqJah#R|)UsD5z#+rs znCCO?)0yA0vj~W&0XHNkeD;dJb56o?(9SYB$M&LemiJfphtSbFnVdcHm|~LL+V9{60v)mTe>ez} zN?d!tpLcvW7Ndg+Rt<{nC~V2u92QAIm6x&&1?#M)6;mo3z~^W+=UB5Oh1V5)d(q$+ zQ^$tDcJ&Bc^EE4Owr)FA=BmJDnRZH;s|eW{bgC>1<4mu?c6Dv0_eV9Q>)J3f@5KDESJBVvnw67G zeFxRDtG*ymc3nzrdA0$@35t(u(Z(mKOLZYq5YOJV_WHAX7b1e^k|bke)qrPn-|Z*a zHLrOmkrpE-Xe*6@9k^I>?BRRmHkPyI&1-6NJ@WQ3ThWAh;K^o2!P>xY>m_C~*}w%v z$%44^w8OtBEo#^DdE@F;8W0D~6wodI;Q>@>vZAul>%-1}<|~$kR&S@NHXn6Z_%B+C21yGz_y+Y#z@kP>-v+uPPDEbcB_^hx4n)Ud zANAqi6VeZ79yYhdi!>Df$>w9!DKy*SGa&e@KDF!Jn%daeAp!RQ8|H_x=RaOuTiVuh zX1Pkv68|3CAicau@FQw{s&W@(ARuSRV(B%WCBl%?R;aly~LJNr=W{vE>{@D6I=9|A^AAP~QxN zdK&dA)zxjRr|qG)^9my)NL`$1Mv^eoVVGXHsHc^X+C;oTIGd!ud)u4Nj2g3to;6o8 zAe`=NOyjBR?}Iy5Az0GD?;x>VS;MGw19B7TLD#Pb^xwJU2ojO@bVN3B6ZG_Oqqi@6K>mM8njO-DD7mrv;j=dG}0smAXe!%N1Sw%ME+{%#is-SxzdjZTK~T^k$!l(*>A&* z>ZU6sgehSdQMBXAa^4ZcCgl*25c9Ek+?izO#T0!1l!x@jWW4yXYxGC%jN?ja+kTT? z?LGfV_@{J6hD~3SFvTWLd`P#dXaXM-OL|tQ1&DQkKfdam05MOmnf=;R!UQ==G|m4K zX2R>SF)?A*8@bpqLOA(wGZ~$2QJVOuO@c!t`KZeOGOd00X*}P@%Hy3%E_#L*vPNkN z5Q0SM>KCL=-~iLjm?m3E&ikzW1i;3Jgw*1)aw_z>Ae@+wv>opT=QyH z5}APM!6)6Kc}Za7=t(A>#3QA}ke5e5_!u=IUS~L8D$qE1#;Ge504i{=;{b z>Y_*1LggZ?uy?FkBFx1hR4ClW9=@d7>J}?m35e89ege6wD}pX?#PF!c4FpG=_V<%b zSEZU0aG-qHMm+^0pM2hHtrG>B zY*n=KVJv<5iM{rcCHSLfsGP!5!>|Arohhk|U)%ER%{M=fmYAa^&Q}jtIr-Ye%uP#N zABPjr%#r_B@aFabWL}w_ob*-8n$teh@3KQb@8}C_!lI#aEkF-A*8Y!Vu}m@jwVMUb zONw?{A~XSu{@Y`0dv`-;FaA;0R}|(5vHf|!tlyCA{2`&V{3WKFjmicIx9e7tDRRdh zcUQ5aVXgDgjIFYg;Svq8f8x{}Vx0aJRiz$Uv>x$hjs(a9_5iIb1CkNF*os#b1jTR( zVzYrR5SE7H5SE3XkbGrU|6x}8mSpEnJcLSSRjdV1T$$!fcCn|IjpKHqw@wC;LoTtf z@Arp{V9v#eTK;-+W(qZ#W{oEMB4_KQ-T~Dzsh{Rd%Gm5Oq^z5MPviZ8Z#F<7Zk38io~_FNsx2GS-om5`Q9oU&Sd8BX+R((9!hT!+bg=SH|AfjHinC z(#(}AH}$sy$twAALOALIoUYRGBKNVIrL-#!j%-TibNGF{+msjhOzlvgxVWJR3 zm4vxkFJ|H;5hiekHkn_RN8x3Jd&a@*x}kA(n}zT>Bf4e>Kk}-BUkpLTF z*$C{Y$h4QRbrW=|+fS~?mtv}4@T&g#2BVk$8^yq8=}zwAFe8=6K1<41Jrq~{*=z9c z;#B8p9KMBP3eTVLU@9^SjBHQ5Uf6oq@yv;62?=@#xk`S=oB0$sfju{jY0ao_OK}dF zP1R<97SpSGIHtr{r`gwi9xI^;9+sCKp*sVvnCx+)}Yxlu*qiE4YLGd&gLSG;Vp zV86N}{%KbL9-6BA9Ywep3;(6SDZPRk)E_Y%QO%WSSmCW%gRJo+-rQ}tQLoI}MO~#S z4$Sh7XHJf;=8_mudyXqR+r&md4a>p$+nM+n;pJ>-?Gfv3Z z(k%`>>TjIlAC1BlIjCE_#f~DNJpn7zsV#^*g6P1_N>oa(U<`SQB$b0AvYP=Lssm!6d*{@;L#~?VpYML zB13~-n?jWq@Ptm@;i}STDT5JXQmWXeC%KLv?t<87s}@w&+rmRnHS#NO`G3zBSH7_H z8QkRAB5zO^AU&;p>5^D;c+z4x(eR8MIrF_WJiTztl>*?hTTdXTc6wd`ZGed~Axd@A zV#s6v?#k__d9(B;e2%AOr5ZX&;G?q+)~VLb>pz+KlLZjne}MFHO{UVwM_dH$RFsauMkT#w+icQ=p-}as$N1{g zLYy19oCQ5f>3AYy;>FfMUQbbzacCLF<7D&>o7GDYaSMpaR0jUON>>EUOJ4?hca+x7 zR%je&%x9dY-r(E~A;HyST25St9$h2TI~)iqYokVb1!MXNj@Eesf`!$~Kiyr00qIrI z=+~TaEK>hLC}{RTgFrJc=81`AuRAS%WF^07xVB=bzyX^4hO!uyT7+c3NOQ%0C zit&my%=Ps)5hS`7UuYiYIx_ zzW-G#=PUk>-alqsF1mco18EN%66U7-JEF-`QL&^ZScK$nV%Z7xKUvQWyf76|m9eE) zmKnJpc|LyGgb&ZfkgvB@w%C@5aF0J6n4x?ZN@0n}O^P=@2DVS6AZql*t2ZCR>o`Ss z@&e*d-8NL0ojy75DCv_t2r9n7w}43ljPn*6uX$)Q-L!!84_dGCw*kCt|s zd%8ojJN1vOm0 z{(F9Wy7`Cqys@?s&=!?&kS5=Sn7U9^=$SZc?!h0_F7j2NROlt$s_QxziHe%L$>yc( zh&KA~d5%)EIWtKg4#9k^lE?S;-es>*+Qfv5QTaY&VPbi9G!13t{WB(JN6^7l+mk?x z8>pLlIi9Uw+w|nZjPU+X1k!t;PxO`mr_L`K=nk5^bir2&LA_`@D$`5sMcde|s4^=~*R`7( z-2&`BnT4!Ef#G)1SjMG^nD@MzM0K2GUQ`kBAomqOHkqeiMzr8E*;(*nGm`E>$jdIr z3%{v(NTPj7w~{rsbcyNPS~bgNsfLvD#v?WCX1&y49N)ug?F_9YozR*v4^^U+%W;+J zgNC-2HO@(-5P+a8D;NW6-La2O!7yA%q{kL1XUAK@R@GC23ccXh2OMOJny@1zLZ7PG zLC<jUq)mE*+d<0^OT^C$%M^o^^lhGdR71>;C4U?2UQ!$Xpil(wi}*!2BLKY{7c zL}|vw2vQ^xXxCiZ)=cZM=a$m!OF3OTE^e2cnuqIijXUF2J?7x#2nv6D)^i>=*a}E1 z4hbK5*8@%wdRUCsCOBgk_}_rm-DmB%lYc<;ZZ#$k1+2zW&YuN!aKQD!ngC zK~~s?ic^hE!c=ylC$-=AEAP`_mB` zgj%e7n0I`E&yXt28<8IJ)7HE`7HG^8J2)Ucbo+D9fv=Z%D&m_f29{1E53x3G$b@%-@e2-LIhpEr11r}A| z1jp5C$uS>~>tA+nZayYBkZXVCg`5(}6i^`L$FYqr9Z@~~+mqhNf1G&cc^G>BM+@qg zA9rIwMOVt4y+j4?7p0T$(Tp%yAZN1gzYLOjKjJGx4uQoqG6Dyr?#6>QuB0CALMvz^mm` zLGvY-h_XYP8d&_8b!6dbVZ&gVBl+hV^{AdLx1ZfULp~_cxxyDzl9KtR4iVLqlfv)s z`Z4GIBxraC3+(L05k~G_gted>=k-9}dV##IKdnmW1jX}C%o-lVkEaq7GTV>$ch~T5 zW}e`XdjWD+MYWXi?76CMC?o6?&}kCxku+X4`DBrAbgUh(lYKBh^8+%6^B;2%%4tv z#2ejG_&HVwWNn{rA5hRC{%c!sEfd%In0&1;MTqXBT%CX)gcp0l@~JgvLM8C$EL4 z{Bk9x(LzUCu3@35>OF$T;Km@lx5ZIp-cdx3m|}D$WGK`KuWJ-A4y^PT>Kn?JoP4hM|~2y$jB zP21Sqay0?(;ZhJxB{x8soo&5*iidmi}e8fSk>c%eXAZHI9_tP{AykPZy$OLh?s1h)0J{JWgkBqzi;p0(_C%~5! zc~m5{o`0KBFYrr=yDKHKl2GOc=J(6P5SwjnoSv9vhSJ|jw}12gOQ5F;ufk!F?bo&K_ndUN2l zBtc(^+=TF!Wq|0_t3eSl?~*GX{!Klj8Hh}0x+1iPaKQ&x*2lGa|31&|(?3XuwZw#qWMS#TW zK&_;xX=l?A44AV6(T8Vgq1GX$o+flA&&Dz=WzUaZrE)3uS%}h;P``Qqj2;?|D#y`KUZK?73pCUDaH#GNHxxjSIPrS841Ah6_X@o6+HcFlP8oe!f;>`07o;z>lWVZsDeDNLgqlV#b&5Qa8>8Z9p-`gExnLTyBHzg}pnBzFeADwg7@f}?Mucvs zNa1hE8#8spJA&|@rJ5A~2Gf3l+>WBD(V`??PxYPpITj8KJPB@7dO*8VOX|2{PBnOK z&~_4BR;?|954x>dIWOVlOzyfowx(UPyEv+;9 z^*QG?OKPlKre?Pmf3~97q#qY2^aR@3XUY>=s;heDYs!Wt0oC5`v4k5 zULGRuIjqM>E#+leFVr?-X2z`Mm&8`8an6Ydgp*^;L|+Zi8{{s>i%-Gv>*cxp4O0&W zKB2|c_MSx@WPZXL>w@*)Z|?5oF-^lwy8Mf=l#RAN?P~AM<#(?8N?K5%{coBDI{LpC zpIhxr;|6X{*K{(N^YZd*M3uFU$KuDC(*Fi$ETIq(fSfR(?}G~h3CI4RYoNsB8=-Hl z40J%a(ZuzqY;Y?e5@g&YME=KIRQUpd$~u2far%tP&Az6E98CAveqC4A2m?9VZyd=V z8CJowsF9B}AlG{}g{{^2hiLv<;+_Z7s}puL@v)SaERO`-X3B*l52ls@`hQVncC`ym z_@(>C{U5=EE;n9ze$*U_3a(z0V{pafZ=8$VuQ4BI3fSD#;j!N~?>(iuz?x-irhLMl z{?xx)qt~mU?Crf<=lZ$#nFOu!6eAh0l0`1d!@qN+8Nm&&!0UGagT;}Tm&t}PaGi|# z+-H^m4X!?|T{^B=y8P*}y5-w3a#zp$d@OxiF6}oF%t7`~u23{f6^A0yNKnOS#{48S zRVFhQxq(1TMzKKsvF^R75qT(DyFOLb=*fLyIeoM@B31o2g?hV5m8BuL_JD*|WswA9 z(bw|g4PV4T35V#;5UTWp*Ot=?k(u-KdB%qunkj+ZSTj~!j!x#5_kz^bcH+6QRI;H$ z>Ix0CM>`GlDymgle?r8LY?yBysqct*H2*OBl%xrNx)BD2|QjMWKK%v!S5QDxO?yZz9W z!MOf$RmkmtTHH{H)HD%iTUe<0!Hm;Q0}Z!IkON!)k*+Z=MNNvBM4n|!7P63Iw4HueAs5_Je*Uq-MfABNQQ`Xo)YSP|jO|M_p zECO=N#cGKS-K`B=`9%?e(>OleT~gA{rfeUbx9j4=RAVj-#(3Ass7Ydpu4cC4cc48VviO?q^}b-Y@{OCoTfKI8kqY*G_Nr+ z@v8#vKZAH-)kU|ywWsd8Djj5j;KnmNdeICd-H2a4)njxlB* zt?v`83)ebb>L%8PEDYAjV4+X*qYT<@KCyY`z|tWEmZbw0IbJC@lYVzAAK+q<3W?t2 zWu-?>viOI!4R7VP-K&Le;zoBTH$}G@{i|pE%apR_T1S89M^u>BQ)$c;jk!9+ za~j+_4-)!qFZ?ma@fFvhgw}opuCudqixCfRI?_ALg4bc#D9+95>6cOfOd=sE%?RfQ zinp@4V7Ivbrsm@a$Mb4Nvm~qeQ$Q$5@0;ddr!AJd*~gbNJXHqt(vzmt*inI|Hm;YW zYPE{su7W|Tu+a!axR99o2LKlOio{V7$toB20(yMXZLFW(gLK3w9=i$eiAMcxuSH!TK{so zp6nYaadoAnrQxs=Ale1pH_Z*Mm0t0O7huW^0HP^-L9>AVkja7@GI5E$2UCBG!c4V_ z29_GwcnN0vAW>~`3{`I+*m(~;o;^8*BjUN4#8VRK02eUMdZyblYZz64^Rk^Z@BWcg z54L`MO)^Vy)Qkqyh~RAmd(!<@wA8}B|F)h?y*OM|BjJ) zV(1V6P^_Gu(VIi96%O#P{S&~Fqq&*P;}Joe<$C?19PJ{G^26ejue+1-sM$^HG}re_=I0OZ(R zIxNXY13_ZTsdSe>#+7QBkF@iL4;_?_V7>LHF0nvv%{P zBg&Cw7Rf6<3`q!{mw{+>$pD`=U720rPvcLvFMmV|>5Hsn7F+bVm9pWcdqB6K3Wut5%Kxyar@M9{{|vO#@YFN(3*b~K=*894cdl00@RysQ2` z+Mnlw3a0dquvNa~nytzUMi#T5vS&9aimk4nt>5qC>L_b2F5RD3eox-t!3aSdCU&9s zlytbh5KlA5QnQa^Ly4MB{SU;j0}(=LLy%>}t5JcE<_?q>*L-zG`lhaNBb5+FRb@^> z!(`5b&vi07QLmL=IF-l#14sgW)IySj9@)4NPLd`ARj5jGs&xO#Gt zWd5tStwWpn#?!3i_4!8DmVrk2TBH!q-M<>r`MTyI0QgRRwf?lhaY(Q)L{Vl3Atn*fcE=64Q+|GoU0)38GXlwo;uvO%aU znlQTg5_Xl9j$sCi_*U{B86WJ2tf1x^bCTk0Rod@_%3LiA1~!81jJ4C4V})B*oq!=$ z3VFHu9b4&~9981UlmtE8T|re}aF9O>XZ?w-L?`vyc$?6Z{%`4)s2sauR>Y0@o z{}Gi}uZeO&(Ly%*4x%dA2#{tNs)T+^G8WPLo-7Gi#5s=F+e2@H(EHfNOcTD z8{P^t4N<0dE;GM>8@}=~qq5t1Cvr9YcU;y!w21S}Tf*h%|HxKq?h{e;+J2le3#@&? z(2aB-YW&d)s_`j|ZEp!vK$+=UvuIoDF^FmXw$myJptJ2XieC#jVhEql0A zlGphBqZ=n;FWtK9oix=uy<%i-YCT$9>wje}u&auTvZO*)q$ma=0+WS`mc)jdPHU^gurX3kXUT5*P=}<|%4q60h?zzO zeP|Pikaunf%nk$$3FT~yV{}#i7J~d1AUC;|(;;n4)Yirk)gt^W@#QI$A%yYp_#xJ{ z(DiM+oUya9PPu^}8#Nu2=*M-$qP)!kSdr)XSyZ zqee}>rru0=A0-2xtG(c3QAh6)b%alMgLn>_3C1^-YLq%vqp^(RcpfK6rX{aA}EN)$C>`_SJChs zx;fC4UDtST)$@Ffj;GUC^)=DcixOY=m3ALi^0>zg5?V0urjTbPJ4IZOw1ANCaWS?Q zM&4k>zO77*K@5Kwxug=dDRoq|sjkAt`HY+9MsW~@|D~+-KE817`yIm5teo6zdJsG< z*l6MK<_9o5(ET&aKga8WT>QMjLv(yXhxF$q5&zyP$akN2qXYRQ2f*gM{+=Yg&AK{cSmVelB z+$n`u%Z}F5F2ah-p&xF@&~t0x6WFlv5OJAnG#MSGl2<7n{t}{?R9KC<4I2#6o()d7 ziFT0Op~lq7rBUdk%_2?5(ns8XV_~WC*@!um6JBe7!$g09{ZSFY6x)XU*XK~h*~H-E zNC;4gz(hI!6T}gAjA^Yr`}-G_R^nGt_hACrxmc5EK95VhG{*t+;WxRto8f*4=x7+= z*ne6TZoCVsKR7Jn+;uAFWz3)80wmG|*J6`3z0o^cVdRoQile`NYzGWfc&uPq%8t&t zXdP4b^+1!4+hgSGFQM+j3{QT1*Hb535uCo`6WE#3xT8}SXM04>!_5bJ!kWaVr4hR@L zvNo)?d~906+0AljyTM-mbx8#wm=QIjvWD6xk%;Bq*fvuNI?C&g`ytvv+-3v|orc@R zMe6b0;!n#>wBL}N7)`j-U^X9;=;?vB(9r2!i&c+jvm!bK_{i!wLAU#O@3pNMv2`9* zP5Hlzg%XD^aaXI{w$S|&Zx2yZYXaDDJi9Dr8ZudN?ZB$oau9H5&}b59^o#)Coz6GG zb)OH9sG;`AQ1Dp%I}r0&AsNuaE1sRRNoVzAw_=so`jivKtg&*e03)nVl!3#ISg4I} z)&SfI1oR;zspA`-9lEph)a6Up-T8FOl+AWEYpWH#X`F96s00E z=;XZn+HK(YFFxKm#tiRfK-b16`oc4?!7zh@ZXH;M!5Le%OF-c9i7!Gp3RJseopSdJJYQ>Cl4s{I3CcR?rO&@5`IekAA>pmy$I7XV zjK{M_g+y0IaM{mPVx@Y5jwM%DOJv>qa{Br(_yyULlYxUUC9xs~ZHk#sq}?X+UhXn! ze@Cc;y#jvv3u?0u)YE1~uMme8Z9{m`XYMu%UagCeU>{tjhP1;~Q+3V5%M0g(YxGMn z_Hpwz=+!=DxWD?&WX0LQTjFC}#MaNi$!a_MRgyv?H>Z|U0PSfv3;Pn&oI##dS2r&R zEkya}glhW5Mq_0GtXmT?NR3sL5rGaegREH<-l)FutFlyCWO#Q73QI&^+EH+(M$GD7 z$G9uEDzda8AS2`z7Sf}#oL?B3%vMaDQm_5RUxziw|3H`0i;G#8HSO+}z4uXNn#aND zdp{oLaPkGZCX@!3p6~8;`EP-rZ1$t#arrx`l1vdo9eBosb^1Q9X)6#oFGHZgmBVHN z@}>p#X*e4$2Yxc>JrFd!!U|@i<&Z+!^)F=IxrK?7DeB#FEXPb$%z1{drOdI(twCN6 zH3^eA39|nuRGA9a@Od=sQTwe7!m~hx-UEBOSgTeq`U|nWu5Y`oEGxh9A!UWh8CVU*(hkMkd^Zgp+M)&xmhdPMC~JhEXH)A2kH3 zXFTFk_2gISR|Gz&OhBcUC+O~W*2PS}SvmtbTHwPL?fH=Oqh#wnlK7Go7{g<6apFKYK*>@ADQZf^@u^btY>vLimB@%8S z(G$(Hn@=TS!rKed4AFn z^xCc4&w}a$_6KhXd;;<`s){s61$f)iF@U?@b;`Fb0SHTg^M7;`ZrJ~e=nATP0g|u^ z3jmb(|o`!@(Lv6+VWMm5q*FB9_{!W>}%L zv(99brMi9rLbJ(_Hv3}Q>3b-tWf4C0E8S=bAUO->j5>Fi*1GkX-F8-2di9#R>R$Lg zc-8x@;B}-jyI|d`U(K_LMr41x*s%0#QL1tXw|Gq{SdQ?}96TEk9F|aFO1g!I;;zF* zoL}uIfLu8V!#hSkXd5Y?3R0m_p~7$=1z6xu!OVRzV6utvfN}jl3B{P2$U!h z9Ur+VF?)b=xCa^oCaVAmKbkB6j3h3iG`t!|Q8c({f*LWdxh`GOyzyJDKT;rNoof^^ z->L!R1zba5fY|j(4iOL4{S-ihcfzRgT3#09nK6XmzRb8pDHhcLjKHDC_>7Fx{{f%r zwJEub=VtYZ6>-DS_as&G_stw4JlibJUAv|*{{#7K8<%rG*x-l>lyl)@{NTEnOPsoj zQh|c+G5$o$CzyewX2C)6HC57{Sh|mr$Q7_ygN-$i5>}bXT!!dovJIW5lQL8@PzW72B*SFCfwr;mAuueT1c%ASRnZMH89cIT8 z~h`0?|>gu*&|8VsP(SB8F_l2jrSEB+gG!E_pV%eqyY`F0UvY%m8%y%wXMv zx`Cw1LkFN!%$J-JNyz1}!JNFRH0jA3t`0*q<68HICH%4P$y6hgOFmLXOL%g6~o+_;Hi`8A@&#s{8PT!7(_! z(37K2+WejMb=w1CRP1*Al@5!3NxHwQ`ZTbEzQ_# zF3);a$3Or0rt0vGq2@20x5{*ym1Phvg1%z`Lrn|DB|jvu)oQPuN!k3r>_I4>U*rPF zYlw2LQZS>8V8qw|puon2xv36vH|9Hu}sNVQ^J~lHU~8gp6}9GU|E9d;h@YA`D_;yb>u& zjXFc*W%O+z)dyWOcPSlAW)`bhxPfv^>a=GEn3K25XR?e$c_s4fB!ZBJ1Qa!e*wkFM zbA`Rb_>0zK1N?m^c2#Lgwd5USgqV1#j`6E&j3|Ndi#&*|!eJg(Lv9hK=39w@5cE zBS`!bnmF%VN}Ovm>Kl6`QDPt5ZzK;{R5NVE9+j0itg<#Jz%x8ovZ;9+`VocP)Sl~4 zom|pP^TJ51disuGhN-zx5?RG(!lf}!>MN{~9Ft3NB#C^X+MsFO2QW)${YoHP)l4SW zZGc59aTn|x*vv`Dca%i(+iBHVq+y8^OsX<~01ZyghZ;K*)C{ML)vY*;aKf<~2otxn za&G>8$qf&gIS;df;akY)khT~*Qxz;ay0)$KV=Znywe+a9-38cWfU;2^o&~6uK~RbD z3=z;wlYYXps_nBTo$04<`u3uLS?$3^boh{Y|NARMoMIfBgd7hqoBj&zbak}$HRsGh zawQvdh$xMwD7BVpxmbad0Tl>=CCV}&AvwvQ#3uo?sDdE7Y%}!;D~uW#cQ6H>UEGY< z)A4nje7?bkZzscGP~GUk$xH)4O>K$NPq-)BB@wp5cVc}CXMeunuw~nB>gE?~O%#o6 zq7TZm_O$};gZh?yg$c_APMh*A-!?vcWD4Lk^=uvrXdb$~#%W$6$yq_2r1-(Vz3`Fx z>0hL@4EXc#fT*O!n*_BWu-~9kIxN5oSTUm>TkJMkzZk!Qp={55hE-7>MX{ zc1Ty18;;Y}&-)dIpbNnta=1oDMmIeq=m*jFY{2RMW?J?3>G55elAMmfDdMgwHX8By znjlwZztIZ;F#t!&)zq3as6r~1e!L zbI@_lKI9g!~+i{76{YbQi-FC3?L8di*ig|`h-}w;4FoaOLTHvRP z!TEpd#jRL}YOEBzz-;1dltX~kX6kF^d2`6*G52PHV$b$1>+kqhOOw=xFX4*-EPY(o z^HkGk-7K3|%PgQ?Oc(I^_Hi>z@fQA3<9IMQXQm|f(xr+D9jjIvRz`soDK#!WqPsfM+<4l zr7o$G-;)bi6b#IyqFtaNFrsJ}#vnCm#$mH&f8-sdlM~2QLTJ`iub3&SEh}d)>YEi3>PNF7G{m*;(Zv1}6IjFDf_w87QMX4$w zezS%K26qr;ta-H}6U3b}Cw^sHs*4W`#*3X4p6wM&aHaSfEQ}exGpL`sne*i`p^@C^ zZR~)WYYegAN4yGm5}By}bu|dx5gT&1-0DQ4;oG3=+l}mu{EnwvI5%qG$;+G{VJmu@ zlSO9`J}m9s)@?rw(2;7d1vWiM1|MEGs=myh%S5m+`oB#i1JK8X|!1bp|})LHoFiaB2zV@pe;N~S-fQxFh81uB`jyyOuQ=0vQ zRgj`wuNgNCD<+|CXY#+B6ME=HNCPM&tHMwP0PNhuxPJt!cY@3IN?oif!Cfmk9bz!+ zZ|xicv-YfvJyFU0Nns&|pv&uDmOpd51G6$3Cut*TbSii0{Kgy9TY%}T3`5U|o}uV; z7&~Wqdg-5M`SLWB6J$2-6l@otf3pw#_Q6N?xnO> z`Eez-%wt{Zv;)QV31n)^^XI0URG&{7yWB%5*_4aC>)P2W z6*hN znBYg8Q)&mLix17E9P#hx{X2~Gsg7^_z$zv>v`G8v>pK~}v>JwU-GbL7sxslK(+r{I zftOnWL&bq~a1|*JBfQJ}=Zxp;iA(+%7EiOBCxa*m4Y|ulps#e{m0~lm|;F8*g7xEz?d4$8jPiSw^)5dtsSR->Z5Exq6Am z`sgz&DPqA%6-}u6{A@8{FCZC+twd4fnxrMUbl5tUcWJunUm0ybp(Uy5JgeXk;1Pep z-D7f33Z-rzb#vN`S^q3W>!h6*tnJ&Fe+)e?5sXyGvW+*!=x}Sjt z$va#!!x^;)%_KBQK6*o_fvjX!496+Dyn$I?z56qoP?qrODFPEKHsnf)prr8nN18BLEVG~9pRmb)6hV8t9&Jq+Pc z^QhuO)WJk&*JK;k>)rp=N~#UNAx2DJn_IhcP71d%XMNq%6R(MQbU_qGu0@OSP__m+ zo2wS8;oVe`G4@0|LHW%()a^XI`IKCpPnS6naf=W#^O5b=3&k}Sc6xqqZyXb!Fh_~l zI4{d&$-d9_Q9({Y1oz(~?Q@j#S^$Y#5Jd;T%}fxjKy=R%!u;5PIa=w}4G#&&C#C~a zBKiLIQS`jZHerKSgLJx8F`1Mp^&r9E>8lMUm62OI`)IuMCe$qA)YLRP;v#0v6+E6k zkDR9PS&EzL;`+s{ z7ttJ~RFEd&B`|-M@7Zj_BAPSE{)JPQD2r73<$boCu3|zQha=jvkC-y?Tez3I_HW3T z>c6={JE6hz>}lwcm;j~=J(wAVQj5=^lRVZ>9XSTT_6X>*pep+)>NV43`#ypr44-#G z0N|3A8lsYfT^4Nts~Mc72Zw2#0DQtBTK2R+2hZ|FqyHbaXlV>JUrL%W>P?y5hu?bP zhu0Byd4&zV@I$;7-eOLSuyQj69p34jdcs%}?h7jL(_1QU6VK;K6Yi<`MEPe7=#|2u zlK$DvluAr{u5f4`Z(3(`Ud)9iO9KWm7eNm%TPav^ocu`L zS}nga3nC_(;d&*Ml-Q3*MqVb4`@3dx?`J4ZuOB|6n>MewpH&|wMrT}#V%PjC_-f$2 z#}2P21?jbh0*mXeUB%UE4hD;rK3xTzZt8MZdLIY4?b3DfY`B(3d#*Yuf!^1ZOl$qv zGqime82sB^s!|mpWJpd%k!E?KSN7Py7?kI{&g}n~M#M02-K|%U=h<}R_qh39`TB?DSRNns!_SF88mHMDHx7k18lIm*xH?0gKZL% zAC2TE&6J(~&k@SX&zEKtI{zKD=qG&zQvEW!L>tmeQL{Fy-0R!p*rjVs3pPbR|CgYO z-5i2@J$U;l!qWd;>~Q4e=hZHp;D;l80PnJq1%Z#tiZE|hPlsQ3WYo+72GH+#oWMxM z4ugs+@a4L%eZy}jo+h4mCdS1ue^OU1d5KAcn1vH;U%XHrhsL zy{wvNXv2pcZA}F2S7Dryux-D$1%newQ%2|&JEj^4s_eY!dI16A3UMm@g6PEP>E2Ls za(iV6D)1RD+%2Z5O@W@}I^G?vS1)rixPQFtL?S}O={#X7 ze&dZsrDku7zD0u6-tH+Aq(3gKo&I_+J=z}WdL#NP*`P)U_B2{#+5XS$YCQfOTzn>! zq)s;Zbu%1VCgvHikG3_Wy_x=AV$*H=XxqzBHcb>V!oZt$k?M(sFpPtIA1FwCYrStJxO5uObFPC z^%9vns3sN#3IkEsDYeMmi_=CHxr2>}OTSjfqCx&x$#~ zI((fR@YnZ?UEtkWB>z`IqH|4(f9vOa(vKn14;we2s%Sn$$+#qkHy|YAi^L+edw1=M z34OBrr$aA^x12$4)>avqznkRFl=RgT#*!ZAraX7e6V7W%L31IV%AjIInn$GO5pJb( z@u;W(n<^U_md}>MBP_-k`#*}#GN=kI3Zs|q?(PQZl1n#ADskx!>6DW025FEEMY^St z25AJPyE_CVeCN$L(eWs1{f(v4JPSK#4QD^7y_yod*Y3na|EyOjbUl~f3X3P>Ia55 zH=1oi@-#S-`g)||$E^`c3BheG#CDnphc1rc_AB@k3(UXO#feU{o1hvW&~4VR0)YV6 zV1#RrSBuff9(Zig9fb1M@1xSKKYIh`E{HJ$ziiS7Cps8EhT($NgdB-D!&n0mG|ej9 z)v~Q%obNTm4xUvqLw{5?4bLAi?303#*d9js<;{O)SD6FGGp!!8K&ke^0m|7E=wSsu zv0rd=>eq0oU9m~GMPCkYMkTWW9 znBp=7{5{|}YztQZlR&SDM$3?=izL)eWhIFI>x5JzW$)O0h5Op8Iw!&%iQjWg+o<>P z?4SC-fk`$b$7I8EFaW{RBxDlGp~7w#_iD#ltYGeAcHBBIbfk)&#~t|U4$FKktWF?3 zNx!c6UH&_YLAgf{scLgEs~r=l(r9R3r{snOXYRiLgirr@i)bC6VTH>Zf)Vr<9^Kmw z&o(srJyauHlz{3*`5+qVTk|rwex-7RB+eb@*PQkJughnlb$Y2`Ae#47#ao#-Lzf#= zGQ-9QjIx9%ZUEwcEYd0zg;GW!CK^CvVxSbRlIqvCstZSXREQNX@ZU zWa@%eb099N#xy^tL|0hCGZoV|PiRPw$vuCIs1f{9lZL_2!;+1Gik;7XVZo`f1Vtsr z?A&q`KQ;|pjY*<`sHkR(-*Ne1Ca;aRpbl-^mXoue=qxzG}rF zrIizBe{zZU*(^Nk59A{;vB}wC)v}Go{FC{%*3R`sa+7VCtI7avZ&d9VyxyAFF}jLk zm(QiN`U%cu7S8&`*5q8$hG;svVIZVYXzpROn<+w1+5WdbWZK@fe0y=*?@rxa9t2;w-_417-YmjOzM}$yOq}l>Qtk%37d+ooXf>0>J zrEf|@63&;UK_xGwaBu_c1<%^&z)h2<*udzP3}H|(U9Pr)wxOIRie(kaGtUiZvP@#S z*_)+BTw%~I?viF=lNt7G+Pvn6y&KIzh0@)|PQG?~vFW>&M_%wYb&sDQJ!zmL=2%CA z-#J<8YZJ0OIvsBWQr@r5(znu5g-#;tHgOTRa6S`yMixG;6jouL>Woo@qv(3Mvc`nA zhuPDE6wIBT;wbYK^<{{R@E_E@Cdorrz-5Ki_1mh53njyg3<~R(g3oMt!;T7p2Gf$d zK5R%$vU%>ccG=dH2`G(@uP}c4^dBu@M4~r+Ke{JU9i!_x+KGXVT^wAofO7o$0W(ng z@QgahqXs(^yORzX%XAYrHXyeeq3z z&vVFRe%^&Q6x8Oj%Lbvm zQUgkH4`9>WH+A#*h#ZVUGscjX#?=HybW@pRUqqO#^O!Gf`Ul8srvd)FGs&nEb|k}J z*Dzi(@H;sBPyPmRsWdK8(M||NZsD!Ub4~!R4Tvdz*H=j>3pW!`cy6z@7jQ%%^)k7N z%MN4`^4sFu`qRqrH>hYBl%HMNa|iHZsO*Sftvm9;p9PjT?R?7Z5Jc4ZSB=+r)Crn% zu+n`7cibZIFKsDV;%2{}3JB~amLM3U3j)eO(jHS_K8x4Ly$Dj}Op#{Lec06WjE2f|oN9`)A~m~hecJgCig)_?o=hrf{P zFhk*j`VG&eUa28zV!MV|QO9VOAU(pMcOUaSn?wv?OfNJT{;1BAo2^Sg)CN3ySxv*^ z=n+IxF>|@{LO&M2eHY!CD#jH_`CE^r@(YQ{R#N5zPC-;pSY#kPCj>5zRlk!6@wo=YWA^UsX7}UzwWt&C@u_VMCxL)xN6YXI#W1i;{EQ5k|E6~b#o>2V? zD+|o)!)!C$@G1scVydU_^cJ3YcsbvEtTPyVtI<$Dvf(N@T|DS3{X@C`XLqN;HeMZS zTa-#~TC1aBqi=$1@Up6I>2%6LIIbcAeOmE)1tD?h(-%#lP{D|t6ayXN+34gzR4oTR zF7jP?D@|Zq{ncSA=cQKVuWz8xMmsp{o{l^{^HM#0XOT7Oreie@hY#ca_1{&*W`d7n zVvHuNtQT8Xy*R&lB&uH>5Hebe5-HdxGln~+n#ny=NOOmM*bZd5KnhG$S-1^`+iS38 zb-eGPcYk6=BZ@WuL~4CNh{yTLhJB`Rck5_9FSS~#dQ%pTV*V-S!5R}WNu%fN-}Bi; z&GSun?~bqZ`#{sIOgYgw@$@V-d&q4C>bunYy-$J*`pETEutnO7bBQSv6OQEa(%*Po z56Qox%WisQ4KjBbdwCJ-K4NNSZ8LDYwY`PPE9Y~J#rXZ^n-znRn(a|mHl^yYGLb8d zvNS3!?`EY`77-3*<0kKKCa!YJ`>RGIT8as5D*!(D%93X?aO!pC1?w#BazQD+eaa_(AY*w&pLj#ZV%SU zhBUEn*zfPtgD_?vghTe78vW-7GbtF+-Qy0y3R$WQj5u=_ z$;p*RXBN4NAi=&3Q2;xZ{B5j$3DfiHp5 zZ7YEk9sahU6{#Vo?vAWsOU@TUCcPX&}~}$ zB;WRClJu?~ywUatbUNCX7rQrbPS)qDlGpbA0t*PXk)@xx_iE{b<4Alo-{o+i;n%t4 zHzudhiDHzPsmRk91h_c9D@`Io5?Z2403g?nAWd@FwT+t-tXnaHg#FUjCU&f78BskV zQx(&qD5VU2WGaixL{`d^i@9*jS%vYx*kKyV6uHl0Puy$5U1IPuO)_usG&mLRFIG!~ zdG7VuYB!laTlLcZQopbtrnP6CuH=x1y@CITZkibt)XB)O*}09g8O%Xzk|$Xe->P-~ z>{eJKscGt&WMAwN(pQm60a2Of_ViX^SLgJ0Ae!XSER;|ODh1-0a~s(Rv;K1MQ=sN zDhy&5t3Ge*7gT4587GU@&!Ur4h%BZBuDg+UrrJ!sgd%l|o~%#jxp zJ_$Z@`=LvAO}rqUZk7_BSou8mlG3r6>ok!9d~&_I`vlZ@^f#`qSiD^w?k{&R3JAef zr7+$MdUq1x;{~oLr1BEq)=o6jiEb|3h)t?>f8~Z|>+`lUe7aRNqT}GZmQ8fB)F4Rx z-sx9xhLYzOEL0YSZl$?#aE&M@#SvPz;|W$FPiB$e_30~NG3&G*@;~mRX>O=H=FDrh z*?U>cBQb%q*&TGyrUb5~13rkoItl>jV*qR|WPR7s)deni8y+t=+`dV%g?lyho_O_n z&6>BbXjxlgd>-DGB<)JCKEo@V68HVF6=ju-ZTY6gPir6qy>*Ue}q~8g?GsPO5opa22(F=rz~FXI4EZY zdgK-y2nao#VCS?E_c%yUBF=T<*OpBot2rcIMY*mEcvU2%gMkd%K0pqO>6y_Q6Bw+W6iv_>3vJ6eT~C4C!ehW94t9L`f}D z10M<&21hG9BV|f-kixKLV~+O^!_0;cS&Q+Iv~4X+FEQ^&@n_ae0;eusw$w7QWd=QD z@o2+~`0%*3j-$1YW~kOCEnX!d=u#jsVAB8oaw{jvpyT*O0}_TtLPBt8F~BCjOoJ;O zU#sN-Nh+*u(nrAQ?|&A%Si{8sITjM(xGLXxqGE|_spM8C!Z@WKD!<%lI}kbiXTE-l z9Gi|WhANkxW$VWVdJE5QH_txYc$R(}G4Fc!1N~NZq$zoL#t?I^=!lLXAB8m-gESAA zR(@qg(1_!lS14xv@^S3aJS~CK4a=C4;Lf*ca8wr^xRq zUvFhu&S-H2z^Cc6j0=&5N+~}{b;_CiSo&^O} z`_WDwpn8Im>Mep$4i@cu<$Gdf~YJgIZdD%3RIgHaBt9HLf`EsuHZOu7VlU!KF*5maLI3W-uuVX_agDDqNN3 zPolD9Ga=6v{OjdY^I*ljpo$8BNgAz}fo-=&lbm08Z;G>`&#A^bcRz!W1&HAS)aj}Z zK$a@56@EsCN=gDG9=!`oHocd(K*bE;K<~2_ch4ldwyw(6e?{eA16-Y^wxF?z$@#TMzjb@x zj(=f;>}-?a&7KUqk4^I=fvYOq{c!rRNbysdU8BehJahPhR@W1~{1eWkE4_I3w8{W$n z-Q^FFx76Bi`W}M1%5mR*zQ5U_t{ePU_T@qo{&R( zkyVCvC8GQ)7r}7OO0@MiLnYb=%T{yD^I(d)ajZpE@CcUIBt*r37@<(aqA4b2;lx-G z8txj^P=2>__+BbQXdac8J;Z<^(%k&JVM?YPE)?}MCa>wmqc|escYQV;dR}Hl^n6rn zn8ulGKr~(`<*|O{_sVgm#uAwqr^rb~7BKM&$zN*G^XCkxhLoNwqbz?8jka=wW=EIt z+@+YNu@b4dZMI`wgu0xNP9A5QCBOyqXD~Neuja;@WgWx=#HHdLkuA5-2U%m~mSGF|$n}>)5 zv79j@1KK)m%cYAq8?p!w*E#;b>>qP>0fL; zN`kR4Z8ap5ILnDLD|{CjT1~=I(vCOXxg@3gh$D=Lj0iKxgO*d@FfHCCGYs$p2LT#OXs->_WlCI zMy=}5xBa7Sso``BeKwLtnd#TcX)h^bx?hF9cGp*oHY;N`(eJ4L^DSKx%Af@)+sphn zxMvi+Mu2~rN)JUXgvh_Aii#kkLBCL3+nNk~MgoqUBFL-(1cWf||{T@G!XbT!e`VR$znBR;%P*;mb|67s%Q zzs)`!EyT*Wi1QU`mhAe|o6j8YeCUYZTfy*pCIH}f0za#?+&jH)U9RN42TYrjzVyS7 z@2Nj5F`<^iImEmQwvHnLGJvNG0%ELVl($1zThOTw%E%iLt}?KN&lT_=6yvLI6YQ+F zqJn~4sefl(!|h#V^^{syI!i*=Wu-XmY>oXhmmeANn5Tg{I-n|SLU(WI++n@Mz>OLbTPZwfwfB!9K->nQ$k#+I)LD` zDgQcTjLTt%LUwIaPUBNv9xjoHLnRjV0>=wy8$kU`^+B@W10fBhvCZjQ1hq(lxWe|J zv?P2auLzt-@m%-TmHzOevhbyP5#+b2q6MTun(42NIph?syr+hI@&^966o%PmqtGe{ zz@In5A67(Y>I}CaWgL;!?2)_+5jOY*l?Bs^eZS*B2HW_QTcNU&CH)d1eO={_OJyrk zZ2#{}^sgMU%J9HL`240kA9Tf3-fGx@R(Jm!Y^L7lAB6t_wc{HU=a3xd)hz8~YGXXmRK31%LQ>Y_;65q-l@ z4!1C*YH5g(U143ZDPTs43`TWP#ptjtz-O%}AwYxx%^a{K6%yT?GQNqH&-HMTMQm*T z{6@uEds>JG83d{jX;Q1@1G?z>6T3gN@nFP39h< z>3R_WlNfRT#T*vpOo*Ssn=YYJnlNHu@= zxv}bO7^rY8*N6D>IdtqcIw7uHPzQ*VXwU3rTjGI_c6_0Z-m>Hjf-+af-8#ApbHgjY z@(RvUe5X2*=ENa0x%cfBSZA@SOBiwg^a`mVT z9yxnVMpb8DY`UQAz(i#}&V`f!oz&j+>yFakx!c74qV8^Nh`%#dBy{%XU9xkDjhE4t zec@}L*bt?}`Sy=e9~Ny^Zz-OAxQA!Pbki{>{|`AM2R^(Hj6J#!S-OdNcnVpkY~-!C znK=5odoF;InnvGV(Nx$!;ukmDzhR5ksj1>xp#Ch*n677D=2IhzfIn-%I2qoAtg_gx zf`{r(s*3qkCI3R!!bgEj+1N5yk_}yok!@M=+nU%OFIRD;MQlAg+ySd==Zy91R|PTY zo+H(8Yc=bz^Ie~a%HjE8(-uy^@Lw9I_DQ~a!2JCVNx{Xwv`+H4ApZM_uf>J_?(3j2 zksRIxhRD(a9&CnAYkPPo$CqfwrK0p6>?*-O51%|niI4w?*;)YL``O3B2Tje?O9wzD zr8rea|8+Xd%26e+FfD5@OLbl^WryuEam8t48EjUdvhC#-{lAg9GpLHoIk)yo$fB6kuwg8Tw8#QzHXRPL{#Qj4e&6J7-Fe=`h5CO2>!2z06 z9=IX8LaE8Z__%Gek>{;}j;!4_4D0#2ToR5K+~dGx)Do7^_GQ|Ws*#!E(c43Bmn_FC zl(zm;n-ds7jzWh5x--mF7YDfbS8C#TWduG8e&L@as|Qnv0l8i{&1pMCyeA&oQ5gRO z?cUoH{-~{$g~84d<1h`;xx`*SGhIc zD%el0c{T`j>7tppF@;$}@T~tGTusL2ANU**dn2W)#?Bs)<%4bWfp>rPO3@2;y{d2D z0%|?BIyZxn?jJ@&+6b>+5nI6+JNiWtS>|16WAQ$Qr|xc_nFS_ADQ1rY4_pAi*HT?A zC^A1KSCtrNbmU;(qe>}r=>-LizLKj^bF?iLO+JDWNAIf@VT%r-oyu{iK_ED{NBQ06cptGAl=lQP8j&YW!4QTzr(^l!uZhm-<$904ZH4w~A{eT~F&-uC0-2p?B&}xwwL*6(_6}l}BTURdG<@ez zu*07@>Es_6fKnYf?yB+c(Th#bSS8xRreFi&xG~hTd*8~YxtbmPpGG|L69NSums-U8toB?Z*jjiQe~?ef z_-?mbPR*%y^d``!gcIh92-~}E&U>3bp)4i!4_>aZ#g$Wx7mC1sfd+tkbxbB<$Tgg_{jwlwMY}*JW<+s(0 zN=?@tZcj~9Z#^gJAT`8_*2AhWOjgzm#%yapB}751v9w<**7DoQtV(`C9Bj**cLH(x zqF4jASN)RvdA2RHm}wOVVbK*Ojm5R8$U2?_H`Qbq-JGw3n$rK2JV|xGEB1*ZcbvLK z9H3Kpyxf!Q<-#bSf04nz2vUA7J;fIGzTHbTmTItc%aXr%yxyryHtftT1r@L6JVU|T z_hBnR-9(~z#c7|DPV-ly;?Q1GHCUVO+J(Wl3MrT3;oK%&MUFyK*^6G`QPqJ3D*_;L6l+jmb%OOF(QEd*W#jhP z7{0Wj2|&De+TjXfEOi~#dE;0$VGjEcBE>3~5)Qf!g1j~Lhe`fbJ~C1bfWxuZNX#Kg zek28i{qzAdN}K-|9OdN*HywRZfcL^(BZ*tW?{#*XIf%wv+b*h}pxmmj6*zFz{bl6E z*{vVA)dLLKiT|Jg&fGIcC@`vnH?;intPJY^_2~?5lY+EC`Y&1SJ*L$0`1+~MMW*2W(&8HZNjasaic z&Jo|zlu4=mh0+fWoHh?zrg3U23iFZx=RDDpy%fJ-6CI(9=?Z_ zrN8I5h9nF8s5h2XSx!OF9jh(WcCfNWiqzw)FNYx7qSB@jJD($78KWnA+%XT1j&v4y zrPlPSxWvR9aTw#=b(?lujjlvp(*>PUDP(3XTO-~pK>i)l)2^#PE(9iz*_BeA?h2e) z+L=Q$lBa({`mo~!SzjI2yP;Ln?QeB9ie`B;(e_$f?tD>i463zdXNAKu36sf?2DHP{4kkItk8#B-e-87#5{>9Du;zoRFy|r2s6c0KxV7r-0+jkzEJ_s|!q^HE81ZP;)8;p1tVf8ir{zUQj_ zx;Ph~%%2v<+k4uFU>#5*xN!b=(%t(MfCQ@jCq!#qfqj4@Qfhs9lh$~UMm(l$rt-D^ zFNEhy?9J+I_mci1^*dtLFFBa-Lk9}NeJEer9_zl!S zeUJC>0*+s7mK~Y__>w8V+drZS8Q=;A_1=1h0*kD-hlWb=@GG!g?pOMBcHtuTQvk5s zL1u8`&G*`+Q;k%nbi0rQ^s9~}Iu7)AO66#(OW*av?Q%7V9i-hgst0#`;pjEekw7@( zFuTh83^?L~g^*W@L#N4sQ8%Ey&nMDrRwZ%{NQ^}Gl1MmZ2JJwQeC}|5P7>fktLBVN zl7C}5E}7@qfU)3r6yHZLBVZIs7($@F6`R--ro>hRqb>z5#r6B^FrO^fc4O1Zf%3^Y zGy{9h3=agf`uPu-wJ_$eNW}&_-f@h-)hxkUgsq0vfKsSBYnlxv1B$j-%coSA9sOGY zeIf}{5toS-n+wJ@x}c`M;uT2?MTKLd_cscC88aLT;`I?gD#xL>Od z$|$)@v5^f+_2A` z*3y?w47zDdixIs7KIy zJEcN5mKF0GN4$8c9Bo#h=;$mchIQu~w_8`)*gfVMRlq~e+9n_XiU9_O#cztmA@S4q z;AjOmMs)NEB<^JkJyF2PDIA}nS^X-PB<77 z^czLrg9(x^u)sz>>la~BX)4ti@bw2AWurdM>nwBCNG8GQ#_)!jKf7?8oawYU0W|$r zdfTMon6YRNn8_`2#!x1jRoA^g9cqjBs6$BPEh5|8Wby@;L`o;gdS#R^pwn5U z7uRBHDczE0V^jElUyH>%bZ6rZf-rGw#o^+g@8}0X7R|N?c_teOeehH|T<^bX4bhta z@gO<3TUSqx-}6)Q;#P&BT+GJvYAxluuB*lR#ndC~3!yuaBIeE4J37V>2*kCT)OatS zx@f(vKy}@qB@HQ4orA`s;ukws!94R}d2|^e3}bSuAMt2qq2FQajHW}~1W8(3U!$Q5 zf+>^&sd6O^h)PtLa245;c+v)kD*ljFwATs}43EtB9qDVbazpS?E%Kf{9yp`QCkA2@ zJeAABe`0JMo$t=1Df~f1NFP&c6qN1jszVQ`*X=DO_q@ri^-0jKp;zSmh z;5tL?KLz5yd3B#W$dhn)`|osZ)8sieFu40)AB}5g-o@qLkPI4bhiPB5TRpCgU(%Z7 ztnOvGc75|~22tXm{XY#ICM<$RcD#_-vpi4rro0@XRd`V)pd+toTKCwX4f8d;EYpxMABYdZhu4q0$Z`!v z0w66{RodS5EX%V2sd%(i%>->irb}oj4t8Q!-z^OgRn(m41<{Y8dx#g;wzN}4bd^6! z%l{x?sEaM?nZnVCO7XX4BfzA-;-jBr`v{t)2=d9`JxL~kc=sFV)LPd;{upI7H&ll* zwd8Rebh>S#0vlLs`bXF9x>zds z!Dy}raBcT3;))2)TXY-`7Gqs6uQ9=c_Fit(4sG<)4dcQCkrSYKjWqvWzt{&RcT!62 zU2m~&FmvqR=XnSZCa1N}-b3oZ0M7DoA@q1gLm|hp{{HBy=lX5qMAS0)1b%6|bUGD0S|@f7rgVSu1wT#sV)=X^++XKox?s52`(4gc>^6 za`{7ey`r2A7KV+8>30Lt2BTr1CH%bYF_?!onvAXRJsjLP5CWdwjRpj@qn zXTyB4v$J?s@{#2yPLV5KV-vsX3mnN+%J`@WRka)5tb=wpzp-%u074XUV)*~<@A-&Y zaP;zk9fuX8ESy}K2HYG!to3s9do9I>!P{-a;Jhc)w5`HnxhjiZeTakGhr6Hjn&!tR zms!7U0N>O9!SZ~Gz=5lSeiI#S!{KBUHNw%=vHa`8)LNB-omhhP4Y_vcIOX#eh4OmH z_5f$3X8Np`ealMC%jN;m>kpCDM+f(;64{8UNnX$o@&q|qzZT{~Zl71UeI3tadOR>0 zKkE*1!682Tz2qbqrgiZ}na~fCvE~o?W~qpRjak1l(JM;*{mggwF|;9=H~skQ?PlqI zt#|#uS!i|HEt(QT@V(^;iFYSWV5G`%Q4m}d=$T28%RQuy$XYuz2beHFcMg*BW$+am zqqf@%M!Nfxr#!6NIm|!`A^n*UT)K=$;m84?K>BI!ZZ*7!Z1!CjnHP=(PDLd|9#!fy zukK~T>>{m3F{VYfontE}KW?yLV~%l;yLpz;IxPpx$M}8Q{B;0@of*ZzAMdwP%%QsS zBbC0$HYJ-%nG39a@8=6RZ6!>8zW#O@EBj_)N@pt|(3Fz2(UglyDx`l)?J8`YDoCk^ z)3^xchBN%ia)kIi)JfDX9gTSnLxL+<+K!6jrg}iFlJAV&Qt52#16<^O31ln(eYz-7 z%;RHw6=iB|zw*pEoF)6fd)}u9vGahleV2UYM2NI_(l2WtiHnT&bo)Fh)#yp?e2e>o zOZV|eHJOy^l7({;ntGPXfAwUE*gdYrjaf**wCPcwQ8Pt=2zDORn?J^efa1&z% z)5DFmz&V$&z@uM#xPJDYoR|gr z#kcB0!peP_P@H`xdR@Bvu6n82A~8IIEO8V2>^W}~W)Oc}#^xiQM}x}Jq5btYF? zWnayur)Tbw&67I_862Fu-tmP+mC^a#crO=*!^*rorHvLS(O;=%Hrqo`m$|C;!AC9HPXSPMMKv z9v6z$*OQ=v>g^$3IbQpt@%(EJ^6Hy(+xTR}o~VvtQJ&I$1jjh(g&S15f(j0NQ+|xk z^@QVXtp+Xy)hGp1bAn>dz)&2dg}+ClKl+mk(i3ekC6L_DKX2Y(2Nu|cglqp)m*9)c zoQ{xnFhnptgr`Q=@BF{>OjoGdj~A+vZS$)DM*U_$AoyT!97MBuWE>&El8Zm9z?mR+ z-#%c0j!ZTCG7S~jcDq2enB6;#ldU{p;J-%R7{a@`bCYHhZf%xJA{y7!Dt^j33eS$e zzN3|iulpgh)GgskJg=Hi!GGkFJ4oOC4dClvd11U6zp?9W8Ovb+s zJ%-Ukc9EHlTPNIE&lw2lhgvCV8^syEjv{8PiyP|kv_~VjNnFkp;tE>i1*3+da%rhB zEliH*p?LT@>SJ4N(!yc){B4(n$Ki@}MZEjF^)J6t(x9GkBn6Q-UH*M%I~O$`*|)cz zSgMkkQnF!isOqu>aCmvO{#ws;Wf>KD2i2$56+hx!-W!}2JV5Z}dgt@IOT^SoLn&67A_sq99T>l_UtG2VcgylAV2Q8arO6@@(z>&{$bDJzOcD z=d#Zs`1+BrF(wiXT~E9-5ut!7nLAI|A`Tif5;7RCZXbOb5lM1UJijUJFl@?{9v7P~ zGeR0l&!Mp+c$w<;M!`VO$}BBd8_KP3$M{m(nxBz59K9$MyU6brT^~mJ3H9nrVd%zO zMS0m&cp~b%>XzZ)3&}lQL?z6I-O)LA?9ozF9T`Z6#a1pA8j_4Q@{vs4?|VCo_x=PjJQ+C`FX3ESU#_qm7h^GOMog! z?#htV(bVJZP(aYVH+Bah$gvlhJU>ZfdHpkc7bF>K{=EBc!L9o;vUN~0vE>5C=Skh| zbGI*1DIBSpNGBt*f@p-oIh0%a^aCq#XQ~OS1pl2c23@*A zO3-|7sBdAD;s=UgzWk-HzUz4GR}@LfH4}MNFv)L+#+MIT)Vxo7K@<3LgKQ?1f9f4)#d4(dShVVZTor*y)=tn zVN3vtwakEF>5V5^HizQ_eG{@zls?foT+>?I;t`sV#u z10g&@O4y_*_xvZjybYHkoAX2Xkh;v>a3l>)+Mmcy`gNH6gCK8Ni#i2I8VPhE8z(zR z?!u;TwD0cs^4HUm#u`EMw=hF0qwvhdCoqy19bl4xX+&thO)Z7&)p0XLM|US^XFuNU zDEb_;=2Fwt`4*gr5o!k)zz2Xb-&hCzB)Z7n#rb*A9`__f;7=q&OnrZq-Snz&C5AF( z72w(S)N7F^Wr!ZGAW!%hP6`98HN8#aBYm)#C(KOOS#yVIv`8k!GE+CQK>0X+7UD=4 zBco?|#>;(eDGaKCF9FGys!t$UDwnv`M_M~wgp$;%3i7(o<6lQ#Ppb7M90nG?EiaMa z7$0)2Wk=-byHKk#F(ktCyYr~6jj*Ggh`{Iaz}_i-c_0cb=EQI~#PYhq9_v`27YNe) zMdbxz^Qj6(&aHXQ`(iJ%0cN+OvwP#|gor(8GQDVUqgFA6v~nztCct}etB-*%2ZMNL zYtb)~^HrhX_F|%KJMtKGYjK&!4|#^wu@=wo+tEo#M$7+S!`z6)!w6xI@^#(PziDP- zA?2hrq=ZO@E@&WKQ`edWM_N7cdD&j)0c2WLen8^}vyZllg1FwzWfOzZZ$!QPhkAjFcZ8(URfs*|ei*mizkgX4C!T#d z<$A}(&6q!pF-x=*6~dK@Ppm6+_StoN&0>SrxwI9+puzY`WvaMXOkM`p#&X>`ns@#E zha{P$Rk2_RB-3ed4uyp=sD!JiqsqxiHznM8hDirGm4J@e1$w zo8R|~eLPazMo%7T`o3wu>a4AOL03*Tv#A?t;4VMgoNCQ!*%(*&X{Cdcv>fheRCS58 zk8VUDJUQx^wX`mxnnef?ExzOtHf}%K)LR&j6QPH!<=H_@b6h2*D5V#Us+P7%MR*qY zZTgf}BJb7n-#c=+T%KgNny~J}1Uawlvzqe_mI?U%nyfW%oU0%ol*@qiZ!F$>k{m>5 z6yMYl;4X*wde`+H4cAI#ELSLT%2ozpz`1@;8~9SW3N zY686hfVgY-djVD`oMW0w_3!5Ht{N^W$>3&^krhL;% zVa#Ae7v<9Q1 zqRb%NEcmEfd<`c-Qy83osm7Dg0nHiIfy_N9M}Q1=ga568$dyJQli(fSa< z2m~keUyj0;xx6COi7rR*pS`i&{kd&An$7ew|lSFv2AV0|N+T z5T}miPGat!Us6KzsB1YnjMx5uY$w?ubp-}?+J|)qJjM9HF7EDFSEu>G7j$YF*d+e{ z=m1f4REL{eFCSQ{UOExju2*n?6?zyXt}l#Hxu6jYL<`delyP%qH8t#)1cU)cuo6RX zKfHuG0mPC6aQ@k~dQq}KdhY*Xmj=~Wy0jbD{ot<*8=8{QHKSHsd@MyX+;u4aDNpK1|df>#ZXJuMREM$bG z_ldn%SI|*`lPEabUrlC4TORG*yt)Yi;2ci#e$ZoF8JB5&g-`pSYffNJGTyuDD~r+R zN~)QP6mYiz7U?l2T>%66&yP0O;(}KbegM^2#JT-#RNTC!IOm6eI_Z!mrNO>8KBBBs z3k7QxC{otG;0X9T?tFgb9O$Qx?2!kuNZ&W6k%z} zYT&MkvC=Au{Uk;D*#B!Dah|6sfr90|s#A<qj$ALuFf7;g!9Jl|5rf(44*=mMzh+(x^d|*+665Tv>R~Prug_W^SofKaS$0 zDR~?9;>b$PPCp@3w^(IOC5o5%gv~ULs~`b?TtJJ5#aLd?=(`WMq|MRcYWSbq)kNXz zgCHoj*p9a2n+|xQDH#?sd5P$II+(IUz0^4j9PF6_vO&R`_%ZYgV?K#LYv$Iuv0uLQ zWrfr$*Bbrkr8*lcwcV?3AUNXg*yDD8FA2u_7Hr8pYqsA9=WML3^m3W~|?hFOp<4a%2{1p%qco@gbj9N5F7|MA^&wNL^(cP-$3`5n@J|g$W^pHL#}< z12@KxvA8bh0x52rVwi`)cyIf!iT4RcLRLheHH*TDT%xX_9_# z&vX5HxE+n3cP39UuGHt3mqdG4VxR>vb<3k) z%*tNL!S#69h78YS_|S*l-WEZ0cKx%;_JR6Iq}a|+zpWHad~<;a*P!!i2a^@2D%j-t zlEmUAxdv$@Dn24>+~#ePHoxQpFtf>1oM0s}<@EXvu(AZBsSp5PnTijm7Y> zN;OOgwY5pOqpNenw{vrG`TXfdY}YCRr^6&D2xxatn!&cpXklaLglJwrMP*{^;u<85 zTtq&dU-yxK&Woy%Mayqfa>ZkHMJQB!%gxLbtGICzoQ1&#RIA1&=lTDRB+ZRkw&jDX zPm&nfKt0Q;1vGvb?P3C-L4ft)fy3#92q>d=UXQB0(mwl-qq7Q#s_mjMLw9#KgA83m zmmrB|NH&-T+EzvIJ4ii*LoI8&)%|<`*35}AuZ5x^`aJ7Ey-D|19-GHvbt;AMoZD@g9VV-|y54Xs{qD8h?oJ@jwqBznss>&!Xy8 zcIxdtjcKhuy}gYJzSsIkwbJ=UL8la~p1|~OK8L&>@Nj(%isX@;jAIH`Ry_RL3f-V6 z3(n2(cl5QtX0)l{FL_tM0(+Ai+8&PKT3Tn2J(D%7E$j+ahtGj zKyZI^vl~bO>;$OBk`Fehk$=Ov-%Di+>~N$cV$~Pqoo8zvwlwvG&mFuk_~$^3V+%Vg z?mE2)sTkxaFLxG!p3@p2L#@<~1=C+)3_dv$U(&vpvJ78HsGl~6sv=vge>(f=A8yLwL4}VB#Q$z`d>0N$oq!q2c+k&3{R9ZOn(f(+& z^Q`h`2A|;*f&McoXTy{2szyl+ADNx&AXLbJNp_z+N2Y?35{rtT&TxC7XwiJ87(~`5 zgetTt|7wV@O>2y5MBZ)7m*)oudEDU0c!|(>awGqjckjWmy>>RPn__*3P?oTe%uU3_ zH$fV6gu7K;AkvJ)Sx(}|mz|%6;<|*n9#xd1g{0)w@WAl|=^b#Gy%DMwY`; z@YkZef?J%oZ_c~dXw%uUB16SCmJyNRgc(66*+%LfiJk&^?+>dfC?>4g8dKHZmIYl^ zCvLu34a~q!T|0ko388 z>~Y0CSUEQZW_1UM<{DBPT`!{3)$Yk~n7DPJH+zE&s$;$OufKCW8t&f*F?^qskEutk zA5J+tnZ}V-yi-(+%5B~sbdn#FA&uAIQT0QQeIB!)_rp^XpB}~Qt7P)&Zr|J;lyQB3 zWIHwB>X9qVI4rA4qmg1gNH~ z8IdZsFlhilVord$o2mH~c<_CvRG-Ey5l+icaYm{V@3<0pt!Hfk<-{beduK;`8w!^~ zJ=Nik3#(l0@xl*r{6OV3W}Mq4=DKB^$&}hvA*2RjsQn>W?zlD6Su{O3=k`MEb1M7J z9lmic|BYuZAu<@3Jtk=GsrEa66`Y{w?XB<@z``WC*5_G@IkzpH&piBj2 zUhfNPLEX}ukV$}w#b;OHyP#u9_mOCD2{_L7cEMp0wmP=B;J#o}OmO^eRej zn0@UF-Bse(xFFg(hsjb!?r-{cCe4kYZNPO{j!>#K!oMBs7_zl{*3Pc)o>G-K6ro7| zUip3&wF;Ib+CRzY85mCgo<(^XpKK({K&W?a$p?FhDyFeCJo`boXw(&$KRv!$@N1^` zRd7LuQI7!0YKLQth3>D!OdfaG`fuyR&~$sV0$WT>u%4Gj{bM|qByTLwS$K?I>KJv^ z>;rHJ4psl1njNXZ`pCOYO57MYDpwyK=$K^96kXkm`-1}B0N~lsIW0g~1_s$j_fnfx zQ)GB0`hV%ayQ2}wqwf5-%uvgNQ`zYIc&7Mzi99)(K-;8SH9%%WH)EZ>B%>I$q*~0W zkQ9)mGi|#sXOTkh#eWNj=x9Vn(PrD?g{aw zv2oC=x6LeD|jFkpc(3yivORk;nQh}S*)~ZxcJ|j5XyAsgE zC?i68YW09h7)o$>+Rj6(oXR<(FVwov%56VBDumoo5AzUz=MF#6(Pyg^Hj-p;&VahR z@Ba?VT0x?EO2&p&Jd;?djpEh89^kMSg8@%D?ajSXQV30|9w zwkhymf6`f5EEwn@c@Y`ePbqC~e#0HCg)7|5Puvk`eRRw(M>_h7Yq(GhmMXdxWD#B# zB0kR+g|TW*k=Y9=x2bHn*^t*Win3Tmy*+YQjWOs1uUAJ&@ag?O694*(w$y56;@JJ? zX>0G0d%gXzo^)|vYuw=Y^M1c~Eh;z;{K&)BTyp`#c$Gw)m^u?3d`#gTmPE!e$;+Wb z4NuSrPVz@?c;bi^4Zsu<_;tTx5a>BD?Ks>Ve(DibJ^$@_D{Gug#+?1Qg|i>!%DTfc z#C2KIQLTC|J98=>;&RL#8Cdt16_{RR|IBA4{}B%b~wK9r`|aL=Y+=C)g&(P_;&gkz(E@AaOqzd}DuK^Ka{4d@!gt209R(tMO_k z*@$GFa{8JkFB3WginCC^6ppDIUe$<@5h~i?4Q6E5^V$HSeC9-j*Ktjmu`R@v zznMl~{ZYhsA%(mgu4QZ%S09PfLGmvE8a%b4g{~_5x3K|AV0vLyVb2!_3cm`+HbXlLD6_a2Ok5UQI}79s;5d4XrbKgL9xr68ezm_y14-9F!ixI}bgpIBdEg-@ z2&fzhySnm0BsOQ;EvV1tQG0cCyS6Fl8)nauL9iD`Gmr2MHcoGHIK#UUdiq1CmQS}< zB^eZFcjrv^0vE06c4q>51^n{=v^)$Y0M?VX)P3`&$vAwVl8 z5ei|pZt36j9%xPQ^@TI>KEeMOaKy#F5T%-0KXyL2+IYaW_&`6n5v%aehY{FJ)a~1a zMLETdC=a|PUeiS{0_rxv(0H`{u3dCtL$w*0?q#7mLUi@^qJYjkK3s6E^0=)>Mf13W z?$1zKn+989sDCzMMh?SR>l_wnw)}u>hf*)pJ8^{+;@>ML3&v|nX<3@cx?_I)-iKce zt#7@HrW3wxRCWP*uPN_Va{vk3%UDkB>ZubJJ}0(6?lx`LrK>H54J&z!9ai&JoX1XG z3!28_E8qD5u-t(+Tj}Y`hA21YN6Zsd^dn?Q%nKUU6J$?@;%V=e=})kM1??Fo1l$f5 z`T~0JlNWR|^5VZF9IpiuYX!M zFIxM|vwVmBHTAZUgjc%tsq{-kS6UXOmvXi?b&%*drWQffXbFTekVvP5!bOx|2r2&E zdTn|zcz#{x!v&Y_#l#YI_H?q$gANClbFS5w#f^)TnCJ}@O^Mtn3S;yVVfhAn;zQ>p zN_Tr3_yu`0DK8U^bI0ffx7mD@so@o;ufpSNdO5BPea_V4fZQ~vt==nz+vJPZdFohPsLhuIu*Roq9ukPznhvzu z0V?LNIB6ph9j;j+qWekdu~*h7N8b?V0Yl~JsTnXFmI^F<%%EZl4`&+xUF1sSvyFex z8t%^3eV@Xb!jM?m=qE*9#yYaRjX`^XL@=4RU49Mk(zDxgZzNr#{5jdVq63al*cDPQwR+ABl68B47&zldeXsp5Y=fy{Q zf-TH1AIqT6V}5Y{GHcS@to}yfs#C#rHOEm%EAu(3_9(dDXwdZe7$WdRo%{2cGfc!Q zg+M(t=xC7w;w8(FeklEp>h}lU1RogYwb|;njw;d9;ZQEZ_Fzez59!X{@fIid@7Z_##2TrS`rQ+4G0^W9bR z95sZv!O?~&cUyf*py#)t7ZB`lN)F7=;fW+QoqX*BQ^Iz}hLe<82WJr=f2>^Vn_N89 z9~w^cIqQ0#RmHMF$=DD;9A>HUNy1pwjLCQW1?*HZi(#)Sxqf|Y{k^(-3i+>!5!&67 z&+7{>IO1UrsCygW=O>p|K6Hj_lJ3V7Pdq5a^1iL;S(=f9b*jWj6eL^rFxFQ|v@KH*D* z)8d0!a&r@HmYOyh0}y@ydFTFO+6`!o0EvKX4GVfaJSLLw>byUf>6J)k2)c*3EUw=N z4V<4-NaoXL^NBXVX|Lv8e3V^O$-f*MnZ*?Z8DpLRoZ_x~Pir+8Bink3Y#W&znQm=b z8H_+ONPRkD|1xemwb~+U|LyHvcAAqA&$0cF^8`uzHDW?-12(X60t;>sI}SwxFXdPq zwOHWFUiOZESPMB`dBHa>2&mb)P2GI>pz^?B0exCBPV`If;+;g&AWK}a?3`CS#a8UO z%KGU+#~@%Wh(ui}SSX8z^$Qe7yv!Y94L}#|4^AF`<0MA={iYhrR{!KHFII!gV$osW z*tlKxpM1aO^}A-bZ1!P-Ok24CYxfZ$tqhvWi%E9=r#W?x74}YLpz2hAxk6Vxfm76o|_E%ZpPG- zrLw5NH%}dUPNTBoQwA;4l@$~oS-+dA3_jQUe+wAUXPH<`F#~!+ zWpPIgNHvQGtn!Nil@@`lR&-3$HCN-LNJEX*OFUEtPCM}8cJ!m|$eQk+XqE8KzOHSx z@>B%YWX?UYCN9#YJT?QE1r?F{C#}To11r;#2ov-lT#3`hEivj(OL^5*SSk4gNbN~b zJ_}bC7I;ukdeh}LDTr!byiyFAm9@f6d)f;f7D${@#v>V->Wj-$imHTyZC`!<6oxff z1{UT*FP9dB6(kOI7RxZp&am4k9yZ!9&8LuA3ttacCb@Qq1d%jJdUsNpQK9kUCfRfO zLU~lRUxU5#Uw<##(u-WVAji#N>wWa85cL0Khj$7n~nAC~zy{2jRv zM=?c0SrH3uj@+K4G-TFBv_v*i6qE3Ei0+Ye+2>Ly>lgK1)bi93$O zdF9l#<{ZIZx%nU0srKydFLFH|cHT8#YXKHx-_0eN`J!e1e;w*qBRT2!B(~(L5aZmU zA?#8S#S=*UHO`k0Yv&q{vMgO{^_vaqMty0qnj$d#DnN7na-bR;EpGf48m?@~dT9`p2-se0 zgh=MMZ*yE0--4qJx-Pv3?rz9pZRLcVcgz(C zv}qeO2wALG-?>H4+EPzEg|9yxf^wN!ef>-GC%Tzp4R(Vs^$h1{*hrD9w-?{cU-@@* zQ-*t4Ob91XRX5WhK|VG%Sg7GX@wjxzqgh4aId-Fr!iPY3-FV?I##)xEef{2q;^50E z&{l*9acR#A3tzm6|K@i3_iq?tXLS}W_;I@PzcONi<%zs(+N!-Yl}6(-EiC%i?Qq5Lke#$GD4w~>kG7jQcTs2 zn`qvlNd6b(c8Y-yk9ZHV8i&m_FHRqCb!LOg9&cs7G&*?RQ@tUu`0&(chdo=SorV-8u5dH=@ z$k<6=_yO9|iwQH3=C9sqBcIz(lodqiyHp zIXB>VdX{NB@7AoGjyt%45_I0SvVQFzQAe&Zy>@wtx6&CrSknnWN{(L%s!0sCwX;m0 z+kP*UC_DA_mwid1-WyVFoys?g)1cw*>)YoR^oT`3Kmgw4Us7}xjf?itRny~Wy;4~w z(Xk<;|1W#FaKUgPZMu^Z*lo{w$a?>XSz?(+dTAHFfk*}jiw9TU$C1DZblyz;DSyL% zE;Qt-e1cba5Fe`Cifv%TCHDW8X)gn`A;AO72~CCv6-D zA>p3X{;4S9Hl~ie+mTW_aRfvH_kl=abuoG|W2Eop zkfOzqQK`-?zo(%|vziwgq$FHD(~i+WeHZInGjJZ(1>xJX@vB7DwsNB|f^jN7BRYA3 znoSY|MeI4Kv5>p$ZQMU|sU@JFR;Q7Tam}VSAGS^?jV>);-Ftt`l+}#CHztH=sC0$TwtI^p`e|#5GQEq5euaPAug5Z} zPf!VT9QO7oplCRaS4c9B^EaK2?D7LYs?|=D%~DZCgRRvQs@+huWB7GTE142!*ey&U zHwgZM^)Jh(d3LPV%)OuatF#~gv?d;K)zo|w9DU`sLiOS??h0f5a+BEx;(0t97y>Nc z_ov6F1@YtY5`tCz-f6+nNY)lO)l5lZPq&1Z6tv}0ch3q!?rCH4N`zELRvF6_8LV)E z=pn}@;_A$D8{Di3!o^8Xg*H$9m~w4-A9v-%Wh}%6=^^GTYYdN%3@69`9y$jPy%BT6 z)O%Y>xtA-p3RVw zcs?a_A!|^_zBqgk$SXp2ITOcVp968sEc(RdypK0rALW@OAO@Wr*ONG=EhCw&x2>@m z9oUFa2KA_o1G`k6m*(Dn}Z~Gd4Cqp-p2YJ0AT&rctDC<+WQX)ZX25TyMG_qrP2Y4=Q@Y3n94Hl zdBMVl1h!M7hu&8Y!b*UHg&dlDSni}vu6}nAa4Rd(yz1|g!us9()fZ6MRzZuLFrLb) z0;m+3UXZ>!1J1~L=+UYCAD zhP?R5qL1AWMm93`bF!-Fm@+JtHTIx}8uS3rg0Gh}TCTKsLi^k{*2^3%#Bqs7l=kYG zjbmK(e(iEy%UAOnFd%Cq1wCw1AaxCax%NA%NDvXJDO+et)uw;V^1d zK7>uACmBeja6T4>|bIdeGnC_?~1MRqTJAmRL!y>OcxSl%Z81R#Nrz|hd8gvj`5qWuJOoCCens9k#|H=l?$;+ zyLGI%>sdPnr6r!-pcwB(ibUaX;zYE zFmkWSEXG{N*AeIu{n1r`22%uPLWu}9<`a2Y#+M}xR`w{^Gn#s=1b#b6uaZw1ug_Z) zRLEtnnzh?&keO4G1@Te$BHYigujaDu28?}5Yc&tEp7OF@f!SbpqF{kjMRXVD=9~IKyqY_M2m#9NKloH`tTecE6ql~HjYzpOl)USQkchF8jY(ERDcZO!; z6gHeLVs3Nj)9U3g4U*@e8)BRffOp^4$3D1Xpe1@xpWgQhRyJNg9-{3Jm-c~wDJS^0 zT$uepJ71z(=OR-bIg{^99`>|QR~y-z6=tZaUWSO|ptgf6o;+b&E$rE16KK;@G!C2! z5e&MWUHY&*CTK&IGh()$Gl+<2Lf1E6^KY}FMYj>@uKxi)NN$**R?1L}^(b(6s>$9a zvzCcv>5iRsT0{W{-2um^`aiRkqH^HRel2;oZTbtMYiYfxc{G{F2kopH;-s%np)|%onqVm%sPvj9;D5;PNv6$X9gH~aX_^y_yB9WuY0OL zrQ)O!^!%9m9Zi!-zRxX9YwH&KM|oy>IAmd68t*PPMH1dBRoR1G{W-i53*7!jWdS^~ zQJmbrQPnPWKX4k7!`){p{W(ySS7ps+N|{gKzUs)?Xcy1C6+*eqUV35`KX914w=`F6 z_Hw#*`G_3pt*y$batV|vq2FI~bUOs{y1+FG?8K&EW%OEgP-ENdZXD0*t|AN$SISD% zQ^<_bz`3B}1ab7l({x&@_ejXX+foU$s0Ex})v>h{9`i~#y_j123|zS7q}`|rXF(zJ ze-!OwDHD0B9EX(bH@>F6pFF+(vrm}$1B0Lh5BnoI$>}z0Hc3U?Q1(a{i`?KV`xw%Y z+Ot6P)7ZbiM`X2mRnpBQ2)UhMpNwMa^oMsY$U>r1LtDUp$vWmoW%;=9+~_lp!bT+| zuSpwGti5&uBZU;uvaqzq008?Z)~SdV(p(8TTisBYqYmuwau*N z=`pH|h>)`HW>F8G5dsfk_(v0DXWX*MZCPVypX4xSd@X!$;l| z67uZJx=Q1(4D467JW9h(SsnNE5Y)kn?w^mYzB*74B}=G2^X(wJChTBYyv}_ex8i;* zPsI8Rioc5gyrYC>XP#PlkwnN62Sih6-cKK`!%4-4j>&y4+mNtPGckE z!ow%K!<XsaFpJzyAM?D;%{NotK`knA8iBuv>A!RLs+m;)N4jT7~P=J+) zlfrmSoqcD{Hq$;-US{eO&s*rrW2xa!5gNoxJk4!MWR@A1c3(m@V7Eabra7`AYPG{b zod8?fycGqrjkpBSHVdAiS1(H|fD4Iwe;Ci}%P&SXT}EH9km#Wd_gg#Vna0KI`r2jF zv4OIdw7UzN1gKC=ZhAIW@Z zqp#mX(qIL~zv_%%$n>n2CO53sJPV;Qv1z0~S8k0G=&IRD!zy!(8>jA}$&M|GBAov{P{(2)B zW<`;PV_U#7@(PJHu-$V=ckK4Z^wTYq8LU1Bo67NR!G);fvP4`R2@E`9Zx^+XaT>&+ zSHa-mBw;c`SL)%2AXvyT?A4d<(^JTJG69?(ev(y2tG*s}$ztFLNM6~k*FS7aEh(d~iAok4p@DT?MN;dL# zHmTzKIa#S<^-&2(x6g8YNMuW$L{8xLcE%eK*Qxp&rH~Xx$a z*iLp=`s+DI=cE2?{TK}*I{vMX&OB$^UtfKpLdNivYx@Px#>nLZ|4zlaO?#Oqa?J(? zqefqV1X-|B6|U}xHgQt})`3}}=A4q6fQOGVYRJb`2m{p(5}9Osx_eHGoeiX?QA~EnKpyW0wE{g16;158{#8jjvzGQ{`u16~%Jb2P;#T-kAJ2^zd zl56JCJt2Tf?p39#CvVf(fwGB7zOlXPhcN685V$*Ck-={Ku)@(xIsOruw+hFqj(n|R z`ycA&@s(0w=7}o;i-q@UrIN{?=bQ#>0kIxHygG1~?i3mS=keDcbb{Q@Mt1o2VCtPY zQscnjcx_CQS0T~{+;{&b!DGtH!?pkFc;&S70l3WH|GTg^MTDa+aZo);5yo&moh);}QH2i0w3qIZPx3Xab_Sqx(y z6#%YuM0V}idgvmkG{bJ|h1@+5(L>s#77u|RFZv21^LR}%tcuOVvEbrV3tvFv5sWSF zU3*G_JLoEp32ELZ17F7pcjH^*fPh}XYTzoLoms`w@Vt}&`9?!Zq^2Nf%KGJ8yW+;5 zL?@4wTiy@H1?Q^$daGb~;cwTvYA$0HR4}E01WNW?D&qk6` zQbg_0$cIPJT5xiE8`kfKh{(Kzoc;=_Hkx69TJ6U@J6 z(-PPwD=e!;e3-0qG*;(aoizjH+qKmr%XLX8|?qJSS8#&m=5S7aS1UEmQMVX9u6?;%vkJgTu>(JY{-<^=4$r(KgwxP3r^5#XCnZPNe$VUx zyl0$<5UnfS4{x=6tB?7|GRa~ei?Jumx*hr9H|cpJ*AG1@{)m_eqQrQ%di$;FjZ`{4 z5kvuL*b@Pto-yo@Gt7iRr4V9c`82zsGg`k)k1vFOr^KRd3;6L_qC&-I9gF{62veT$%bS_#!=WE%Y{a&S6F;VONtnN2y}o%acyF%#!5uC7a;%YxnAg@ z820;1Y&y!!g^b6x3d;3l8)|zFUSdwykUGn&eQaG|9#_qNPAl*O!*tAvkx`@a8a_0@ z)VI3(L_m||azZfr<5KIZQI)A2GA*moEtv!+wKYYqfu49v85QF4-Lmf;;g)z0yy3V4 zPq3Exb@TI0|v^OqypjiVzxYGgmKx)%d?>iG`s5q*`P(>rmd4zDRfg5Y?zH z|9(DP2UAr6awdrH%5;|W)2h1HiuqYZ^R}B}X+qk~0^$oXBIe)469o#@LoAr5uWj^U z$n#j!3x&U(0natsg|CtqXF!3Lg$JXJ_)Yhbx3==v}>zkt28r!Ys@!3Y=PQp@=$73U{cwnmLoWp5s zbj(}_Re6AL3ao*(D*(!KznS&If##(!0I20x+#|&;OlGrxVzb%2Or-C;+gN+Nl-#iI zSa#LUom|5G20gu7`3I2&dw=K|u2!;EMlk1|__R=@sb5fKBN!U>^_evUFX$fZKiA9Z zY%vqz%scxi>w0g1iaHL}I@Ug0bGo?VKZW+FWDAzf6&s44ZACC_+zrgK9evuyPa=&r z(w+i~Z&rF<;`p{kkScb+@udWPQjjc{paU`8SIO1 z#OWsq%>LO#f=;hKdk)emSg&1M#|sp0S2Syx!cWTCun}DDrZ1{rPPoo!9n+SsE>?{l zWJ{?>>cOS3`~ol*ry#|MpjFCGdN!XO=777EYVhvvfgB9J0e-;3-s{>4ym7#A4bmz> z@qcH5*#~UAk5@X+^E1g>n>s5%>OCrY`gDw5uu5<(D1G8`^WoiH2-*G@$8r>GdD%?8 zDbm0Y{;15CAm$Een*k2i6Nyq|+c@o4^KL%iG}>&+lDgAQ5LMJk(VMl1rxDO!wbnST z4UC#2s_66apS4!5cJ2!9(v|C5{&~1H&;A!UB9LIk+9u9tNpDMj(I z;e^AYLC9@fo>3#2V$$}uJu1@N2;O-ga?7#Af3eH9Uuy)x*EG%|G)i-Akyo#WpPJK^ zaoWbh#*pxEb# z*Q=I6w{8E9l5Ne`d?nXzcCiSeS-daNZ3~!)`1)02aWSZb>h7kL(4CkiZ9cnu#N(P& z89l`Pd{(3LvS-%oCdC=k$on^o3JK2)$~)xBI(HnZWCUgH4-ZwdA6~TEy(r8liBUQX)A#tr73ANy z=|0%a+>$BEY1vJFLNBWoC&x5jS;jlSy5C`}6K}E$$CZT0<>N4CtRZt`lcAgJYcWnh zRzu$Nt5ciGe3yay@E$=|8-=apC?Eoi)o5~2?-_Sxv`^yZARdAE&kPl+XaN9q5hx z(bI6=kJ5&xV}&~Wy2CfT!V1Hozf7T*aT2vum8<*?D_hGdVA1FgXEe#%Ng$=yxYZDU ze?s$5X#MsvD)^T7Uku2DE(c*$k-5&%+^?rVN98*G+M7#d)YP4s|H^ZAWPh|}x7>OU z2ye2UHUgs^^P9Q+$R-)+HTn@rs&#P1mSFA}cJmXMVez^X^peS=m0~*dN;i;=4aq>x zjQ`K?n`=d<>cS)98!aSB?;zdebok6d zyFucDL6l-gfH_G{x_*QfwlT?{=viQYzajHze;*xuy#nUlOuwFHx0Ms`piT~5bOvY^ zk+-k;cSdTezA~FA?j2hu&+-hb?eFP{36T&SgtS8AY{=F6UwItGvM&5ozOQ4GYsJvG zHe5N=_)paksQNT2$svtGVcC+Zmc`4r-!sJO5>Y8zQ%Z@4OLi_@sv=+HycENoNh{}E zJj%f(uoIa1eAG=gg-7xV4Qar!=h8pZshl5|1%HqP|Bfy*$9$-sr&fl3;*ynmN@(L- z-4B7QF9$@Lt*2=rHDZ&eCCKn4Nx>taghzjqh=- z%z=*K&o?nH#^k74g$I%fs$tfc(frigBNE+FD&P#7RPF-&2s(3QQd{=;F`QK)tJ-9= z`D(=Eo#u;(T>GyGQeqOl0GxyXw!i4m{Tq*SPy(Qnx<-h z@f!i_ZRE+~3L6>Ao#r1S zM=4pY@yttGW^Z7#R&<#ZVwY3BAwiT#8ZxVh;=rBDOAWq0^5(6uCda-;%xn()DbBK5 zm|&)#l0Lb%3BrQH&qXOhMpDYsXMTOZ`31k0Am|ERXoARhAv&MQ;8Q9s9NSXKt*yDs znv=wMaSQ*Gpt?89L_2R?_jhs+3J4FAw|JXPj_!ESB(Ybjh@BHd6D>mh*|ZQP$ITiS zn1x!$l&ktBb-2tkW~%dqy6u`3=Y(69siFOM3l5eAcDTJUphr(g1L&u-`sfekL@v|C zj;6RIY>D@Z0)0l|pO~HUH>olzY(OOjpuNEaApuC{zC1JYxWMn=H_;wDlfnnNkzK#aK#H{xQ(DCtoNp#Bxd$A(>c{wAJRTiC8X1rk z(9@sXpM*?%M{5`}s*xC}ap#b{Um%QbI|^4|;CAG-e0_?`<-xU)NAaxYH>TBAPUVXX z8hEM;BWkH*+^B2#sCRh1<=Aa|EuNGHOR&=GdJB_N4-y^KST6%qUfibIEd^`3;ycBZ zDvd{uzSkWRp9#5pq=kl5k-8rmBND&4rN0uSMl|McxSLl7h9XhovDhu!8Z)-tmB!Ut zth)}z#!7tg%@seE%|q<5muLzISU_y#-a1IUZK(QaitZAzKCU!~llmML!sU~x>-mKl zhk&X*Uj4PRu%3lNX5wML(Q9~;T=&aSky={Am@d`8w~0jL7U%7$-wpY&I*Lg0CU{iC z2#k!}JJ>Rv^f+HegkN2K*zzkdvPrne7RrV27&uMl^He_HxFNAqldJ1zfU}}0+EZ2u z3rrGn^%r9^5k}xZm6=n%5%^6_jj%U3Jf9M87co>Pv85l8MC3fX7$xK7T{!`dqRsho zAp`ma9Y@|`6B<&}+7jq(S(Q{Ebp>GJhUU>vDX?Ke8;zW7$iSwRlZarDg zeM`<}Je%)HEFfvFPpd32tIQGa-)UPURm4BzVjzq$ZsjCcpLF*?@0V-!_G)`3pli+j zss5ZUHKF?mn=EGNRGn>yTF?L@!~mq&MWDmj;7{4v(Pm%&0&|AqY3e*D z@#ezH>mScUD{TsF&B9H9rLoK8+xs-+Bkwk*n9t9qUrmEv7R3S9?sAvHKl2UBF-v=3 zllgZL<-dx8>Q@9LW;7*rzg$yG+dHqKrGTdpt|9P2zvx)}wF|*93OU5uF}H}pU!7$7 zBJNWUj58E0hZK#cBA*6+toRQA2?n_elI|HmGm9QcP@3~HOXrF%n2vy0gGtPU-QhF8 zhPun={oA9HIx@A^-p2?@4tHsK0&wK@edDLdKKJMTF==BrqV*FPyG4B&uFu=JGjx3Y zZjxXcKq@?PdQD4(^h*34z`VN7feO8qLdE@IsU8+JNBzCYt zTsV)tYM@)zOv~6!R&oT?a&?^PBhXQrW0WKIvWmeQ{#JHf>Ps>mHMBAhY%6S9*6qcp}7UXkXS-iBC3P|;^emJ4b&%84pTll*Vwwk4$ z^*;o27Y{Y#gw033@}$bTE1O%>a(35dGARMw!DS9XyF0Id%Sz|pEmsDYv~^56^iG~W z#k3XzImb6Lg-^Jg_o$PTlZU2oT|GdOKAC_Z#Nne)8#kaO-`z<>c`#a1NDMy@TWqb4 z^rR2I&g%quClb;S*vN6clB#k`7P)QGOFe5+th`jjvg4LGtUke9;Ok$cWy{&fsgj@E z%4fI}v=hs&P0Ib79BR6t{_wSV0D}d-bl3gS3y{4$`YR#%j^157zjk@X*^82T6a(=* zp95*DHzqGpxM$&eimFXK1r`U>2a@q+#{qcirxz51PstFfEjOq(#yryLrhokKp_XRs z4d(Hnb$|lnxOgnPU}9;<#+tyx`gv_s0xx5)p3kvEQ9Fm*Oj3j`la$)_RN z)cuS#NrXQc65V(-E*F~gsVxhUtP3XkhPHCSwhc7$jiRNgHe4~OL z8U1^%sVUS9l4}+DIJ}jmX+zp2!U?E_jP<|hC*t(Z*j1?-l<^;5I&k|(OpEnJGd{M! zFf((|qCIJ0KXpTgsn!%0F(@G~rIlR6-;285|9&ubob(HX^$1jedoHx@(# z&($Vk$$M|~duTJg6fOSDAHFO#=p6-}x)vwok;vK{!NQ7snNOA9qFEhm*shh4Pwz zd(ZAC=W1r91M0|=>TX{O=ndTm6odCRiXO^*PrZ%K?~$h<$jQ9*bFhn+-)}21$l?_r zAepg#G9h2WXa_jnz7BCH*z_X|=7fw}m<6{>qIB%MUE8>QYftC!FrUm~F>YV~WCYY9 z;icoIBv?lqr)hO;6AHiQm=Q2J)oNm2(_U%lQV|_fXs?jjo&0Jn7&hmCR>GYYp@{=C z$f>Omj>dTFY~gCI^M@_2Uf$d-M_VLm=eD4=7pAbd+?Urp$cGye5y6UOtNcsKF{V+cO5)h6HtLt{mv@|#T zF%lu978zQiDUs^CFT~M%b9;--!9(xSQhz)j^;5Ovc>WuHw{F!C4Q zI^zt_@uvmW{L7@jK(UY7rgHM^Uj7D0srx<9OaL}Bc3=8wUC#SN4)>dZ4riHb*WjWx zu_YPT-e>m(ac3S?Hn!~(u?pUKpa@a>f8Fq_x^Z@&EwZ47O{R>HY+{118Oo zjX5jlw%{!ycDyv8P#7#9$MG_1o^WhRo1(a0J7 zuw(LTI+j5>p7$LcdELz2**!}JGS8e~dU*0PGgm_)^Z1S3n8PFpt2VZu!TQ}*4H7cF zCWp`*4lo6so*joo*P61PRs{N(0~#mCQBjgvMuSoTJv z%vqrziCABGbTwwz{ME@nofVQXuuf}moN6fMtV$el zXuS77fhZ0KRDJU61day3f;HcTbYC-rnLKLgN-#nu$p1*3W)}34;TmEpxzI$0=b=nP{?!u=k^P^^y4Fh);*1syLg?hPCA( zn`sOEY*J5YLRqCVS4OGIN;yacf|mW(@VYMKod!hEmCQXsu;c*& zoGuA|@OOT;A$=r5hlP?|_R`7%&k^wiVadp7ZH}33@U`1|WhVC5RXwaBGjI3%!8-~h z<$;nXsvz9tisY9>hyOOS8;qR3>rH|!b(9bX zF_!BxrE9&t%!cC*QVa$coC3(6$w#c8ag5Z&O@+dyMUD**s)9||EQ|z4~yjP zT#;osr*IE=grrfLTN~T3s)PwK&9A$Wi_e-2^Of!twkux@>&7^iWe>CBW1CI?``2~q zsq^<{-z5E`$a-Et=hdIPn>T0Fr{h|5G;B`tu};GnF^{OPj>R{$UZi_h#kHWHI$jXI?`wzps@la{79_K{vG#Z5UPlu)&CMSZ+OBEX;5kr{VQ*6kV@@wtCk`G@j& z^Zp+iaK-i?zUtl#EN@VH-6PjEC)@Ud)yFlG zVtjpk9Lh^>AZPTrDi!|;Mk3G$G_8i_sI)p(xw&Cki`+s-ng*A_(I5qK;c+UT0|Ou4 z7QdBODSSamnAO{Ua=EPaIv5EXm=PgA^*jq$u^>vAeByGc6wdwS-=A5{RUpnBi_w0$ zwsi~e?nKeEYoyqV0TJsq^smbU-*2qAY8OA(+2sC-OS*(fBPo|nq{yFs3DehzDo*|` zm7cYYJ``;4nWARICJUc zj}hPIDVhNE1$7ecRp&HD74F;WK_R{AkECrxvlCg(`w}1z^ZXLsfK|-PyodWUDYv@l z$Qh}v&idw^kMH=<`PS?zMHtI>eJkoy7c9i6pmUM_^4-3fL=RiT^$`>lPO z_vmG0Ea{2?$N37mwzPI+`^`e>*Dp^)gTM%CYYs%*-{ba`zt>JrvCh>8V^;3B?2XhY z(&~#Tu0bh5TzeOQ>GI(hUsj)NMl%exThvTVUVadzDOHIpI!08<8E4M8-GwOq5ibOKAlj$TPq$d$(2GWuF~?8NsUjacE-en%rUBjgYHkCWhkm7er3Cn>-Zl> zXTcC%Hp8`^%%cS;`Xph)Rgf? zV#dfm>t`Pao}@;9;1c?aPzxCuA_Ur%|MZNOuVO+Poa_ce?MyIP@98LC7OOGpD0CAe zWb(Ij;Wl$gd6EU}VuaYUcu$EhX!;At6^Uv%GBz&xzs=M*ZU2>xYI!q@2V!q@m?v1i z9N#wDwXu=$M_py zTLcBsQxdPUoSV{La*#C)D=9`h4r6lB*L}XmRl@6bk@S0+{B4l!S^+gNcD=0JwQOD* z{ZJ}Wg8Z`zhwlOrvf_2K2Hy?-`KXZM0(|{GwPfp>{5smx_m^nr-jGO2L*yMT1L{xD z(RTq7*lV&{Mo;L7$n{f9SRsF=5WEds!*yuFSW zTjaCL(}tkSvhJlozj0$ zPW~~6S93MI%FV+1WQQX-jbmX)8_Oh{`IIt>UWJQP9+**Fom~KHMNjL=Bo6R%bXc-! zzZ@{lWx>rLcI@)oD$ZS?h0xw0sc=ZVpiKCtTuv`nK1^x^Wbs2Ko&w zQ&`Y#;K1h$w$toCi1Xftm7L79h?3*4(5143_~7elF=e1?Aj_e1q}%j|n4N4|2P;YU zUz6P{Nt$reU*FOdlr+LX(G47?vc`cbRQt$8&u}p!RWe1K9v@=|9_d%eu@6Bpa%s)O zMTmnr+V&w*=i8`__Mon!Y04X-1xi5Ok#_J#1;DeA1@wj2fTshtD+@N#>$4>mxokp{ z2@n589^bv+XXDVGx|CMN=dK&o9wWr2;&jgCdLGsKtXvtrueeq;*lgCD8(c~Ln>)wWGBl{-Aj75>eNcC`G9#2oYC$cJLanPGR0D&9J9uWB zxi>V@>>lE)Eq?7I|D-oCeQS~sNorApk!~15aY=03QeQX(DpV~fT%f~7GP$2 z?oQ(yYd@S!di*BdBib)Uw)YWDAQ^V6WEFd=Q(JyP-8ItTZeJikvYZ3zNzTIg?<<^M zL(f@u1+ha4qQ7nW_w-T5l}@;|cg3k00U+l`jT4NYe{bKpv&i%b#oMpYRQjb-38VYD zom6;Qx2~2zIej&rwS%rBuUTL?KlZq4PD;wWJ+W#NO1|9~LzZ8^z%yWu1U5pOy=bnH=UjxTv`6?p@HtAwAMf- zpmkQ-4Ezw=xC^vk3xe}&kTm&zey2fW$SWrJ%ga>B?84`9`|&Ud=)T?~kUA$7ARgX} zyci4tb`;RBsd5nGA4~?P8`6F$=JxWlLid-WrB{qZwOeVb&p#fN${QGe6K?6`79r#C zIH4PMuy*<>Ho%K2{Q{YxA@f4OX>>9Z%J5k5lePH^@&_ALf{liuga<3cBg<1l1!jL_ zd@aXMRv$ukha+qoxYVa$hXdEZAo&$fLxZIKeGn1@-QHY2&n7F*PuR+tmbnU` zjOUj#O1@6D?aMu+!lS~Unp8SDHdDn<{lkSoNz3XL>{aKP{0pHOmAFD$ZI&;&sO-J7DHaJ)u0dwVuG|v#52I!T zC_(f;nLkYw#U#@uOUqoh-@ZYbmc~XbHM??&qB5}0Q4Q0pEp9IeUF`?muyy(0M|xF! zx6EgqAR%c&ZtJmN-cq}dHB0HIwspS!Sd|zOTKxb5ttV$Krhqz$G0pCwDidQ866E5g}=fOyY6J~ zs_BG%_o4o7U zOF4|BoSXXbm&C+HD9q}Eyd?=Z^_9mAL5(&WOX;5>$NE`feno7fEaa?BEl^u{Q_bDp z++f$>fo!#ln(Q$7@14m;QVk7_>^-X1%73%1*wXL?YA<-dJx;3x=qo`O)eiTMhB!ct zG%D)f9bxB9_{SA+3~|7C;Qpa+%QBDZoaaT$e4VYhkmUz%nLOY`4+Tqe|j7H@@B?vy_$>mnCz;T ztq4^*Vu@LxOtA4%f<9CAn)Do%4h>942A#!*6(=oyve1LlIp~nLPT2_!?tQd_(aa@x zx^3u*kQ;$nCe`8*9stY}^geNm9e|01ZbL)@6#b) z{rp0VPM%^&Gb_XmzPRQhnZDxQk`nfYODhUQbsMt={A+;=q`gg!9ePDPv#j4aOwp7y zm5-&Cc;Kt1F@&8Ns%Gs@wm~Y5E2UxmbndU4Q6Zx&5~I>fA%-jd>L<$L)u@QYMTLH& zWp}qXteB>YXci_V(nnm(VLS>*5*>1w7qZI8gzSyUlL<61GI6ASE?1hg+7x=|y`S;>+#k%>N$C<~GdtBY8dMcB0J(~>XAEG{Esp91`P6M@H6 zf7~%ulF3;~sSrZJekFJV=1FLWV$qVo^la*vpfnVR3=Lzs3+<7gQ3fLo!qCJQMXms+ zR9i65Xc~kFz>QK0JZ5opAPrggA+riiU-)O$3?*g)24Z~PoECdpdHV-($fuY5O8zMl zH6P!iIb%Kcgxib4UVvwWbVVmdEksH*#QVTO10_t=KRQgTSge=HJVM0!h**{asRmR= zn1tPV`re^cEE%zqe1Z&RG~JNJ6>SbMb=VBi+?o1f)u&rbLtfB29HRXO6c1;Xcson& z9N*FwwYXYGKGo;L8Qk*!nJzKCvU}}}R`Zr&QEWX;Gk#wf^-O|5Mr$mfMk)+@t(6GA z7Npx#S}bR$&VGor+rC%&@JPa!;8-ZBmcZ||rhVrcOsz2GR{rpD084cfWglk;A;r~~ z+_wKcJlLu9RZmOirq7FR@+Z3lPq0%Fb|M1lqUY8qTic3W@ zV6datkDu$iHO^lVO&?phwViZVgZFVKnCu0tpT(-)iZ%+Z8t19+vZoC76Jt{!H+y9P*Rodh$ zovblR9VvMXK7Q=G5M`)SX7QTtl1s~yi}%u-zw@?Sp%sI~mwQPZFB^3KdGIsXOn z$a(@U!;O`NVj zZ-Wc00ql7|NHbQY@?A;uKnD-y2)*+=@FcPD6wZeHM?gm|ituBteQVFcu~^ODgsmIt zbS}c%@X1k^h8Sb<2<`D&@<9U+!0dpi{TPTXN%zgyjw^F5s6=%LgPbc^u)sfKV-@xHN?vd!p z)N#)6lBt(he)2xf{J%-!TSnuM^-QeXP`6|kOPp!qFEFjRJ1YC($Z#jivxkSsmhO@@ z-Rwmwv)&;2T)3`HBB6e@`uEn-h-?wc#yA}A9oQENnU9Y z#`IV(kvohvH#$R%ocqk1O*1)D&IvC~o@|C^gyHewEH3YPjstyJ78*&P72DNbBxQ)h z{2|BFU~VHeEF8yjy}nh0JLgHZC}fgdbbiKAZY!5I)O%@Iys)*-Z_gFiElwu0%x&U5 zjpbq@s4?P4@7 z6c+u)bgMV#Un~ZPdEn&R*JW(^HAm)_&f7NKYo`mzwLBZuTwZ;v5}YWkfNXKa70u(C z!|LnyOLHsfr=(xNvlQG2!X-|!nsZJUjOCd?Zh=IYdZVAwEBR3DbUI8fy20WXubU9> z>&dw?s)_%)P-2LURJEQ^8&3Y!Sn+nn2edwvz^lnO$@}v^{y0Z{WH@OF9cP*7u?@+I z-FLU#a%E*mRc_)+r*v=JP2W20NOjXEl8Y5F4x;wP(^}^?AuF^?xxh&y3zyONFS+ej z%*<`fy`n!`(@MUSmHUW1YZJiP!_wb?fgypG6V-QgdF|^feQkLsTh3S{RUf;Waqx_X zdMjx$rBmfWO}hGcN0Rq5Zu)E2jqGVWmA6f^_POMbrv#6|L6?_7NoGO!5py>rD_@%8 z)9g}kKU!0zebnFQoBVwBTSZhhSQ4VE7g5Do5jW!9)Bx>>E0r_Vq$Vn0CRTo@YF%%@ z5h0{e!XjjCLOyX3+sK635YyjLZz7@oJIIV2KeLwW&*VHiJs345Kc(__olz*Oa%2%{ z_rbg93Rcq*8o6ou;!%%XK%wOKd_-Aqt`wCY?zQ7JhB=QWxu zLf3AS2GzJ^Mz^cHmJiM=ZuEBW;tYlE)d8bQ>^=DK&a?K*md@vi@5_Sg(2O{s<72`F zh7;qs6@Coyi0G^nUMManzAK(d5^x|)Msj#Bu8=8Pp53pA;%-NmPMn>e(}ADRuix?X z=C4Y?wa})2dokz7ZoGfC)`3me!9UB%H4_4N=SOwfdsv{bbMN2($9>2`aq`#hSa^@n zI3Rd7(KQOCZEGApEjaC}{j}{tO?{!1Wb@Pm&Be?A!Qm#AZGmZA8G>f_lk@CHWw^NKl~oV^ABIHF6T8(<2ghvRVsRJmh~=8M%w{P_7Jhqv_LaB3n6 z`b)UP-si3o192Gl7g@Yuxw;lNVQYadpYPS4&)c>}?TxySL3AvzVvW1%UTGoKy)wW; zJ}z@75T72&{q>3Hf;p{1JVK61JuTf$00*r?3`$43U=woPd$$fi#4l*^#lT};|7olc z^TyWS{=e6a<}tzAMxhJIc-C?aPV8$QO7hwEyt1LDo`H_2Yk>2Z($em8im!yL<2n|L zv$zxOdZeEj)40T#SN|=tmV}6Ltdd-M>&Ag^oXeu10I?<3reMwxj<*8CNPF+trsR1 z!#+Jt@9&9u?aFcHPNJnwGtX56Z+r1mxgx`!@ube5~y# zh(SXZiEFNVKTM>lx^t?D0+Xj=Hc$FCN9Fy?>^#*_`YcRrTVN)AfL*uY1FjmWEb{Lh zXN8)Ym7S5v0Joz3kcM6nYWPbEj{Z{oG^@|ZTb$Txw@cuAI2u`9N~ryiJRr*CHaKm# z*4bjnLtghqO@u(XL->mb&W)nw8u<`Ds$-YtNEC#F5wbBa(HDi0U^}pLmazD`ErL(% zpQ3{dx-K)AM)mu;C2(_>odTIGQg(~{P{x+`ks9*|rOat@xJI_t+6lg7c`($9^xo}K z+~oybz5#2CipR47FY!sJkU@?b=D-e1rshhLol>r z(IvBdbZGH8syE+)*AOSU*1}hDz@l3AOk_^SQX)oa{aW7ZU<@WDHaX_i(m7-^!^O_e zaAlJktAXrwbSv6J1D?L*;+RS^j_t_(Ben&u=JC}0GdX7PEOz_VxjHb4z1iHfh$o67 zKtaP-rx{|RPNpJ0aqThXo5qPv4bw0M3bSHS&sV=u0;8DNR;QN|jJC&ggio!r35uti=@^~_@b(g&P@=f9z^OzxSsak#oLY3NwP zL;Z5trXLi^ELRv3LoBSWHmsXjh@jnwwJ}cPpqsZDyNX+ZS_~j?> zqv7A8G_h_(9$1<{$TcW3=2`FZzecnyxMzPp*`PC_1vG~`fD&pz@4Y@`gGmPT3-JX1 zL)87tv4KYfONFW}tpW&TvsdupqqO94gA~w~A#|CgUyScp_o$$!363Lf%O8bQ9^opr z2uF{8K0IKB2=?Ftuy)(evcUsF>NBymvJ2;bh#j?@eWx?!(JI8b0GcD7KO5aUz$rJn zhN*}FkU;#j`kvuGTv`S3=I+~+9LZ{d_?)L2&i?bpc{Smd~VmA*(J)BT;tN z92g#-I^>dHg$pSIuX_KH(ANFiVVIy%4?8FHrS+B~7*Nm>DB7Pzt~>h(CA(^88wi7^ zRYz@D>MN|ga!W@lK6Sx(HO-xm))W(`sUs<0E>mcQC?n~4>*`KJM*P|fEfSemrZOz9*?LagV&TP{e(8s&8-mZ({m#qt#pmO0!9PHzv}2Xn7Mv0y6lX_EW?UP z)A{SM%BlpZ9FdXv--Sp<_I-i4%R+-{W<%|!Pa!f=gP$P zFBgnCTG$f|i#aMNf0WwCWiA~&hyG&YYVLLzaQH2>YhAT~s;v%@99+zC>x$i2Vt*a< zIey}E{cnZpqZcnj((~61tvT@ibNVuxQj+{h=tcooOMn zJBP_z;;pUM9o!Hlnf3hhNX5;wW=9fT2%Xwa;oz@&ibBUxD^TD&JIoI-HF@5mN+kjH zxwJzYX{({`;0&R~C~~{7QMt86N2lqbI%PXqjx~eJ0UiMs?XFq*@E`-rL3Z9znUifU zf9cca49})tLv&jKbT2QH7_?Lp&CbN7Aj}@W zT~blmaCFJD?sc zIFh?zV}G*^3;N>|6eXnW+UZ)4rdf|=T#+}4?x3(A!DzH=W5b8?AJ^>OxVZ>Uz|)9K z`CPZEKzQjfb?3Vam{l(8@8@2@U^)LD%a3yo4E#zkN{ zlALwh1b^ei{Ui)P z7R}RssVD?KJTtDRZSaTwnV(5YC6!Zd@rg0zCs#2(BPs#HrDnRZ#sS+-c@qO)U*Gh* z;0W*6TqZo;1Gy*O&+M)E5}6aDP^vmu#KH%rd++ha1Qh35*vE-&v{I2w54i8|eutMZ z{QKyEvE_LKJbC8RKSNnKcHHp_E8oqDDjsv zunJnb`23d+$b(W@K=1-ZS1MCb$YT7M=Hg5k>^h2A`2?*Fcnb<<@M{fg*Yd$IUG8V}G z!l8Y5PK(bzmU@A*^()nuDpe@r5-Da$;M}jlvVfc%>V@Y_y5}`y5i}6kDZ75Tg)83| z2%`mHcZd~k%QMy&EzWWG578hZ?m!6^6|yP&08n1+Kn-FQ)fP-{m`GmDAs+Pm<2khw z4q)TE*8KCdFs88dP{auF?gpMEAHy{6=InBCV_L2?FFL(-ur;`=u#a~9fq0g{aR`E^ zLUItkaX)fuh?OBa9i@GDKtZ*9$Du{{8AQ&eR%N(tiBq5{0Cp1;DT2q z4%cy+T!We#H->+7SJ{g+>X**A>B63TgtikH8Z}L&rpqxs0zHHK2}{okk3N*_M5?Yx ze8MX}IPaf~T~>D#Zo0OQA|Zt|`LafTR$&&L*Jf3Y9V}P!e7hK-;J=9^hAQRf>pGft zPL%>>51XIa4SPVOyFm+wG@@nwx7cVf=r5onl^+@=MVB&Zz%@^fmR{FWo6uc?T_d2r z)J2;HuY&UM2$^cvjhbKe`GQ|cRdxaXCo*@(6u3n&A_`@oL%`BEePM#H;r@$dEaKG@ z)N&Ex5=kwNpeC~yF@?TX6N)5EI;t@I?kupEs7AZ!=iuHHMjIjXxE~!+|3_?0 zVo}69;ZSS!6AbR3)%u#8jORA>6R`d?D1gHJb0Pn$-re#PK=`%L#NirJsLe+Ni_atQ>iSTDJUUjI;&7gkb zY+H4l zUn{s5k(uxWL~AlVmyXYVU&$GS5c*D+=ij@Y`WLpL$*ynTJ@B+BrMo=MkvEz#c#iL5 zRFh)QoC-L>w8VK9tv0@q`sBdQX%ji1$feYffjh=LF5py!cP=#2A!hH~u*#4OW=UQl z*x2&=B@>*)jA&{5gocJ-)$QCJ5;7!Ecd5QCMqv0Ib>A-jDE>b`cANT7Exv*Ntl8r0 zd_gEgn(5sHU`2rg_QTgwID#nT1qW$7|n7J~BuDr?T>u z6(v7`;N@4s8BbcCx3>?8z|3$%%aC-6M9CJ)5v{xJ3G43+w(%ZyN^E2=K`uxQyjUq} zkj$U?L*hB$`0)23(jvdUjf}UBR}2&mPp_hZW$T-8VeegVX6z3AvE#c?tO_n5vCYoie;ygww?(N-emUSq{q!!pxV=inN#tplRjiqbo@Q*K zW{#TH%g|RQg0s%_7_X-4d;w;%40o%$r`rnt4=t>5b+}&yc&z`D?XE9+5m7*IwvlBP zSfV?I;TbT3>_X}0TngbC*loF}e#PYjH!pVEP#J>)Ea(~uY;G)4 zfWKifi-9m-@ip2I(NSIFFh9Q@T z%wyyg(9MheY~>fZ>Jn#D;MQZp&x2De?A2*WtVxQdj8>CEL6sUVr;|y+{@R;7-GdTi zR!{?_dWqoQj||S6Ut#hq&26TKxQ$}U1mpr!s|h4+X=p?9{l|exh{NbE_L&xLV8aAY z2Isk$=C!k_L=@~8HNcdjaJm!*`TRF;PX0}EP1k$27vJ=5{rSHfXo$D>0ozIl7%~9+ z`EA(=zf2z=Uv~=q7G0&oaAPfCF=da$IDT9!RubG%j&wFD8`UwiYEW5hug0NeP@h@Y zS`Y!eN_j0y6IhdgC+A#bSU^CMANAArjN1iRT0Bl@(1=6mwb?__kysP3@Lug^uoN#VOT%;ntIITR@ziDQdg+^MrSAz7j${D0Nk|)pOMZh50MvM8S z2m9m?iyS*3wlP3WZ)b0I9rzxi&pzyKFT=IgZCzF>w^8<76+Pvrk#%0*^FOs}cetFo z)-NQL*`m2IzZPTt%-~C1wpYQn9Aah6rO(|mH^)Nn!d+^o{Egfa+Fd`n7I5HnEnK+G zI8n$?EkOvA?^EbwmO?|NO;KC0EU{xr;A!do;7q3fheQf1#6j<~m?r8;NmIBa*R#f#WkU8FEIMZUVF>+&~Qf;z_l zp-i?A!*S2|Si%n!ujBOE`;!VD?`71u=0Y3(LNNgvmOlB9~ z*OXa#)jZN1tvf$`sjfOh(&3Y&w^r8*R5h;dI>WA#^+^47T=p zS2T_RI-P=qj8VGP{qws@rCDv1F$aOp@<#9D$)oVYxAg}uK;qs!zDs0m7|f~fQbCJH zSp}Jj(TjXy3`fWe7P<;ZMqFRw>KlUsp4&TR&~`%#R@FHbz%sKcv;*>TV2!!EL(7}Y ztoBTGPfCWo_wq7?QTdQd&f-b;#|5l*G#YXHmF61E~3* zgu~j1Q#pF?tcrW5M_&CwYbV9_Q zW(>DcC_=lhEA?Zzy~!LjOuG;0E0RRVXD>amKRTjIQPv>&=1)_wUK5yjW+pSsD*lBye>)?3xMs$a`_;UxEL!rPs8ONWO?|yg}Aex|;i9Yie%VItx zluwK7s3Jo;Oe=z`EDew}FWVs%O`~uM%8Kx2Vb?@KqT!j_&J!arv#t?`bgByWJlt?) z`VD(`BKYtDM-4M{TcV-cV=BcW&bl&LVwhUN!ZE=i7l{{T9#f2-3jOncKQ%MRDjf!{ z@8jLdhhC|+RIE3bl0;|+QwqJRO?SHAybJ2!qh#cNxSt zuvclby#Bs8;s*94hKp#+loNBIJCX({r{-V3J2Nm^0A z|8BMv*d#5h!`(*-O~3nZU#^=OiSNRM5YTXTDF4OfHDSe~QYkpdhM&q{3RKc!j>yjO6~%3w$2Z>?HPu$k2(OzBd;BQOl~Z0;oodu`@y2nLdZre zU=caw=J!#}kWh`U{{vFc)k?3tNv2^X)f&;p^jth4ZKh4=C2e#=X08pF`IAr^6+!K6 z78}Nx68h(A0xXeh2g8)?DKA`CXF?P>1R51|8cBR_-G*wch6O#z2 zCgLTxY>tU(J-QVRlROghvM4@@rf5iGM%Wa(9Z>^^V~Zn*8Wyu?P0z~a$p_n(q){V_ z9y)>SKDe31+eo+aHGN=r2O_<>N2;JJ#QK)m!>$>42O89_bP7d>HNy*;zl`c;JPjio zPMPhKH!U6IGHhrlZ;Ep-EG>@6@<{)(>z4=!mhi6^m-oOvweQ0sGUOH{1J?z!$vL6f zF}ISJ@dWrsFa*1-BiqpYS4OQrChHdYqu#Ys7N)k)#LrNNLW|y2W;H`n13f%0Z-=N= zdcTyCV`JQaD6gCoiTg?iLdd@${J6HRd_q;J!D)y4>B-ynfhZ{hT1P_vzTLO|LK^kT z$h^6`4yE{Bv}~_x4R*xCc=mE`mKKrKI|GzWV#lLJ?)1S3CyudI^ZYs9Il-87ZKbVI zBUO}6J8*b%@9f9u_-Ht37m%}$O!(5!3T(nUHDmjDl(jugf;4(yW>cqYU^OpLohk8S z&l>@+mODOsWvEid`vGIYyY$;tcZYe4;VUvysCq#D=eQckp%R}f!1UB>zH%z zx<%(|sdMM;_mGA8O;!nNs+qrh8uo12EaY=S{Ll{-V`EWrJ$p~Er^2q2|LROR5$ zP}K+lp-&CUVXPd~8<6q4xGr#;v5A54&Un#zeP!(jD*nw2^FKY|KlS@tEorU1XxFo^LlCnO2M}PmOsoi&antW7$OqsJ5;EVvX0~M zuuDNu0RX}w(Bc9K(8DVT87cXp0=o<2d|TX4Rp}>cI!@m2AYFDfHmzs%lIA*#mVc-K z6wjqK^0G$%AeS86U_Rv$A)nq9JY4x@${=lB30P4|K<5-Q2L&!}QILh$4pGvV6vRiC zUXKkk#Zh&eZu4oN&Np7m-B&TMD7`DgO2cK7%R)vsR5Fxn3L>sdr+I-?bt5#|qF{b3 zF66yFzjH!#irye=tdD%5EL4@^oX$-4H_kk`C@$^7X?@H!wO(6g7KhKpsmq)})v&2H zwlPA_ko=^47h1&iQc(G1({3L5HCcE;68!@5;4a}t*9glK^lg}x5e1YOxp7cA0I3Eb znyL*y9%}HgNy8W-nq-+`4B@QGuFIOCB>LC%g+Y_tfJI zp;rlX5>svd68U~OVMpLU(_H5_s|{s_egC=UFN;$b$C0HtSKOCC!}^1?n`($OK;gjb_Uwrmh(cthH?YJdqwe zIEwndqnfgc2w6Z`{$-fmg3-J{0YmvwBTp034hh$EsqI-MnO8e%v5Jbg#Zh@fY1%JS zDSPDn!@$J0BH~y9CY;rGDa>Y0;}=}3%!hgQxzjc`-M775{T=7poOnaSN%M*o5zge+ z^i0A7Yi!ENFlP6zF3B&yw@mXtk3Ln|KYA~kI1$xlyt>-EOJ#*LMnIX?B##~X&cgTP zmy&^OBJ*b|+b7t2Hnz8}wEXxeq`^$nn@pbo^2fBA-cnbaIk=xX`p7Fy!I&eAk3bTS%gMF z;;6&&;GOC=s#FP-3mjM+xvM$`yyr^U;f(YI7~tr$W0Tn8Tr5>&Wd$884fgo1*pdgR zlNbQXOGvp!*hS%Ly_v5F&-^e(dm+ZCK#l_edt8GQ6hNC)y$HW-6%8j$hR4~^Y8m33 zEOah%_mO^{v<*wR+Ta-v1uHOX!`tKEQ{@62x-N84jszI$tIzhetmpS+vrIi6J{XZ-Q(%5xCl60h9{T2FdQs#Rbx7{H@}-sH)Lm-vZ8 z$;jNa-YeWyRRh=V(yQ}VyIDmWtD&u}AO|J6{k|x0_}E(>uKQse8|;lhxHj-|Tyj7N zMCtt$O}>HDnP18_KpACSV5!pv_5?o0Hu8i}5``(k$v}qIsN5DXUGC|@BLqzCd>Fg zz)lirA;)7nw=K3+zrG$5*W$cc&Ztd98I|JDs+N$IWdO>1k`E(6SSM7d?ywh{IK310 zM(9UvUH}pq(Tt9mDfw^SbAu4?O^%@M&i%c~LT&Kl;iBZ`%H=w{Fx6Ytt@VPx=u+En zkJ{JTGYnDs^pTx`1059y0GFaDLo8_dd2w+;{EYf9)N@fel^TzV{3@YbWr| zqA~3a+P}9E0s)Zb=}^I}9BNkv*pEs}#gA5)6OGW+4-Ol$ge(7zvW(e0!Lr~^e}aVb zACOP$K21I&68VCn)FFRHua;M)Pfi`#TTFV%WZ~4-pn2IjA-IY|h~F(+Fi*=1X6O z^3Pf(5QTrrrLLJ1OeOvDM)0dbA|}I^Y{e8xD6!#IK=E)Y<<``9EEA>E9E#D;v=LwA zZgrjrI<-q-nG=7MJr7r3_98p*Ix0YPO&FFl!VQ!!;^=kXy+4UACT*(FUsP$N)utJ& z*^0wucOz8hA$#H5#xAdpT3W`v*fD`A;7f^hb`mkZMV`A+_xb8;?5+WeIYA;m)0dPG zG-Baum06|d;~#P6__i7e|FdLmBA&%h`_J$jHoj^~o_2LTCRt7QtaT;c{gB|N;?0Ip zl-&PtZS*hbJxsIpf0TawsKO<$EP)r1s7Lm{% z+--5DN(l24cgrz)ry5S{RCXi{;az}|s255oOCdT1UlNYxhF|R%dJ;jAW~Oyou##v( zsod(keQs>vCzTRsW2fbWHv8lqcI-wO1rEb9qOy_3=wS(0wQ^eNvN4=9(!FBUc=v#2 zLoOAFc8KEK4bo&6X4b~_bA z)O0*1QHz(N)h-I_Cj82dk7w6dpv9s>6Asyt4=a5QC_=grD6}*!`$wsqiE#FNs%Za~ zsrQ0Sp3C6QTMQL0Xv)X~YFuQ1?Hq(9)l->>1GL7`<%uR_S#6vuBttSoAu87w+*QF|UP4cJJji78~6e|6_0}M}oGw@B5S!a*gEBsM^m4?v2$9XE2J+1mwdNwQ;UBsfdPSO zKrWtAG&J5gJQU1N3KqCJe7{}-eVy(XW7cyQI^j;)Qth74^9I~w9=X$FG&wf_=K&i$ zNvohBUJ4WvGxKBuG3bxL{0_wJdv1fR>ph!EL08O~4)VBtw}*HElJzV3pAR_Wi2a7~ zJ)?qf0ptopWh0O_Zp4-~oB*Om33;D?99=ZG{zH`Hm-z6Q})FpI5iqB>U`9_CNetb0!d@r9b`sJNo^54A=|$ z6bf>iA(ye-Vb2NwZiiF(CEi*HX>`Jof=^_Bo@9h&G@wP&}NsL3W>}ym7?~pV6@A7%jMDCpWb3aqp zC1uN$W0Ox)RxfLL?`RKuR4*$>Q_9n17$=dFu3m8tpxW-fP@k6Nq|Nz_MV_v7iS%Z3 zr@f}aT>WJF_IU`rM}+tt)KLQCa_5>TpfR)80J*q1bGyx_IF*GZAgJ2WU&HTA*Bq-X zKae+aG(<9IapQsvytPiFB=3mc@V;^KN@8BHkzZUNRjOonjM3dU64$aMx$-9^Mi)px zX?EYLI!k((HQSQBoqogtC&k`}qh5u@)vH&B1Z?@94B!(GT2}7TyIxjBgWno^!b<^m zL8iYh4*+LZp!{h(>hk{E&+tbsxJUCxsK@xg($>`-&7zCK@!Mz#wtKK70cxY{Hv? zj4PwY#R_mYK+7@k=A0zor){k^)!OLm6RSV$=g2nj)jxCc%8VUQoO~a#pZHR!P0jYA z+)YR=E8O5}dHhy3#Y6B{6h7;?7$5u_Wu&y{TwjMoDv3Ngdk6ZgUzBLh0xnd!Am;sh zJ9c{j)MNkgrNB6a;_1RSE09BKp`o-oJ-K2=I%|5~x0-joj>cf&bjA zM{U)d^nEGj#@p^E)9pzZs4&SFB@-T=CQ)7Nl$=b0WNIeN(>T{Azi85{t)sDNvkR!= zt)OYA=kfaC@8@EIJ8Rv#O(19>y;Yr<$gaSJKa@zqbnr0m)tzilTLq0p2H*YyX3@HT z5*TD-XG;5ap8dp0ug#+O^&Bm2`u zGcLwp5bo+fcy<<&sx;p3$A*;zUf(zASY+bNTZ`Xf-lc_Pu_&|pA|G`WJG>V7Y!X#E zI_qKtIDK+CTydP{b1jrnNPtG4y@z(u1WxtJRjiA$Q+AXR(H3I=lB(dEKw}X zT=w6*dtQODLV9({ns`^in%l8N^-<_b25~vS({SZj zb%)LwF*1A&`q|h2t;{zeA0OyR*Qhb=d1xX`;X+V+|Md4&^lD(zQ38*+4P3juzP3>v zKlp~PaKr9tNmk12`hnZKsCdn_{jNfHaP3 znw`J;%Vo(ZIEtqhoB~mFnX%SSFF|V6{%YB3Ex?r4hB?jNJ*yli(b{e_ykZ)cH3aKJyir3p4U;OWyR+spZN#KlgbS1k z#@%6)HmAh|pN<*I(icF@qVQqEDr4tW+Nnw3V%Tg7v;H>|Lb&2gX=m}B(KosOqSrX#mh2&D*P1#P!;2`7CEzDyb=b9 zF?mu*1}vRJD<-8#Twx49RRl(iB~X&kn%d@1x%TP@!&_e+%VgjGcGj34xnnCSrILdl zqs&l8jAs25A_zXBWhI4wNW+yuV*H%M(1dW;wmBm|rK!O2@abhNqupsHE@j>1M#QT0 z%iz46SZu3%HV`WNUH?@v0W8jEw*7XVp@c?-ustKIg%iWgfKkj>F%$Y3EmtkB(P2ZT zuer070V946SW<~#MJa@Esa+Aa6;Apg7Mi#5I21v(I8Ol+sH&=5k+aXj0s&f_oTTEy z+S5g6@R0i6fpMuVt*@b7nS5eU-Rs(UY z@P51vi$b7aQyIQq;r7?$gNJONAx(+D;-P?&m^^zCa2>8u)N4*_=O6U0zo_?t^$Csm zdHi{8BNI(4l&h){$#U@cZDrCi4F-i|fS*j^zHiVoq!cvm)fV4}-)M79meh7lYO-u0 zmB^(dV)$Y|FMVFt{|iyVLrNIV?gm4q>dbmUO}+FrwZLl}y60V?|SQZd^^ zLz|@dKaS2aDC(|_!^F~^(%m85-H4=03$nlx64E8o%?c9IAPpiQ4bmMh4G$sGASJmd z4e#-tVTNza?6Uhm_ql&@0f*m?og%7nY%N0+!)oW9de^x(AZ7Z3yS=C`AUqD0F0ZG5 z3W}y8|6Vr$9D-4v4E}btj^-RsebD6<-u1e+X~4Th`P`fomyUq;53h6mu#G{vBP4}s zt;&3p=3QX4C=)>i6$#fCy%;o8RpmqCqpw}Gicv zlo|bCtqL5q`6vpxht?d>zxMf$9+FsHx~;B@y6=OyYUIIQ+|eBKgy*cz07TWPb{r2} zIZl?EznaWps6DZ}JHOX0OO*{bFc94g9COd8)g@f=Nvv=tW?iEsl6Xt?Q3)YfH-)o>I4UJ-N{%1vz6nqT5RWWQ5F>WqO)}Mr8|u_><@$Iy&A5D0r)opR@v}O26c5$F={qyK&x#$*uZPRvEBh`1Jep`vYz^_T{`-)sOUTPY z(x^@O1{JTaO2Qe<@caJJ6Gg6BOr{^2u17J>zS0^xo@w^w`3d4vIuZfG{bN#gULL%6Jf zJ~{cGQ*IO*&I@EteieC_vXPq<%ASkZg3|+q$4Y zel)_a zqT?RW5D0~qq@tV=MP(i+?P~|tjNou>Vo_!ZKPK_}`6)EfKE;d=b+F?Bj- zO2QJ;@XAqYjP~l5<<_^^0ePi2FUR)0l#@h4HoO8h@q1JgO*xm#Sa>BBofnUGx@R#E ztw0s7Q)5g4>jx z2#&+O8u);Hs%Fu}T~gMHj&s(Vz=@#s2s32r_q+K`k8grog?v*Na&b9O@X)pH+Vq!t z^%dmyqvt?jM6Xoz%neRvBUc4!IxRbg5GH8AG;vZRZBcX@L!G3mbu`nS0q^6<-i*le zJ7r2+6ZIVSDc`Mb*2v^n)BgKt%($K) zC%V>r4r{7;!C81h(rg|*KmSM`i2~C7K5ZqDxz84kzyS$Z?&9^kZK!1zBH#*8kAdRc zbj~R5`>=Xtqt0YMC83i_1M?qrIQ1Ts*4uTJ5cLi(eSLa%C)4mt{sH_dG1OY0S9pl~ zPb$?g7G~kr0XniUVt$jFyGKmNJya8@>}5sKJouYhxp1g_`Z*7-822^NjhM(fKxis` z9za<5w=aZ>`zfycnwLBX-Q5lx2XSId!-s}60E?=y8sr)#334UVQGoq8#KJfgV?Gsm zg)cDvlKXI~iWlUAA9G+*U*{204^jcO)5M7c-R2;>v}f-&0ld}*5W_emR7y56{#Le| zc(_IxP1SOb-rxP};e6u$YuDHBXlix^e~6@&*|T%|$=bT1sUJ*CP!pN!lxcQQXIT2! z(0<%2IT}3I$q3JjxaYTpGTbNOrldsv?!q)_a zo}JT)q4E7$)&LFzZe{Xl?)?&#ABwQ&5(=8=!n{T=pK&=*(=?>HxMjoiv%(!whHJJk z&T`16{qvTWHoj5hJBU`+91v^ZYCWNQV~Z+iu+RZEaLj=YT1pz>qjn9LDVr>mk3#t8 zpV9K`;#^r!Dw~U)I*84N@u)S&?&8oH4Xrz z^d%fseedR5Ee^`C|1e)05s&}tM^eH%d)P{PG^JaAEINj`RE%a6EowY-`iYVV`CPZ{ zada`6N^&!voxruPrN0fq7miTzIhgUTnO|up=Z*dfdFK0Ir)W!;b^VvhfweTXlw(Q1 zwCMd{J70!J(#GGE8iTVA0Cg{#c(Q^T$IJ^E841tndj(6j z(G=cD{FKty<~3%uu1+f{U!;Iv%p=?cX%18;t$F`Uv1}sH{%z!cqGn38l;JNU2r{_K z6&erHsak7yEH?^Q+KF_l!xisA4cycm|D zj7x$eTRq$&)QB4wArbA2pgP3ztDjs4t9t%0E?gxMMgt{?2h%d=qeq~#c)vAtE-Qh= znzyW>l=IsdiQIf5m#feN;^DssnlA8BJ&_1T&R@25-Iz-;G_}9~6{U8l!0rMwt^a`Y zG8q1!NgBoc!J(xeg@5d_PonI^k;~+=50Q&#RIP>^1Gv*#Jo0MJ_G;l#G?-~#I@(&X zYSDv(7`7Xc%xJg379w`NBB@tOeOF(|$lcFU&ZTBcKY&#bvgK2sOgaX6rC zJ2Z-`ju|UegM1pQs{ortw}Wa)dHH--8Xr_)QZ8_`no*)wS>|ZcHI&+D8j9qX@@e@^ zD6RInb3Vh9mIh6jEE7pP&WvOyf-j=ZKK^5u_$+N8(gk*1<&~tv&^| zR6cv{E1n=EvOV9$oD1gGVM!vp_$z(hH{<7q+s}2cfT6uR0=-0{)O|j@yiW=Rd{045 z3)m!(!(x$FVN@(p?ux4yf|(c)R_A8^$|J-G_T_Wss_$+Lv zTS#k3CehInMfH4{03^HmHA7Y|=)t}rtHO@+2MrzJTSDf?ydK$`jCTVH%5cT`B-6h= zo4}{pGxIm;*=GzbZqTuX-^VoHz3%7NU8eU*a@RB!tV~v4y&_ibzIW^X6JXc6*~eNm zk=u9br#k=V^8QZd7fgNCmnxt&=QrV7XWzH?mA)ZH4m_<476KC0jKVQrKB^~ebJ?!d z9?KBsSMgSqMmABmk1GDWPKd%qgs~uMotjM^CCc)GJ2=}VlcG~3a+?Jb+p~lK|4Bu| zG;E1Gz00#*_@Z7B;Gb;{gvVFn}%iSay zP`U5pa+agaHC%3(q%FQ(cf&MdlsDC7M#80(j8gV-94njkgO@BmPRU+UrMeo_>oUZR=p_UMHLt!Lx~k;VWn{?~Vb&PhDZi2w&yYaI!#k zflmgUf96(x3!j$-r38Clif!nj6PNWVo z=?(LkC)DQod?efo^+zRY+IjfFt>$^|86;vJ$b30lCH!(?hJMtJ5t4eK0Vk! zU;vop$?^SiS08XU77)DinW@j)k;*FVwd)(+cc&|8R5IOa*I*SCAPZ#D^g4svnqmsj zSMnj&eg-r*LF zZE4RLQ4gd1a>#GfEtr2gC3Vpn9jcCjzR^ZbH09Wau-Sz7pa^2RSZyv8~nAsvxF3p(#R{O+Z9Pze6H z=F7j6Zb~lC|Mh0ado@o0p58w7CHVY^d^jq3%DL-2?|3>Mz)V1e!~L^rmXCl(2*8%w z&HJ-64>B6loGh(Q4Ys7xKB}SI2%gISOjDef)v*nHU-~pOf{z&u4183fbrpi~lvf~j zo=RHn74Du;CtgK<_Xk6R?;x(6yrM84{YBoUPn$;~KFPazVA0wF3W?XSs@cUM?Yndl z8~3*4P zczqjd@dP7}Y{!8+9cJw*MToXYJ5d>rxY3q6{Z&=*nwQRA4xcPD?1s&C&>t9&f~cWQ!1f zdLQzy@P6dO+LW*Ho-M@3)0RWasXBN@^*MSTEh(F6md>@p12Xu}P2DhzG%FjuTPOae zboWkm$9HwsHr#6kO0&l;sVCCj(1*H@wY`d+Q`qwO=lh4xo(aq>2)|@t3j^rs{x&)K zOo~qa{xJAwd+oP%;*0siOxkfB2{}yBCdq1__gkRPg{jL4zcnj;ENuEg6F>TE_!()g zb~D!Tusql6)JE7sxVZN0^ZY0=UJqLsq4^f%4NvVG;gd3{ms@N?j{_2GCie$1h>Apo zQU53vs#u()2C6Em>E_cqUhSCr*w56H>oTL;ll12Ct`KXHRiYc95QYxkW%&^`*YHb! z)m~uM$F{v2^(>+c>Ndu>laNcc&Sm{@Kci~9->CF zxs46iB`9lbUxv+!^N}E#z(tygzasS6i3;+ z$?wWq>(z9UNptGo+80kCOQ(C5vm6x0v(l6p(FuNEJ+Gw(V`RUcT$Kr2UhTY^oZ~M< z0*^}bQCRhkexwj?k4(8@ci(2M;6(^&>|h$!&lR#qc&M`;{A_y(;iirY0u)(%bI;aU zu`}jVg1J!)yX&};xeqjRxuw$0REuz0IBNJ_`Mwhlx|E5$IYyAODP(83?U|GujShV& zVZ4=e^`B^PWoM#0@+20m;nXkH%^YaQLX#jnre`ZmoW?)NYsnF~WPCV!b6VE*@K&3Q zwI-Yhz|9b&1!BkaU`@F^t4~@^YO|F^M$z%qmLA{wOL^+Q-kjj;Pxr?_+U>eIeo*jx z`!4*y-z^SRP@Sk!*WpVoW`qAI;(l6t<3)wyuldxYvb=K_+g+HRB{-9fzF@eUOhNrZ z%Y^dg7{unXF!5(%Ms589{7Tg<40~u)m?%)bjF66PG>+;sysxN8G7X1i?uroxAneoR ztK!XTB!^~2R5;RpytS;OGKCm>zc1UdR|Qw;yjnh9@of5wD97&2G7aI5Nv^XvY3DDs ztrYKk!^6^)m=cxQP)Cm59G}+`RF@3+?wPF9dttHl$9>M9by)B zT#`A)xtyao{`xf|9Yd#0scm^9(2lK5yx|XR8IHdt_?sl-Q>2wVxF{qRLy~)-0oakQ zmJe^gm3{4ZfX|6FaKnZsDz+`I@le`=9y_dPzGjCd%7gZNK0H}@y4q^I@5$jevjT6O zC1l7cSf?ej3Bte!$zTD7Rtl_1a#&4ZzX`CHlJ9*-#{c~2$-oD?dIYg-(A^*7ZYs#} zY1zY`UI^y*)^6}*AZ9%i9s;8I2mg$N?eEs?0)lWd-5oOFJ#u@~gy?7u?U@jmg@K{i zb*GBKFG&VQDJJ=e%ky(KdRs7&lMW}4B@Age`5VxxRq)qz-FN^CCpR zx>-vNj)ZGPQH=Cjl2DZB^nC4qj9a4)fNVdXXDs=kAIpi2%;Tlb4I}U^eEV*$;G;C^ zRf%Ms@9v^T&17Y#pKN;-=0Gi|$Cbijiq-QTO|leCk7$^U;xnbW!%V@N^JN=vtLq14 zHbwM|sH6oo++T=4VHZf+IqyMPp~mCW%b1BzUHMhwpk4l~eJo=Rqq#GDnr7%Ov|e2J zLl+<2cbVMByRCUQ@F^|?U6AQoZWr>qe^Sw~2>dR_oo?!n+%NAzK_8QOYM`f?+ErTH z?9t!lA>s0){bmebzz6X4fpL<v)E2Mf$R+NvVAyAda59~j`M)L zXgB>I!BKe7w;+;^nzPndEBuM08syOclXJo|P!3s8A=zy$!W;i9;Ei5?H(H&EvF+M&pt0+9Q6+`Q-E!h%d zBN}l;5{1+kZxxphLmEzu)_u*=8aHyy9`%-{ch{OkmS3*g+R0_*e+a*;3AH7>5+pfs zBTMKVPr4%4zAgnim$FKwM2vx6G+q6Y391^es$K+s4WM^$c_`shO;G)2UuWuk#Yg_*{%vvpwXI;~I7-zY@9}Tg3@tFuEmr3N~O9(=f$*_KHQ|~sM z5li*>9oB@Sq~MbnQm*@TZ~vEP^}acLo_K|y5?M&5&sN%zesV=SG{mf|NAK9MOG`5^ z$i0tP6i^?1ml^J8ezwUl?+kxQpiM^Lz& zYN)d}a2OTcM*=e~X!8c)^bnRMOZ}nT_~jRN)ZEL7=oXw6G~z{0(a)T>InFjbpl+IJ z+hB9i5_9ZfY1{Hr;PU=V`67vLXgfd&n_-aa{LW7xp*5iz^QMoGXb5W*5qEKs;s<-< zCiUvLSRak%pp^+BJco3P~Q~^^rsJX9Iy0!;>(7$JW9rflAL|ZBR^NN;Ti~DvAjKmli829)) zr7xM-)J+Qy0?1(rKws`WCP4+0A@w-c&+7BiUpuuxj7VR~8W;e>vK@bC&|Mt(ueh`U z+LbTW(;MNz*+j|Tz9z=Po4_-&2CBuj{qAo^?O7nQ^75d7JOa5F7Coeq{CG12oLHb_ zs*_Ptk!#1desMZ@5mYh11S1@aCKN z|F+4^vmH;0i&fT2=01*L&adRLuB8G}KUn_!Lt&jeGnCTqPhz zdR<+HPS)>9^*hj%+u@)zG^xMckP2BgWPkeVpPhGZQmK^76O==_$+C!0gRKk`8zcEh z-z<)QKtL}b86srP!RmE^@$YbaSY_kL+B}8Q#?KvCD8GE4Q#Pauavf2>y`9iEY>Bd?LG})J_?>#Jp#>oc#d)p_~ST3=5 zsLehE!i#Dab*)Wo*y`WtME$hm5{~~#m1@e7wd!?i+xL;B=(Bg!=r681(o7WP5>y8* z0v7zx6u}mGKR7bNb$9BCbh>B4eYa4ZaJn0{4Y_G5 z=E?y>bs;GH6`r@_+>w$~)-7Hy1zhF~pX8ywl7(EYPd(ara& zqqoAb5GH-`QyaM${gb@D8=;YyuxO$Y+FbOWFPr++M5ukj)^wZ@4a{F29afYN&p3am z)xCd-hhpWOK>t}AoujU(B%{}X|Ir(QK{gqo-;8C{TDWv5z9Twzp3pE4a;c8?GIt0u zfKxVDe+kU8;~-9;A1oQF>axlRP#r)?J@^ynPPIEYGwU{9&y|v};USRa$VfvxC8~WA z$DGgYgem<(s#0wCnlK$fJ=1_P=@%F{*tc1<`)ChA!)nzSbwSuS3(ZldM9y_@QUAS> zYsw~=gY|5Cs42ifn@n?oMjNcnk51hI1u41_AY+r2+0X)R$i@V7AAcZ_dj#o7nKZ!c z^ngJcFr#W!Vo?9(vo{&Ft9|4Y#%+nzNZ)Xx++L0 z7y4qJ`7&hUQ)f3#_{@z=X2*qZdq?MbKqqup1EqUM?^Ax`KXjX0fE<+C7=JnB$OofP z!=iTW?>M@a&D(rKCe=@4px!va%rw8k>31R)@E!%|@ml3^(p_MsO7(E})PbeCFMwbm zq*1YJ#D@;WQS=?M2(ao1+C&X!3Y}?x6JeR8KHcfuRhEp=B!S67FM;NA>Gq;#o-5K}34`8^GIJIQ*M2_@olz zq>aR{5<6?}-<$5a!EUa+JZxU&5;;>!CXmV~fB)^R`X@b3@Df@45)n7lfDbqI_V!9I zxOWMGM|e|(KNiq1hKXze9L!fiSCP{p2x^4zCWyI#WPqB&w9#ZViVa`d05p$sx7 z{(*~`Z$+jO8NtG-`JTkYqFeZDj8eg{mWhjy0O9;n2=Y&yj|!8_Upde;(;0Y$MnN&S z1OoO3Z^Zp%a!(H4bgf^WgxJk&c*$=rAtcUiqOr9ouNZ#v77i~k)irGGzAzN~9=C(o zq6Tw!P}dNskZBMPNeD^U9U?g{^9_7^m5|b?s;t*yCyMwyq_c!hRnq3P7Ipvug}oXX+nV~O*=5EOt>Ypu{X7R&LZ z;-vgTS14eWIxy2GlF){=73ELdC%Y0qa^y3xt<1f=VU%1jStG4tC%pcKt8Ln>@3ubp zN+9@?sZn2#XE{7yU)<6$$)DQiNp?|=jo$>BNCIoAf9nttvN33qKAaRyJ`7DC!ba@` zP+yVa-gWIK6D2? zFYPPnhf;xRvS?|Ra`UtscZ%?LRiekAyfLg%$WZ;q8s}n!XB&s@*E&!Yg+c`;`WLt4 zCG8zc$|Pkq-ztWAxcDtE((4Oms#(mJS7cGROivA>WZTCG_s`9W{k`dE7-Ds8<{jS= z8FVcUdRbcYd?__D1ivIMA=d+rucm}2(~4%YB_2M)#mbD#r8*_bZ4o!Kwu>|^YrVLK zk7Ngjc&wq1t~_wH!uTgBE~Q8Y7(Ngs4L3se&R`fV->*?nd-fD?HyO8E*}i2YD`TF~ zkpz~_w=@S8*DHVclprFvbdMzgZ*V=GAdTc#%k$*zP;VR*O!%h=$=pUioM^PS2MzrR zh(acyC;D>Zl^>*j!`Y!SAysra5S7_y65jS~A#FhSO}F@0 z<^DsT9@()NeaT#1H&-P?BcM-fz_sf<6OtC=*%Drt0Pp0~1$qvvNZ0DLj&;^v;(=|; z55%OK=|_isn)-$JcBTn^7SX@;CFpXHz5Viq^cM?w zwmA_d&zN=e@u0%HcgOTC-Fw?bwZ{SO+)7HcF$-8-xMV)Z!?iM*w zQzy?`Qc_>n{Vm3F`l#|he63SLof*ZEK#e?DhB~!nLbvScA4FYBNJozRgYa{n9Wb!zYE{p1xC5c|T_fbE>N2C&`189S&{F)@=ok+g)j2 zcw-#PMtrwoS#1Xuq7E+l2qv2DgdbOdn2ICob$q+60AdBmpxuImes4G3gz_hS>0uC( zf5>4;9l;;@ZI*z+6js5e^cSe_maCTQa-VQIA7csR;-~Xy8p~~V9>kmX%g~CZC8gy^h${f)anIio&4UE}e zz|Y$)DZTm>?U}DSh!;LbT>jkorrCVI*mZ5()vT`ggh}vk59{zCW)<vzml1SA z9RAGo%w)LGmGC{vzHR-pwQv}mc?Q`h{zVK`!|=42LvFEsoXUP*uY+wu39>JLNkq(( z-Ey%p$V8iX5$j(X6+@d)_zFqiO-im3l0t%+^9*lsl;X_`UT*Wuv7>4_2t6qp3vJ20 z((@`Ew9G;YitZAK=n&WXW1O6)(C#t0=_6H?9iDtI@1NZr_)pk=86!>#kbL^7ESqW8 z4BtYZ9gogsX_BcX)W<|Xv&xsB{P^J&vWFzWCV{A;j`oy&AftA`);{x8aPAzWG3k?p z3g4tEQ}O!PTid6MoVp8X&@37oz<*rH!@%4r*qf(&X?yp16X=`=b!bP|U zyQrU1p z;xgVu*0=?NkS#;Q0!On3op_cBl9%1m{BF~hhc|iUr0oLaEW%D7%-uVP*G9*(`=IK@ zlH!ZVC;c5s%!+8bN!CB{m>=h9o%cwOux?3d=BLHW9WTrH=}dUHmN5rdtiS~g!u4;_ z8wN8{wZdG?M>LarG0;*SUH69#1CiH_yoZOMgjCGaqt zjwCtSmAxO@4D9}Ne|`a`t%n%s??vtzqgIC`4_=%_ZY{!E2ORn}mdgI6G+k={@qo=b3d#F z=|;*KNtU?n=QFbz?8Vj}1ydZULaAz(T&aE-qymquSZYGvmZ9lp%_^WdAEQMD^}5lL zpw}!Nf{-OBs2~pk)9J-btdSAvYn50d)R^0Gspz`LR-W;owae>gcY+?#FdRd znV18p|{a&Zfi57(s{fuQu$?O+yw@=%8YaRtib7yF1$?WFl z*;vT6%U)PCQuM>oGfYR$v2Zbv?hVtDlfIugSlCo}AX{0Z2bu+I|v|L4D|Iz^-CAHUc zCO4kql0%4}y;R#rZwu>8`YcZ4MGDj)4VIvpx(QTfwLYOn6D`FS0B%57nd~_KBWG{57E}y6o zG~0-6Y)y-%{&pw3bJlIkinP_ne1+5^dG@0oC@if< zafn0ZcW14I$1)MbHPtUAVhmaazw(OE?53)E^qCxGYB^>+T(90{uR2Y+UazU`gDWQ5 zN3J3Y3)~HhAYz+{#K48J*uQTW%~l~<3csgPUTT-mlrlh=#_$fUls&kK znVv9RoE|Hg6pGgLF%Kk;_%Jw4!#zCzZoDR8#lm5pGooXA8j>>SEGK$kr|L=>J*_R?{2I9%`qTey68K=?8Ha0!yjOox!K#5$tVEICE--NFRB z5hGew)vodTLiU$5schMLgEn-W@V@SKol_azEK8|BG0C6vVvXxMADRD#Ma$4mpmC@V zR@i-G|A1I%V!teY)G#L8nfGimtyLY(j_`#vH2rzAH6UO3XH9z3X&Rv5*4{sD)#*C> z(bmrtSFAoFHlOyq$BbLO^l9x!T>7x5-<6oeV~wH|lWuuM2%~6HOkS_p=;lzu3nYpg zsrj2x2+#Ra%THb=cSND>SEyQi#2&X{u>VR z3Dfi?CY+=b(1BX6uz7rc5`6;+A};lyl3p>-ig!-iMhStL9wo=Q)9o@>N|Agzx|sbu zrL~US5m-39knHFxYFkE8OZ;KW{)ml_XJW4&7sUYgHM>eKQdX$j%G>18;2Dq38}}W# z24>%1v{YDR>uX}$54Ai}`a4EpAWM$oBzhNwVGAx%{-%%y>Hn896;uuW2~bJfmSn(D z?LY$OJesT>Ksx%H5tB?d5$L9q0V&zFIr4&Gb76D+G^UX0%LA}{a#cxv6i_oyn;GPp z@C>}arPhyg_SJ2Uq6%qpf$|lFBo48DZygkbgSDHQ;6?5Ivf@X-Mu>*U41 z)$Q$-NITKxjlvy{nkkAt*y@7Gm(wJB)1#x%l?J~r;@}T_C>o2(2DYnPP|4$<^6CTz zZIG5pz=$dU9B^rG`AKf>vg(!t85}}1GQ2M|OUob-S#Tipf+G5Nj^vW8yd1ND@F)__ zXY;yzM3is{T^BHB@+Qi^i9Sv*_=VX}T`hu$UsReJu$A4R|mM@dxr|7c0Xt=NV zug%OP7yIIALSN(&ZbCVY`$3U8SA(CQClLikAlD=k`_XuVSXm?q_=BIe zc9}diMOiw5d^b%y&BLc#`7UC{HV))~Z8+d4F1?>BL@2*;tTN57@q-QlpEJ9*aHe|F ztKpN^u6yoIDWCkVn-nnL6BD!3Rl*cgZ#a)tEybZ8N<(QGwltT~R#I{r`t5IKCT*{e z6&}B6Z%l6Ah+d`m@TBGr^?XriZQ|5j*J%!`k1sJT$FrK+cajcWhAAl0cXqifELvCS z*=79S6)eI!X$|WCBqvOagzaWTK`74p_gg;!hK^oMl>C{A))O(h9oYp^80S-3O7<10 zz5Ngu4;xTV6bFOlG=`Oq*|OD}7>oUA8f+a0**ep-0!QRlhIc)ddf=C_e`BWd)^pBppj6O&p+ZSE(ZT|gcXl9PBbnKx?IKw&x( zL{+owaypa#2_*NxR6@-~f~I?HuRQ|?+A!Gjc{LN>O|p_rO6Yl^m@RAhYq}a3VE`zQ zIHpS*v^UF6c>8ef^yPPWk54mLg8&bTbGHS=EV;;o295zN$tPat8PKZ!|j5KOcue-7SYuM{}aM(hgd;Q!+K zPM1D|;cc<$7uYQ<0H$Z)&6-R^2lgWd2EvPiwu*fIg#!d{K83isS$VGRn+7ov>c__F zYD@6WZ~p3MTXVi{E6^bDZ_YtKtv3KpxjDxd84FE_mZhvgiFiU4U> z0}8K}SrN;X9shRepxGs{pbj4zFtUQ;mI;tY@bd$lLe;-z1m6pl@wLglzVsai^!*7` zGk5`L$!xgK;?N^A2hs&V1A~<1>Iz`&DWl90FXk>Z0IDQFQO)Bm?#m+Fe;$HEJQXc2 zENG`s5Y)%u&-7mq^BK+)h`YqE8PWO3P*u6Ntq|YF$<{04!!>>JQa3DzI`Zn6OUh-U zOx#6z0mj%V;!+;LMm%U{|g*)T@*2CNVuRi6~pX()h;^2R3?E&W~2A8n5fwMlL7y>o7)b61YuN9QWNL zVd^o0g|$Xn#jH`J5yd4OB8qDntLV>@OH7g_-NMDSp5};kG^Bf%mb#X#)=?-9OxU8} z90^YIhmbCHccUuvKEthZ*t%($){m+TFeK+1I7l%hME%x?8M#YUpHqisiTBQ)>Rs{Q zh4|-)x|(+fa~PJ=G{o=r+xbk4zH6m9Vk$~d9Ebil(?=6`y-19Pmrg~(R>=Yhkfe1& zVGj|lZ+}Ei9Qjdf&cn)Zi<)`w7NecJ#Oe$mW?ED&If};J+E6pAj<>|CZDa8LyknP= z^OW(Ex-`1&Gfl~%-WN{{ic9qCpCEEbM0cbP|2%7E6_S{H_9~0258}}%jDMEoR5UxZ zT5|KMEZBYkxyd@dvoWL_|M7->uN4(q>c3j@%FdnrLN+*Ng5BwH=O?W<=^?FNAzS*> zLZzE<)w2tGJ~<>Yac-*vpH{H#C!FeBwwIU!L8BgUA@#tUdxGHmKN9~m%av8PAO)yJ zZVl|W2fI`XALE71d>!^s_l;ncC*+~QcsA;uF2H+a;k@ z+3Lb!s^Z??M8MpF)nP}t4H}WmeN4c9N)SF7)#R+A07e5)Nmo$qq&QdTSSS#bw-ZQk z4492^73v15zfr32l=D?0$AlYb2T4_=;|(oXBT$+vPx7AlNB89o8K-?7RZ81w$3MhDI)suEd|pe~ zilbZiSFs)#Q$ju%Igv|+=K(sN&k}u(Zw+0whJV{4GaAUw#3bRkhB7S!gk|Q`AM{Egy1f0j z&Q0bK!%csE>IdosqvYz-x&=hAr$1-TV;tK{2ILq zRGc3!WRecL6(;_Ty>PIM2p{7EWagws?0?yRxAe`x4r^aYt2W1N8ptI!-kl=KF6L)qS!7@3W@3Wimi`+!RhEJV&;q>e}z0sbi#S&CxksaJnR`h zuazWbl$QOe!PF+^B9yPHoZ(sFH;zf-<+96rO8?N(*ZSnzS#@Y;@YvsUKM$Yysr_Tn3TJ6@*2hCK#DX{CZmNaTgF z%RlrEI!tvssf4fqXD(jh1z$_$pr|`^^6VuE1epUf^^y3brr99|) zf$hjn_~?x9E<_W@a`DN!&flp!P4qwml*T6kUj9d3$u^29+IC|60z5IaR=)-0scbO9 z8g3?V1ru;4@!pQj>q*8>a6V#ycEdPA)+DPKWt*_2ts#$gJv;>}$Q+qm8S2D=tGVlL zNns-~_!b=);3%3A1ar1-y3(`=zO0QHpzb-25Su#b8$x(CGd8lQzrALo5JliRAas1X zIJ4`jAx|>LPA_lSx>I%vD!;rvO|oyukg?FsNF({~aH__Ba*@aF#jHuy+iFd-=TJQG zs+|jW%RdUb>n`=GX3_cN3i0T>R;se)q!zfVuGF)uWbVfW)tTzXQjqt&!#@`jpUyN* z$6!XAX|T#Q;zPu_GbB-bo>ArqH0AJ;2w zJhL@$M!T556nI2Q;~$I2^vGeEP^(|;^N${D>UcCA-G_RxKY4*~`gtF>=WUMe@i04+ zwZ;6+{n_8Y2_XKA5XQd?fztWC(e#`1X&$JXUcI@xioNKZ{?{UrwgWipIx0^)0iDy` zWmu%W>y!UaSSYX)&1|d2LI)w;{-sTUG+10ZO`dtiFJO^FWt>zgP#Vruwa~gk4j(Fx z-w^EqY!2x;g1EYVpL*5|OFOEn0U|m8d_=Z(zka_Ngq30{O3T5o%bJS^SVdrS0Po(r zgEUw6p5(2)>xKq*3+r)xAr)_Kd0G8CCsi!Iv`#T8MeMQ1O55@A8wZ-|fv*Cq1){{n z|4=2Ru9M>Y0ejzpb;vr$4ss0jj5j{*SUL9N&u#@uO%led;-9?^=v~s_bqFPh0KB?u zvyJd7ocpQLCO{#xL!bK8`5|%j)>F^k~yv|j?sVEg+~u@ zjzg*9e^Q=&>1!-{<(KpbfUGN|-v0WDTSC<&GJywd58&~CdU+W!G{o8Cz;=$gm-X63 zFlKuV5UG7+@>1^SHa#}%$Kv4P5eU%ekH13)#z#980+o*a3TCA+(86%~_wV2>T8|I1 zpQ#<}w;z)+d0M9a;Tb&$gVNPj(v6=#-b1&&=Z9njpMnwbrh#=u>2q*mRai=B)u>t7>l`Ci6oZDM(896}g-C7gyL@PL~7 z`lhGC)ae67>?v==*~1AhAu~2!f=r9xb-0BkT?c1UsW`>%M;=U$kE8b9`-6Z-(<#stqb~d})G4PTcHeeiMSg^*a#XrT#-q+n_9m#`KFf@4 zLo2})rn>5@-J<3_P;NK~OiT=wj@cTL8p>XX)mayQ{z0J07+28^f_6~HR9X3J+vCjF zsAU26HglCTKgjDOx*M=?6Cq#k~7o~H`0@RPx0-cG_L`P_SyDrpIkJ22m`Zdksn#+to!;LCB~pbhZL1qSUqCD!YNc6lSFZGM0kGwI zV884H@WsFkPRzIl3M{Iio-0Ms%b`w<4f?CAD^q`R$`x|;^tINRf;tZBHry6i2Sb9W z0JyVe*_D`8V%(hu_+wDjqET&j$7Bc_(ks|7s$O5hF^^9X6J7aSyr7<#E)k1dEwuBv zc8UIjJ!BY&Eil8lK2&{5jIiQ5o&hmi$|&!)Wv2d^BX!<3?PP;oBmf*68d&ejK=e4H zI)T_5-3Lu{q;Ws0_5(?mf~T<9L!ao23tzzS92&whaRQ0&ySKSR+a4q+z2fq@c*3OS zGa-e;LSrJJ!R}uHsbOUEys@Zv{LYSj;KN_~P0{uBJ(4*y&yc8^r^KE)Qa93K>A4dNhT- zV>rUrDLZ7>1}jrk7GJSktywxY*uwbdT!+%3TLM-x==;fqG=LUlDjU#kx4=kvva)#| z)EhJb?V8!6_Xijnx*a5emXO8y;T^$YDTriW(GNN*n}V5@=J?oNm5VNc=zkQQWmJ@1 z6ou*T?(XjHZWsh)DCrQ8mhSG9ZUGhPmTm@VP(r#vL|PDu?|%PeE!Tn>nET#y_TJAv zpWgPAVH}N%-6dT7zWorQkc4lj>5IpTI04-Cn@{BLw?n6IBN2j+>z61ySFz1~6<3AsQlG|U zRaW01eP$Co)KlyJBcuzqxd54hZnVcSr<%1R(VT$oh7`Pv&zK$Wu>vjL_LgY=n9B;D z;{ZwJ@WpygcXbF^dq~XZFn2oOi@>p7c%3v;g;DQ^s4TxTe50LGtv}9nOBnf-nF{CE zul@)OlstXG(999>Tw86Dh11}@Sh1eiLzMr7J6^@!xMYobh?r#@48<>UAXurvw!^Z0 zD^B*2s4^+(O$L1ZOs3juiY9|y)-8w^tU-*Kpl?U6zPW!YFkS#A&ufvC;5f}}ytdq2ZZ+GnB zLtF~dwAGsManTljGZ&?fvGGvO^CYK-#OITIfVHSp3Ega^HBivvDV3;ma^toK)Clh5 z)buOSGAYLMD=R6=Wv=Pja_)ae&bm`elw$qyCv^}`PXg{IV{4jn?AojH^wuBclN>~y zQ7IHaE1Y}17jr00{i0@ZaIh(C9IN%59t9_dBxw&M{tO{y4PRgkmx2E%5+aL78#Luc z4F}}tU!YW4wNm3Xip4tRZA%OP#K@i|Nl8qMC|`uC4>EEkeYMQOAIqtjV5JjIIKxCn z*>glDORo9YuyU%Gg`8!-*U69K%SG|=Q%b@*1u;Bw6~gPvGE27fdsKL75|tGp+c31~ zwCg1&K*X2hpo24vF;I30jO}BPw04FMTU+wvyn@b^`Z`G1GgDL6mTKiAZ)K)oTn}rp zq}9AYRh3E9aQj3bjrltxmu@B?LrSbK0TFNIU|5JXFO}3j;s@k7!(Yap<1$(??(WYG z<LyUZK72$L2aomJ49 zw+i)^#NT#ddpe&@-ipn&i=&8#ZYXj_R#m4LAUq~J`JZ&c@t03}x%|M0jiq*}n%(5- zDAKhZvsG(_3Ap5AV@!N&nDm^E{1F&w2eks6DRaiVxJeSW6AF#RU#3gjr$Gv$*Bv+1 z`JE$gyJCIe=imzhB8Ps*b#4HGD0h;M7ZZurqv!42^#ihO@Lyy*3x)~IET3pAs`H!G zdYC89a}uFzA5RWv67#_JS^`%y*%&&&4L8;a8i{Uu`y&du2Z`y^yvMrimRoQ8n2!Px z`nyQR=9p!d4ASvcuhYhp2CH1HTIHAUZ40MKySsZEmxUzrR-U?`?&x9N3YlW1scpw39AN4eeeL=AWW0NDUof;p*zD$lo_*Jl z)pOYDO^gq8JDV5)-SlEk#&2`nx{DKsR#(aY4I#=rUpLn*P%Q9mtuDDyUB9In5-3~$ z4I$x{0a9poLjv&QUkND=c`HF9n z@W(m|1TpmK^d$&tDt>}3Gd3m-?*5c8>jL1<_!%*mXO7ZbdN zC9=;^&vzwHGv^b$vhZ*KO1&lfaDm%lrlXg}S8FG4Vc*hXX5T4f2T%hb7!d7?!@JqH z{dfv0or&9fhdL(X5{j>U7A$jBAMQ`;LF3<0Na~@3$?O;5t;f@-5UMzKMY)A<4cU`l zBJ6Y4xN{HD-FSIB%z5aV43GW+G0=wUjr#-!V&WtbOzX1G;+VE~UME}eQ>hQT!D zLo{UcKR+?1bMc$B>@(n@=kNH}3I*9_wd*5HWOl`i>DGKkN~pLxJVx6xf+qlc^fRVE z+TJJQxa4MW^U_TcI#Qe?;R0jb#-DA;SXpwW4mXl#w0trLz5qR(&Yx;@%K~-Tlu}?vxS>TB4Vx$ zIAU1;heIBR>L6GQupXNJjG?-S5f^}X_H2$>6M8k@n;OZ@6C*|n}vO)Rv z_x$ADte7>#AO6tORBoXD@(mPNIQcqV%uH5rfIcKP7}vV6?-`?y0h%I#ZfQd9r)$cA zoZR^dl7*a9Hk3k)KHXFU=lD+TZw}aEdSlOLpR{+}->FTE7~JJ$>9eP=UkL%-iR}HH zFE~=eNqelgd#By%>yO50^g2%1COU_kfQct~jSZT6#w$?_M=XmzNbHwONeQI zBlw*BE&3100g~y>F@->qw_yV`WwjPm1dS~$2p;_JZ4aNLu!C4aJ4EI*i-y8JU(F_@ zpzI2j!@O!v6zn~UkMs2iVD>CyZ`u{jmw*mI7ZrB3AJOKd_fFV;1-H-?=w)ATnD~N5 zYdPOXzGK)m$!bZz(vlCBE!v7yUH@j*M;Z%&_tn6hCJ}|_)Gjikr}Dn~(}!NPK#T9f zKIIEZL)&rSCVcfb${z|YnOi+$d^kW>s^$c9wtW0rldGvvhNmO5cAb-GgLSx5a^=m& zPN~qo>hVUW4|RX=^1=`@QIwPQ(?j0ueZxneRrRq|DCNAvvN!G z3f@o_i&(A2tz2qTa`j_#pa=+DeGTsuXC7j<*U06GKv*%b!^I5m7giAHOpcx-fk4_N zlL$fZSD@b5$VxA?0U1&54;!rgu)!p2ijOHCewn0VTGStj(C4l zQe>8AR{hLt893B11Y38tysj5&NJw-X2zE1k={^>G@h|!LageX6^zPVXc5ufdKi|6R z_tOE|XhOV?MsN$v2CIdU$UTd^=?m?>D;>&xQUH?U)Kyl$FazUfSC%E!=J#9pjrYW8 zVTM6rFz-zDxAc}C2-Po5mYA?V8c|FKMtt{ILc@a6pQK-(tNhwTQhVJQ;W!tO4ki7_ zQYJh~p#+!s%Kr_MN@nkb^`SkMb%pFrr-sWZ?!~x#ifR1S2uJ6_5kuz$Hb{+ld?~_b zL^O@Sid;z=U>|j~jZu{Hhtl&pzRD%Z=hDo#Pgi8t<2rm8ll^d52q%PX>A8&0kue@m z5L-)3_s2Hw*Cmrb>W~!@EJ3@3q(4!OujV^yKTFFK+_9YP{0^?Ag%J@+`185w@3A1% zLkN>F`?SR(cLjYfEHI`3f`mZ+2TwmOK2o3ISU>%K*{Xl`rX^D`N`yd>i{#Cflt)_Y z-nHa#48Ka-<_f+?+^ny*v?POgXi9>3yxyTu`yxv0F8-pu@ypj|?;SoWai=eA)Gz-Q zS$2J!dq_SZW!1G?I^8Le%cV#mB51;xW9+JSrwYkJ`=8piee*~?oi5Ca@urQ(uZ1$^ z6 zQ(POa>S}}v#k`oOm~`a5ZXF<8z<~dc!)auR|G*eXVX~1wSj%TX(;|PI1x3DPt|CZe3sE6QDaQ&y``GGTGa7Xru z^%?)bZUB7g;FvyM$jb`UWaISaVKS>q;^GOHD1H<>3y)djunVd5HNKdNEK};FCON$@`gk{Ar8$V> zpvLb{3%H1KTUhkkWYPBl`lkSO-6w#xE+ry#(RFi!T~X=krgCN2^zU9F)>xfSY@dgL zZVZn?;P9fMp(zDsS75g#s`5cj+TL8k2GkL}h@n~BECpinDl4VUn>Ad)iD}V}LtF9{ z=vf|RKf?z7i~x&)MSX+^)uPYf=@0q^5?x(gm|!IM);l0((B%r=n7YAU#17Toh3Sl^ z2_xG^t~KlzPYGDs3)b!HV8aZc7;q#pFDG}Ss$3m=*iaB2`L;ZJJn_yvl{ardK62T` z_v4Amp7`2CLZ=dh=$t-I>YceiZxs%78sV$@JX>Na_JKb>ri@I<26BeHGW_A+8l*FR zUBM!KJo0$yDPwB%Bq@iCpG|dSRq(q?l7mX+2<-0rHZ)x6ig3);{3^MjPxa3~Z{@i% zjmD;=xGU7Ke&JGbmC1^-z`}~Wa6nmiv4dY8SL)7Yfe3#k(+{KG;52O@$7H+wR5861 zwuIgV6joF$iXidoM-CGa4s%Z+@ZJv?@K@I7Ugwpzd){xR*2M7Vuh#P!KrH0gku+!qXqGki~j2*mwj43ETP zEUX~ruv*XBu_hW}&85psYReEIhf2nbit#RKQfcocG@&72lJmOYAzkb5Ozny=biujP z7SCU9zT5UMv(KiE?B1$yo1djn_f$eEZ#izYSLxPh%13$#?KtfABKR-`-@7+&g|!)K z{!*uq7c)E0;}^ZY#x4~zz2>|us=y%zm#0F-N#f#x%-t51=wGSKUEYra(|a?%MSgGK z;TJThAdcTQ%CkN?hh<)mQs9tcF$ymU{GA9C&`{Pa%_D2*J#+t32nT03ZdL7Ljux~B z+P${KcC9lKEll7%t>M2k#(%iOeJYT^er8sm!o9tFgoZUtTo!(m?BbjehLL>;6nHFr zvcm2lEg9rcMZ3am>hDHr>V+x#%97+MZ=Dc?U8UU#!nqRLSZ63_c=z=UMDP%QwungX zj><}d*po*0jYTF4w1f8Ui|5DNXPW1szGvE5pCl9=uGq$;><>XxUW%zMjVkP1MK>yz+|8V*hi6fH?t$k zrCkyb3N=26trA=b$vY>nzrn4=I`EHK{Q29rfE0iR%j-Qy;j*--Sak*+JbH)TA(Pw{l7UU8u`9$uH7f64yGOkM!g_U#RkF0=} zi6IQrm!e1-!DHDSi&S?-+37WveDTm?;O!e^OD;RZw;6uA13i#xhD2=z+*w9s_xL|3 zfUb|I2ON}Osm7K-l{0}n(FAym(4`S(E2?e9ExzI@_Z}axSi`cx+SuF}he1K7PeUiN z5hVy;*TsV<^^sLi4UjLmfzk2it>S8%-~DwGC`DV(oxOcHj?X_@Adh{7*Ip3tq}Z`> z6P#R#T3D5I;CC7AfimUq@|D8`fJLj06_Lgo^yt7_GnEqbT~*aJO2h&%&@fpVd2-na zzcyi87j;eRQ7n!fq~9^obcue3i-wjKcwXmxu6Yjrxl8*82ahyO!>$MpuaGUe)9RNv zabgi^QUH`V0+{=2jgN?x@OQE?`008844qZk4U&+jJczzt53|ePUL-ag zlHZ@$9~74yvzlV_;za+JLUrL79SF z5|O8*m05-znW%0=ADyKhrs7DK5}YGKpNg?bx)~djk#?@CHeXe%9~WzzdHRjkJEJ7q znDU*5u*P!Xck-eLI3a#Tjnvgy*%r-l!+#SGZ&=r2YTB1ym3rx+21Z<&nqQ@Ey? zw(TwaH6VCV5Pw*Ig>$9xmi3NKhZ3oJqSLd3$B&F##8Cim+*x;BoSC*$aQ$Gd>2iM3l7tMadxhz%bav2BI$yz`ch z@Dd=?Kt(+SV3R>92x2rE9n5D&0Ec4~mYuu21JR`TB+1FShfFTPm_J$lQIAMG%LoMh z<4~vumSlP;ly#Z7gl@|4oi^ZqnRCFj~eM5WiN8z1olRFVrLZxqE0g zC^f&kfDx!Ij*>}u#o%!A*^)AE<|T_rl&z>%wtV6nQ*|p%bd1!TnK+^ZJ$*9Jr1|kt z9oHM73sTIDqqaZ!G9?otF;Y0I(giOSay^8Ja%@~Kla*;Nzu>@u)njbHb;}V%)&1I}gtbOh<)MW3 z>$RMew`yaUNe=R7<7s*J``iRCjPMl`gW@#8eHGlyf zv|Z-M>z;!}yI89G2?D1;y42yIn=4AKU(W}R{?+5*9X2E^Y1CbuSjJd;A_p^tb3P+R z6%(32(yf!@<<*}k(`m^Kl+j^ZZrS_5r4F60m@8+~%ic#-Y~g`jY1txE+e8QV3(dgn z$bve2fKxJynHd|2u3rpbOW!WT@LoaYo_>L_d#;Mu+4+^O?E6|%t)VDj=JcTO=q;QR z5zZ>#8?5C7#>W=nIR35uQ)C&jZ$8ncz9T}~;9>^P)&iQ89#c|C6mbs`W1JM$MXpEd zC;&2@L^UR8;Z0eom?Y%gZABwqu0hA@sr&Mohja8e^A_ zVJ451Zw9l@_lssQFSs>|b@y~%_F71Tx0?@}?W=-?gB%N35;XhJGS;u$09+lp$SQWW z-RSW(OSE;&mUK#25!2a?qo^rZdV-+06_qOBa)7&S%RGQlh!t&YKP2eR=#s_I(DO|P zK#jcDu~Ttz*+yR7Z(pDt{+*=3r7~D^X}e48yHiEV5^(hIy73G4SA`fju43=@D)zq} zDox+}1_bMtHo3ii7bL#=q|*PXqndy9mu}Bx6xbuJs5(MbE%RBf8M&u1oc@t2$0#7Q zW`hd6tYsHRK_`L8at{7l%uy>jCEJFSS5`IQrc__M<)8$60f&$S;)n`soe74$q+g+n zrEe&Ouu*kC|1Z;zU2Mm3HG=?BhuN_Mja>{VegGUgoFIkmfSxT79tY8b-R-!sF$d@z zJh8Ay!TLHq%n|Hx^s<>p!wFKP99{y;y%`U1?z)N($t6q73`k`<&0Jx%|4snQVqz0# zP$JmAbmkt8*kZ2hc7V6c9gB6zJ;7ALvH$h}HJ+vKSe4qgUp6X^Zot{!2#@yRTE_iCt`7g6+tx(-fEa&0f(X@1t|j(#@>Yr={a(;<6bW_N)(SO{f&gYsjmPC|9w zAmB$Cvvxb*6nzs#Bb3KFuqmZQjF8$#rIbRs?^ibQ$qwFGWa@RX`6BYhi%mrI7OO-P zCW3CQscr${ukq7^!duKh*glfOkAkz45fT8vQs5b<#f#-#VAOlV=3 zkUEgG&xWpG4As~!+nbATArA~B-U&*aA!n%@ntSf7k-diRahM2#k_8apfApAkj5gjw zjumZHi>pz#Ac6@_Xlwl*1X11R5B7N zPB^1}PYS7IgscHm!^Y}fO|kheI-6;|>i0b@Iu(5{)CnJlO2%z5^d)i(5jC zuy*5|tXD;6yeiP=zggUbC}%fH;@hPS$0e68=11H9^oH{#kDNn^_7*4|E->iUh=j3U zCXHJK&(N3q=Q)KQAb#zP!d;_kD(tl3oLT!x0xC7|5M8qI|2Irlp~vpRkL@CYWZr7q zatrq*L#(Mi*Mv9iH;9I&!U~QF!C`iEzEhpB?V3MjBcf3@a%@;pq`usO2zVAn^PmyT z2h_9<3TUGh%c-#c;Gmc~PYfX|&C0gK!b$7tookw^bvZ%N#dgl#&#j6t9^el4wL!}7 z1j|r=d8pRrEw~YCuO_fG_vi4+@*i1NM#{@xgOt9-tmwVF7+r!gtLSM;QpY0L_K!^Q znOGIF5D^&hYcsx;e7(N8(W{u4b>i8T@Q?;C0<{1r&kZk(kEkE{ zF*twLON%m0W=EHN`=j7qH`Ul#mSx1aQrDSQ`3719Y5Sila};dTex!Ejwf{5hjlt zi)bD9Kb5_eo%}39Y6bv)cmRpc3w(q=EJ!L`1JyfNSKRhA8@K0STpSrsptA?y6D^Wf+_%#wU!r!?I9zTVgHB82TT z#pzqjk8%Fc(yY;{^{;rP-b)NNIaiZ|wOB&dkjxl&hu`v-x7Q9l=s{!fu3g9qQPW(Y z)^yevT;sG?2Lpdo2lZf?FYN~O^rKq5v?0eJv5kooAo@zsBo#?`i{|WPthdC~`LV2O zaVgMb5}Uveg$*Fvt80cUV&H?I z9>4arqtQ-oV_hLBCcQP(UX1lp|D4MI(CX>u=F{qCAi0nR!e6|PZu(75mDrlBeC)gm zd?T6Ki%D=xtbt9EfkWE*%H@9VGa2E8YgLdIsnWjw#`1Wu8Y~*}3yXD$3cBw&M|l&a zW-_+d$FUj2EmI@oPWsLA-wSr1lA6OOR=6!0?!RR{27>|)*@|YisQYCQxbg^nlrK}v zNs3WFofMYU`lF)M@s!m6e{d00>0!S3?Dr*2Xfs`(+yY+iQyrg_)!RK88M!1BNN5a+&J`uA& za=rWyE+^64crFw=LDgdv(qt!!hDpMM^v+2-l2;NOWV8NEQF4!+xWM7-g<<9KS&8<_ zC)3U<4)hR#a0v&e?I;6^rMVH;NfMd(gC%oe6y%6p;9?O6<2)UiBAh*vsr&X^UR}s1 zrF;^3*4;gFq}-cPiZSqARf;4FDFu9#On}w|+8K3Cn_fEM%rvCy*JA=4%4EfW?B~oD zc15TG)kCvwLK2biH@;@%cjU#g+)3Ptv?LloaXg9X_)qzpOta)JWgqU-G}roMjqrQ3 z*IopzUo+RV5J?8%_`jitll&TtllFK28IoC2>_N;}o`VzVZD)X#2yM)Z^7iT=cc=GF z(c$ZUOVyt!@QcD+FoudQ|!) zcwtzW*I?UK^?KQ=kt*MVv(jPlE1&js_^=(cA+F@-&D-#p!8gq#ZR-k(3-1_rz5d+a zC!E|w*pY|#NBlZ*+Z;CUXNZXdHXl64T@uCNi4#mPW>(mY%a7Ncfhw;kyz`rXqQCi7 zK<9&1vs3gGZNo~NZ{9o*Y8LaHxBsVwzbFR@k2k@wTj0nBKhP~t)*^}F3lGJ!02dKc zM|PJVZStbmVB8MBZRyCbBG=%r6U&6=EW}G}yj?)B_WgthHW-jB=KMBzq(T*12r)4_ zqJK6>6NQn@wQ(1EVP(n>TZM+1Qh}^@x365qFaDK&z{23oLcNx*j+xI|I;#hp+|_jw z4R$R7r60+RfGpfJxpT1~$PhO1?sn3?d3%(I@quH=6azQ_vcGRPY!3dwrAo8Q+H+~w z!l#ObKhZ)AZ(oqK#v&V|Y3DS@1v^TGiW>`2td8|JA2mp#&)nSfFpQ((*EFcE_5-4c zMYF$!LrEj*0Yol|F|@Zv1Jta5Ji@QHrX*RrVNw$yteekuvEUzPw>`x{Azhm4eBqQH6PiCZS!*3EsFckUAURx2QJN+N znVI=fuFYe6`^KLrJS2+Td(0Z0j#t;-m>OSgW(I+XKdReM8&fHFT?B2t3{*TOfAL{pBe-8%|73RFgkeev$w zuTh~mqG&tf9%cq5!3X%CHT>4mteFS%zaix}iyB13lH7y(+_H=@1I!45Nia5o5t<=|6LSMDqq=okvNjaa%#=&3#W`ctI!Gy!tr=!~08d8i_Rp+#lJsvuX8?3~!X>aRO<7g!Osl_&A_s04ngc z0JUo2v{nk{2K@xHt)sb>K;r3}L?Ew{!FZf%&x)%Ty5pXDkSbP7g-s{?r-ka8s+s5$ z7Y@dD)8Vn=Ko$(n^o!3zf1>ZHeRHI+2|*iCIbW2I_VMiRhFIb3Hg7;3SYbfISyJ*) zo7M2Z2%*q3#0FMFA#E?;1+r0^iD99h(>JKK*!LkFtFv}c99k*BH`LwuYxzwO4t^Kd z`yv`!Qo(%3hVd0WA_10w1@>FOy^M+v9u&=U>6S@kduT9L^esVL@Mp?o_v~SbkiSvxh8^q|A9BnPmJ&050CdaEUx;^ zmaUj~*FM}HsN4pb8X*t74YK5u=rUsVxZ%K5s|ut_SIX<)SgH1F+BS+Jn4Cbt?(qe% z+{ouzuHJpdxSye6RbnkAJc~W=*v`NG1f2Kabvc%C_ zQ>n9kdWkT227+@Qn;+3tyJQI<0v;mJHyl`jVNFzBzJ~BH_urY|vS?jE0c-_ux~+5qBe%Z;=4Bb zT_FMf-~1_ruPkZ%o8x1>kP;D_k)@c}o0t@{E4bt?(%nUMsL~gf&0MAxqDVW;!lk~S z_AhEghKyMr#w4RY5dNqgW)xE^zW+n9-+#dU0dGGIMTC=U`*(tzMqVmH7^|#!&my^) zgJpDI=i?h0Q<8DKdMDnuA=}|;h-nJT9Ei0X)Uf$veMF^S;t zAnUWHmEv_42joLS*12jSuMih59yG?#7*R7?apJU2S5&_1rT3{mA<`jd3~T;NJ)soQ zlwk)N(fbfW#3m0lvk0wUPBdyY%!YE|bu<&5GI*hIKsiiA>eLc^*RY_av&0cC5D_6f zS@dd&xVd!7CA)2j4Y{1<61@zSDVy3i`*7Z)InIt?{m*^Hg=e9@%L@`ZefJy|cXoUW z6}!wx9FP|%xLE^GUrcQKFb~BKUu%V>xT)r z#9WJ%tr){Jet#{QJz~@5ru4+e(RldR=HNm`5&9uSs6^vJ=83I;#bDu(A~jG}gDsx) zHt%RRa_HBi25Btb{>`&N7-#e_v++S#`>o){<|eR>%-v#dI_D_JztEP!9>iRqyH}U$ zAnhx6j)#4$Es3KUbr*O?`j;_;0%O?_Fy*8(n3Rhv`4&AZs1XYB&o;^e&&?AfexnA@ zD0)EcL1??PI{i=_Uz?oQ$xhEmIBP!l5LrcVO^H4FwjD4cpZmp9z;9wbWlizDI_)I^ znr)H_be4U4Lx}7iUV{@~3mU6e7DoZ2O z=|Pruh^)gpN=pmqWM`>)Z2Lo2Ep-7fJf@W3HA75xB0wCJ>+&VBV0D zmW6QHVOi+troxf2S&{{=o%!m}7gi>Ych9Tn{eEBNTw0`Tv`6*2z=a)LlHY={*tV;(7>bj+oX}QfFP`Bw=UU$OqkefFJ=7?5j?= z(v501jf6c0_9}mfoO7fB0Uvq*d5z!;(bD{45rR z0sMI8@4Qp`G4G+MO3}AhC`*{b)de~Q2 z>dWC-3F66`MP=D*)3p#26Bqi36&Igh-($E67yiN=CBrh0b=&O4kJi;^(UQ=_n4dg^ z5Q!6Y#AYj_pHSVGjq#=Enb?r27}t78Q8mO#nx+%8C1zmzuPSK%*dBd!qZEOc7jhmI z1D(JV`(S=aYIDX5lG_nrgBMu#Yks4MB)z7bGbHhLq+83IBi*D1#@+_DQb=2m7+195 zLV8+%)ueW)CNUCoV9iNWxok5xI^-f*SRUti;2&T-UyEznlwU-1q=FBvF_oP<*(7x=d=BcCcJ~eL7ir9G(`*{DAH8!j2?Bff^!Eo)(*B zeZ$IAH4N|k1%=YO)10z4>O&!(@MhYPDt;+6Dt2suN6NO02uWU>_}slDEq{Age7s;9 zUzX7EZfzKSpn+|l_pw9HDloMweaUHLD#q+2 z?oNZ+({mBd=F-stJKViIn9;WR&O?E?$jW6F)1&y8g{}G>n`hV5H=Hd-6$D&bDqb-= z>OCISBW;NY8s%T7FKPbyOO(@=&^ntsiMW`ZneB3Eh(q)Rh^=*5Wm!30IKya>>&)86 zN-B+??%GokOflU|PELz=SWDr!cg&m^pe)tyM6v+(qRwBeDMqX@jl-?KgeFBK0oN{nUry8)J!Be75ho=2d@?1N=F`>os4gS|+NHi3{!eRcB$PUL7ALt5F3CnaFEAa_#4`k#r0) zYzw{xiKV%l(mR$XsaPCcF}7TcHas3+7pHLlLN?uPU+@(TQV zD+~t`=VB*Y!Eza%xc*>g_v&TYrv@vw1O)R{NYYC~Fyqe5==uc&j0#OHpB?p{ue$ZY zr>9clc`Uz(+B1tNhc)uFd~Y7zdVDNevr}f0m^zxFVSItLnvME4+aZqLGT&hj`GX<< zEOcw)aAxhKWi+H+HNV1Bg}*rP<;!!KSqnZ7BwwT`wG1p>)~fIRw0dX%=jeJ*wwK8L zN72r!x%j7~6ep?`u>3l7fUg|vJv0;)F1!0rCNRN-zp&;GKDeu==wHdM)C?vsle*W6 zcZ^OPeZ;OK^#tO#nAN}Tt)KzreSpk!=&D>Uqbls~@wK+Z?CINdGUpAiQL^jc)bfh7 z>yRFXnHP6t?q4h*?-Yo0S*dVX#STG_TU3g&YQeDh9oR>#zI0rPEjUQ2=CZ_cf}0kP zD!H3)g5LsE3U`r_&KfbA@xxU5eiKYE>=uK}6lhIzO*}cppfxhC<)6mPZ&MWY=3AUS z@Gdm2`1&LfUzumr|C2PpM^h|Dn;=4=dHGl+B7+~P7AH$>Xq^6DSb*8^o zhw&3hEE!@mJ5`t>eqS>M0W1*10+B|dq*>-9WQr$~v&c8T5?-A9J zVzjfNqe7bURgO=A?xk+XB!5G0x<}6(g^Kt`$I|}BYM+WlNA?Y(tOqtYU_O=^cpma6e>lTRY+|ZnMxR>%kwEeNL7mi7Yhdy!QQ^U z-N%O%F1xe{uv#AN291LqoB6SyVP~NaDNNeu4-ZLBOuml|vJ5jAX45abdmh7DL0Hln zN>ZGs0+@dwqf^c`q59%yPi(W%A3F(AvP!&eRfZjy)zM#HRfjk{pkNK3hQt~r?DW+Q z{5?f&5~?gJ5`kf=6#2T2v0G%6ouL3*KsguacQAZe@g@GL?91l)zq39YC*AQz`8wlu6NW4D@1Oy^QdWIQ6 zA??^QT72e;Noe90;+q`G&f>-`NYqmMzvSp=zO575P1~QAb3W3EloQuq*Hh{b-@dmq zKZggoalV+TBaX$``uY-bS@V~;ACee&A%+$2|DT491TFHW$S^1H7-B+(`LMz&JDx-O z-aDDlDUA!`L0IV++Nm^H4tUA}A#r;Nl81VGJM^r;>#V;*-F4+aDKa!kHY{OsNE?tO?g-!1BYjX zTZR8y8) zlVC$6l~TO9BqTOZ=`>?Ixu`U$gyMqGySQ^sbwM$5P~F_XL%Zk+QQ4ROcCg1vkiMVz zPSH5(#V-MW6;=0^pF^>vytpf4>AYqt?AgfjA`xxDM01qHktL@5+TKa1{zM*>>GQR0 zR{BXH!zzMAkuW@5s$LoSZmBPmCY`iTAt|lu)M-QtD|lH<4v@8dG7|co>Qf(O4|rqJ z@-{9$<6nNd$dZ^W0c1QATJt^D2`?F>IBJEx_k8#lXBjx&d;0HQD%`E%Vx%P9(XX3i z=;1k?wq>^|#7-l*DBOwdwO-67nQqq!E!atw{1fmZ!tp=|OHhi4&Tqu{uEgo-rD%x; z?DB(@*}v}I6=-L;Fvzep;YZ)DAtkABTy#E|dkb&%D9otkur#1!mI`T?CDZ%9E@x#j zW$v}F6J#7Qr~6S%`YYz;8#L_&ODeyHVL94kr=89AR<(TOV{IOFCIl&)g=`69`J$rX z7`LV6d|Xu0=D8#x)mzFzE>VsS15ty!$dj4YuQ6#;8@e}*EUxj+(BF(-#^{tUW^PIQ zOa9$iFsyWo+nT#h?Y4!&HX>km^LV2C9DS*0xR|yWGGg+(Gn%{CFU}!&Ehg&AaU`_g z?e=ZAJ$tuqH=kloZV))FCC-4=B!ZvBNkga9OXp7wOg%x1kw^>&3tue*2`!8;-Eq?^ ztGJ3CL=>3b;DhJ5^QP5PyA~Y_Pb{J>$4b3ytkCmtcn0$&hCAYaLjY9> zVqnR;t4z@zD2lpehO0ge@k56*C05Dru4ST!(+ep2*(dq1)E2N}A8FL{%QN^8nbDK1 ztoXsL8glBZpt$SjUqDsqgn=CCU)m6Fz?pKBW2a)6<(MxCCTuX~orix7wZYEz8CdQUEK-jLEsly$Cq1O1GCuq<-JC!Tu_y$W~&EPx}8++ zF{kFROOZp8;7(BJ~`WB zmOX*LKpF;wH17ZefHKpW%~xKP;`Iv%kuN?x>a@6PN_W-@%NVl4Jp<==kCk)8m=zF; zmhW3=ZPKLdKqAc^a1d{{(orm=OW4U$yA7oHy&$;Ie%5%6XE_&RC{ z)B|;Grd0uBYK7Q&!x;D-dGs{!Yf@20OYs7E{=jaSZNOz{R#wT?bs~n_qeZwi+u@9l zPc4#AW+=Y=z`vUdGqF*K*cA>@^nv31{vI7XLKnZpTBc9A4A+6BN>U`xCD=5(#nER_ zFlK)9FXqQ)JT~3&7M>BzZyOPt9f>fZXE>fv*n(*4@5iV(SEf7Ubtppj{9_b*Vi!~# z)BZ=kq_nsDJ`{vrZSICXgg&IIWg-Ed2t_2FvQz8lk0a>tP>t(*cPXhOv!&H{-WeXl zJ+5=Oh}LjPZ7%xy5*{@Z5!F2Ca7Z!1u35M`0^z$CuyJHRdohPHqQ|DgcnVBzs(mNx z1wqZ(VuB?uXD9zpt>54?f?gL5ZTJ7vtS=UdHN+~&u^Z`h*(UyVSsF(c5H~0YhlX$B zvQx97q#_G_;S_MeQV=)Qu*Ih#ufE--F~88H6Bn}GVZd(eY9-va^jf>Dlt4&3O~57( ztAqGG7Z!20u;ri0xDwLTt$~^TH}4LmaTP!19xFbu#Stf=U=h{KH|RAKVnud4*w>E{ zhsCnpe1iGrJ2nf@=~olMpmpl6CeL{^nLE>L%-?Ir= zM&y$QNr`QtC!8{nK0#-OuLrE zjGLf~H$gQ{nugPyN01LovG+1D0}I61*k@}*WXm2YL$gMLt}7BOn?Dc$!*bGEYX(kU z2hu17(g*^N@F4XfiixIL?DCOI5EG|JOlp4I(>I{9o8SO!9#cKQmD$}H4|imhR(Ek$cl@;zjXqKH4Gs zLSAZG29Ki5VLu#gD2m=u3?<4PknS8st0D0s>Gmr3W;BwdL@-r>SNsZ`nAod*Etmm z_)exEU{Z@+?HS9!3jmNwm6bUN4WBuKLj0BSB!(8Q(4)oP8W5KA?ygEgl?@HWXj1O>CwRdzz96s@ z&_#Dgyuo|-c)RJ|w~4&}#@)FN+~J0ncY~h7Y0oz2w5eHSZ3~3r{)_g-3&nd6=MWf#d z=@Tq+4UNcgQc4#rf>0)+MOV4)8~2KWEKt87b-R0h3Vp)FV*qzb zq>&AJUJjvl607*ThhsueAg)mAda&)SV7{aW;`IU*Py|=UV2LEePtN%}ud$Q)c-4|) z42iC3by1~yWNe`JSi!Nvv((Jvf(EhFP33TKd;U-7v(pP$C9h-|J;)XPeuC`@9a8Fg zT|ih!+9-b*J-4~4jwIZ}#h9DpDrMpKjtw_3PwNP_&YL8Hax*r?)cYnL#}7xBu^~V2 zypHFOQ#s0c_m0s;z1NjF1EiAaYc-QC?V3JOZ6sI)Yk{hzhG z@j_uOoz33g_rA~LmRSbj80FM`WYj`t)O7zZ`9bHGs_k*Ge?)V9QE#=%@(&xa_h&9_ zbTU);j8kmlbjA(6F>$eU8ub+58(>HR^95|#4|?EV&`Gu@ca02)g@b9l-095U%XIfx z9QjJI^Rj4@m&8RRqv{5h!@9UnYA6ja>no0K&p7;1v3yKz=>mRKQ#%)X$ub`ApK`Zy z^a&AtJA95MY>FNEUx(D9NhOsM_Lq28y6AvThdo5!^vlb?DLZdr(x)cc9V(pD^6rak z!96zb9P=c@BLjJI$h~M!Y&Gd^2Ro~07hVcB677Us%{=Va&= z^u{!<23t~ZJ4#0NA|E+cId~#k(?EaizqH*VAEu^pki}vK>7ZKBq-Fz&ToN9%K4h3c<9 zR*?A*3wO<*#s29)1r3-_805cwz5lXwX-#0fj26douu%B;3UAH%jcE!8kAzKagYj*D zo5y985{pZw?Rj35l3Mj$J@n|adRH-vu-eKYg_Dce6r-x9&6ch?3SthN-WlIo_$LOv zLY6^&2)r`my~?__4i30c;Cb;yii=GE$?b2cf!?1E3w7P{lidK>N;S)8r2xq;2kxZC zJ!|KuPJV~}cLk|Z((^jV*npOSWAFY>A(-7efV*JCQ#4Jj-{7$CZ^JM(EMN|poItC3 z2h|!(3vS(nza}guBv@eFowbapm)E~k5WraThgeBc!zy&l{H(%MC%qSB8h z&7E3y;%)X)IEa7_BIpz4^df%eg{Q!J!1P|RT%6$9>8a>-A$Lm`WR@76%4joI%sY*KzVdigSb$8Kx_KCj27+hUpa^G=SH>7CS0n<)>onGL#Di%WFKjSlGz*A z11ew3NCnD0Mr31|jbVPD`FlanV=BpWQZ;lptr=H`wK#!kr|(40jMm<*vPw)0_p^xQ zP)E%-*58tzq4gY^mDXEpG^Q!Ty#S5$+I^@t*CKB%E#nAoe$Opv7D2oRX#Mln{iOR$ z^%fBeCQ)i=bszu4pbjY3@f--Zul-gP?R^zhLroex&era1nzpjqB%6}LLxjpbz zoH<3f6uv@J+Aw zGbbW3?ezFwLB81|B{~apuQ~0k*rcq6`@zDd_;GBCeooOJuP+fZg058XVb(xRj4k=? zN8jka{gDa^I_fBe;s;I)mIN~ zbVF`&>5;2o8pTyvQYY7c^!zsW)Z6rFqkDvnJw^Z`ulX4dK4z)7vHrO<1^AG?SuH*c zEOY+jOM{JfYN^oG3p6-TAeicRK6|&|A`BLne1_jKm04m0wM7HiUD4ekWU>tZMo-az zAWlFV3J8KZ;6*t6uK!(NU_=_an_%6nd!YKV?_LZlKps}VhTtuU&`oXR2O`a}2#?nvGpUl4UqM7yK|98U(@E14BGUglKNc@wX&OL_QHEmk45ww*(GPY)qfhxE^~4C_gdQa7Qcm>&fcCQ+rF-vic|0=?WdC9atCc z|Iq(*tsJ`tr8x(6euK6c}_h+7BWRvMsRx{{jcrcB@R~a}w z=;j}xmWy8x*e7A9W1T<;UnR2++=I|zIP4QhZy|m5%PStmz%ZziC)eC6*4z2$?V9EhRG%y)P zih+pw04!1ClmJgLuw#I3J|fdUN|&rNe+G=v-n6aE{y2m&U6@cwn}YojD~1{?Gcoqy z=>BV(T!ZqasAr<8AdUoG4l~P)bV!7CXvc3^*)!^=X{7c;1mL_Plc6W&m4Dx zrRWROye!CsT(nm|>}>Ru!av6j_`Tl5xNHRc;br(aXH52$i@QKXL$+2z&TnpY1!W?A^e`p z!(5YpJq_c@6I5%sZz?tH0}+gY$Y6ZU*Tb`G)w3gmQul|cAM$ljY?I;uvC1TThGY-0BIOyNJn zW;&wus{nnekDsaeqj86p1ZB`v;)TmNhItjmX5-MtBUbtO{9XTHUIEWx5&XW}nujZe z2cPeF=EvE0w57{L#mQtlo3rfk@Wz*xFo7l6BioYm_g3#Fhf{}*F#;~DS~1ye8;TS& zcRUyR)n8gSBhGctwyBd_zkhLePUAMBD|Y+xUOk#3LJ1?plH~Bu*CQ0{1UoxxO7&s* zykE)z|4WluyDCWm;RICIeL5RPsm}tO;qAEW?9FGAq-QP?%ye6Lf$PR6R}|2EIns7M1goA7Lzm{!6W-ke^fz5k4%DUo*e&o2aXZy8UH zYLE{dLxRG9Y<9<|^yPgyg-EnxEs8Fg+8eGoG18^cn_l{-^v9c-HK#lfl;1+6JUVBt zy<++_!>9w_UcJhUHN;TOcNVN6Hwy?)wEKCaxc_tWSEBS-+Ze{A=DjjPi!JCN4wB1_$A+W%jC56UT~94y_Um6 zR>}WNapH;Y^M!XqR4*cyIL!A(sN1X*FH5vOg&a2=m!mx!vpZf^n04spR3?stRshqz zYZ9&dRN&CWS>zY4>I9Nl82MP-yuEwf2|c$37gRyq_4CDLOvt6j<@Lx@&_`ZAkAD*G zB=NdX%z?o(t;}R+J9Te(KR(u`*TmX&v^>8IS1a-v$>35O2B4YWlwSb9i7YIVnoyA~ zM22I7@`c!tvhFg9h?#jNCQ_{5Btbu4e$x{M==}jH)U!agJ&g~ev+!n(0SK{%!wzdDN#q@Z%`>f9>_+K=Q*%m0SE*s?x- zOxYeCWV{P)Z&nf91BI4zU!@HV?6#kWiuMtPvCjtnn>k7=@nF?FeiAis%uy3oO$Vgl z!$-o`-6Q3T`Z%m>$u%L03Cmw*i4C+^XH0(UldHUFG`{t(@`C*q(qpe)lmQBMoxICC zqRq(Uo`Bp{LEr|S5#&Z8bzf#9_qd`#o96&tL?AWlSQ$0cHPRV?950-WEs*WXBYxD> z=RO+q&mrw|TwTI=BMI)A0P$(449~N&w65wq59mAgi(J@{v#>XzI_Xph3FgdMItNO{ zzQ)PyEZPxd+|VD{&FyW>E}hrGS0|VQv&Dxpx7&*$n3x6bGP!ynEdi9{2Ry7;U z(o7HvX0XLwm zSy@-Ap+pTmX^ME&*>iD&jvC{m8ta|PJ7^a~gT-M)Jb8-PS?V2)>;Rb)5|Fv4x>#n! zJ|$U1E5@jd;~BTPO+`5RUBllA6s`O5e1r1+zRa=|1Fq?%%x z$uy=AY*GOuTHevCVxb>IuHa&(sFHG~+k0`U@k~^1#&jOPQ5>P!L^SMPB(K!EJuBI- zD?+cu-%s5`mQe_cQN5Os{#l)omc;LdN|0)-tM+)(km7GJ*!wPB=7%>6;IAe-Sd5L` zXcDwg>d}#{v8sAwB-lV+e&}MzIf!0Soq^|ND9_bmz-Nk9HR#y(87Nd>+=aBZA!QhE zblmWq9vMA_(x*Z0zdS2$ynI3u{w}=RzbLkkPXaT1Esa=^Dl*k_(NMTjRY{5drJhvv zZqr4c>1oM?0RgFm%wR8(+@NAu_EN5_vu^Q_x*1QD7n5)m#eiqJE*|#Pr8kYu`i>1? zx|mBnM-yACRLRp~OXIe%wuGIVX3?sQTpAuyBS3=K0a_(|w$!}PFAGuPvFjvfyPY=W znEz3yL`v+{z}n?z`-N*MJ@DSkO7<^dbrUuwdgY6ZqSJ{5xEuQw@!W5&TRWd>CXM=$G{<9GAs;Hk)1sND$c z4oD8Uyy+QvIPAH9O2A&#$OapJ_Vi>v5l08Xb!U6clQ)+TQiv8FJ*OlN!7T@X(&D;eeI49$a0IqDauWi2C6+ic# zT6<3AhKbRkFU91x)Q-R7qqH*TXYDU8Y3%8wQ?I!j`EKE?&*||bPG#TvYzZfdMu#a; zPt>mkwau2Ydx7KbP$3vh*&CQW6kuOtN#jIe`KxtMQNZE>H{9#y|F~}?VK&(&qtsH$ zIL^ydZxni^)yxD>*;bI)h|@@@KDgjgWhK96&{qe)5Cfs7S7@bTzbeA1I^YLTqQIr4 zL?k>?tdQm_?3&i9<~4Wq`?x_SIy>8#M+GLae2V^zIghj%u)U|l@h$S?oq9;1{Z z_-0w*)!mfn{lAuw@MImSI}lOjm`d4^T529b9>?Cjm;sL`nqkt_o{*>oH!U89%0i0S zbH=>9(Kzml55aq@-686+2wLLLBg@P5jSGM`42@pS)T~ifFkPTDa{xh5 z8j`Y1dS_qrFioS?(#mMK@VJp2th_(ZbE#DScKURw;3zd>$tCpqXW~*W61y~#m$@jV zQsb;_2A8`gOW++S^R-qV0$s)d&Qv>^@@Mhk-cnrO8-U2`jqQE7JcEx9)GKP&E{f@9 z?~v}cysrE_GI5&lP3eT7Z06uLN5O|JIZxr|{JZPCY^O*D(kl%{zid6sCS zC-K3Xr!XbHf{N!ZBCvPvIam$$bVB>@B9JNFHY07=*0vLtj&WU2$z@s!?6qGXQq$IQB0D^~}@s>nV$H6NG^CS>8 z@T7%EF>JG(CvW7diafO5z2U>TTy5^-G1yZbLrfObQuYD3gMP#2jb)v!xM>1t zN!+9YY+j9wgmc|1kGi_tfviJ?CwDRG$DCKH`0!#^HU7>!_ST^qk)H*twy~DseqxKG z#VO0bJvc50UdEF|slPy66?hD4tkbsowp^(5=rI_#Wj^ktCa!Ll_)+5M0_kWTXom`g z*GBIZVp2A2Y>!{i?{zR)AlC%y%3QSa=e_7^1MnIVIxr1Xw)u2No)5a_YtQd&X`cZv{pV3HlW9JeLH#^fx{xbxwg~Fj8zY zxWkSn03}reakNq%#~a`pC*RHyc7ck72Mdz`9G(^}g(?xV2Jtw@{A&s&D~m%R0-dqI zfT9*?IjZrX?wODU)yx-}O`xhe4{}(~l~#J>5j6EO5t8(^v2{MDr>5FdIxPf7gf6fv z`u9S{76G(VV9z|BHcc&2N3c^%b*fb|`W?fp5$mm3Eo(~BHs_Krow|u@YMJ-&5o<3* z*4%BuKlO+u(Vs3=x;rlzY_5bQWOT{A-MO1>bUNrqn0oH7o&0!e58BmmP*pW+><;Ay zIMVxNbsOt-_D%{pexCdG%-wtgZ104Mib4*S!itaOal&kxk5+n4EJ1eJl~5o{G>!0y zBp`&%)K1&Hjvw z&Wq0^UIA=`gQoLg01m+=z+_oe)CEsw)>CJTV-;Z(z_>k`$R|+-R+-E5MTO0)ZCXHt zbjew3RVZjfKD*f81~niiLIBt^4M-+F)im4vmFZp;l6Y;al{bLKX*n%C4$7glHkey*Lxp5-eK z`Yq0@y{yxyy>5zSfX^_wi$C}i&9Qy9eH%Os7Ws|BV8QQqcZRDu9;cb(ND-EomtulH z7;0fLKohYOtZteKlglpd!$v% z@pkk^bzb*Ki9AW+d1?_Cvxyi@Rq19?lqrd8+Y{KkzMGL*aW(1Z&Z@b;`W_=fMRle> z9WeeXvR6(I_f(H;K;V>JXeu!rLEO49$WnU7BOZ;@(FG?gtK%>a*(1{XUAz1l@w1HF z`U_C1N=ziQ%$YExl7bp)DbY?|A-L{qL+tugQ#Erqwj{ZEa%~C^&_D4iQQQs3rks?s zDXWf(@9J(bN1>={L65G?Og=trWwO?YkHVy{aqx>|5@NTTmETvRKp($h(dzOkK&3BL zl6_6-LV>c+C0y&5#9~%M=)z)FJydMH+^?4&%OlQc(1_t^a*$%eHs2>|?~qC0Uo3X} zYc6@qZ=MP<>8T;yUd?By$5X-LTpnWHLMab5QL%UIEUJnyY9t;{U|7&x{6izd#P+_b zN+{a46<@}na1Q631->*RB$7TVJYuMfYr>wX+6%@sRu|w8&~Px4s+=&<$c4(aH4zsv0r2U{m~w&YVQ~}>rziCy4tbc zz032aKUVaF5#B=Y9>+=^8yf`9s0F<`G|+-Fa#q@(GkNSv-rgwyJI}*qG)Lh^APtvU z3htCPUlerAaGNuo#UPIT3HNX;;FH_eyyL?9=5}EBZYL(zmquOZG#q(~@B5X=jQ+7t z6bEO^ohPiQg7@qVvE4_E)f}zT&@$GnS#07`G2e5dC>C`sWRrc4)9=r8`IbG_rd0n; z>VUp_6Sn5tV`Hgi@2>|p|LCTbgRN1VPJ@mvRHcm?`{nJ?{UZwWXV_8hXFTaba0*Jf zbX0@LZCac!ulXy*;egzGBPaF4ea0nz0XPc*v|U!)E5L)!#C2Ajuq^K5^HpS8Ri!JI zCM?O>Qy9(l4ox-fJ47mukqI{io+% zbiiEUV7X-4 z&;*{T5Igac6?O^}dMc)I;Cvprx+DD50AoyYrZ?kbBEkmQ*>O6sV^io(`+S#W6+AS1 zu86QD^xH{a!1lhNiUEOHDX^4sQG31yh6QilC>ief$@KKKVXTNo-+;}QwrC`Ym+bE_ zn$epYKAlYrJ25TNcxflF+t1^{4{@@jGQflNbQLmV!H%sgvuMHKy`kig)|Gi}Q!FWz zO#dZh@-#f42aJKquahX!HrGQ<_vrldin=5L(^tz-LqT8k?-b!3OqmBOfB^lX)WNcL z{PbC7)J6G%w-lLyub_mOeiRk$Hs-~Tb$@Rox68CMloJot}HY75cd==o`2`}!lv)DO!pkO9=*+y1*kcVH#hG7o6M4kKr%G)!Tb$txYrO$Es^CZn=y$AAUx zC*|Z-O*)h2H;Ec$9@Mq}@Llr-X2V4oVJ?e|JQnHbTpx!nWJ$Xj_Q>g*BCQdG&6#|} z2c1UA@jJ=Ub%~3XBp#_wI_I6TWQj>!vg7JoJyPXJ5h!FYP3a!2z91*LQ|Xbzpn6+) zI2#vh6R00kr?T1-+fONJE8Sx#Ixj|f|1uhCr-8`8P&{ZAme!upWZ!#OU~utzq4a}` z#|_eGkd1OApAwjgd1g#{`Z-0}6rXo$`4OJ;9SK~PNmrY-S|ZYnF2((M!xIkS7fCR; z=whA3bc5u637gdZTcuZM<@Rnw-<|!}rCdqFQ8vo?A&4a|Nmh`!eCS=QS!J4OJCxyS z8&aeU#HpuEu!}bzp<&xe-P1G7gp89RMaXG&9s!5Trhdg0i^^1TMJqLx6%E@I_cL85oQ04Pr>bSn+qIHME_u*cgDoAfph@HuO6Z=}k{;YJEzmuF5@*9u(8&5m z8TBb{yc7eGiJjuIZ|q#Li_GLf{AS#c<{8uC1f^!4GSAvcumgja#duLFK!;Z7s%zR{y;A3l5GV zCUsx!$4;)OL^;O64&4bJLGE)rE~OOk0u94~Z>$rv<(-v$Isb@UhZZQmL=vE@7|ufn zwqFjPB1J7NErE}h`A8VVIw=o#Ut=5|?+S+W-vwj$rqmuPbQf2<0=zwlw%cTsj00=Y zDl^BYmnk=+>%LuHw}O8y^DPx7Xz9N}3D8euM@}a|>D4*448toC1&j@ZYrt<;Qn_${ zKCe`H)xpljHlg_`r#x;-+r$R`&=~LN$e<=sKYa501pikB+~VsGNzS+z=OAX=e?w`p zT;xtiv;KM2Lvm7-oZ)HD#!IOIx(G4-IUoM(Y83*~%}ENmqGb$*0!3=9h|WqIdZih{I%zn&&rh1^kE1z)ND-6r16r74~z|DNvZv>r818s}pW1WPio?!1;o zP9r&!G~*89%emt*I;z36H0XDOnyY1t>`3P{0K9ZmkjV$Z)3|aw<1-7HaTwr2jTos; zfjA|kLn!vRJSn-8ItDq5RQ+!yqL&(>y21$bx!(`_hxd0@alI+YTBrpa2dcrmrAqIn zcanKCpXFpa!Wk%wh)pu%%)hgkE8}8(!}DZQf`=5cA;dw(0bImEE`-g=j8YkH?!u0R zp_I+CZ^5<_9^m<@Wg{+GaR{VXOJYWrh)4y~z`Xxy}AVe?^$op{{^@ zdUe>{u~6qgc$WeBr7=nrn%N}LD^aunMKOVbns+=p=KTx)ex53^Gh>2Ln2pM05e1X+ z9@Fx-ug-;xqg=J5=f`W0u?r!!Ldpmo`P0S`5u@1`5D^a%U$v8I@e@Sx z4~Xh_unXG7J(!Fh;4~`HzKolr`=pyQHb9cf?rr#VJwO zn;wdZP_iXT&TzcW1#@iZFe@QlN!Zc?=^?TTB?)K4E^*|hcXiB1&$X|Wa>3~KMTq54 zJW227YZ|ZcKK*skEqwf*m7_cl`hb%5!NM-dRx1z0LPoSwg2pRTDhk!8nS6x-PF!PV z64rj}keq}(_o!k!Z!`SijQ2l!c!YeK-0#gYh=APW)3TBf>IY*e|d|{_mY+C z(>l)Im8$0$lGWSmAY#2H_UxU*^2*`<7KyV#C+n!ctb$U@madJ&hy{$?kt!F|I2ws1 z>y}l!Y_&3COAo)ETrZD9K$~?*v$Hh$MqesSL{2oqZhQ!sKk^~>n8PL@YX~jZ_m2I7 z>1`3iHggOzmNeL0_L-_-H(g;DOdw)y#v`xJV~ePB?w~^UD+lKI?-AdH2Jd-FGp-?q zWT!k$;{k*tk_G@U<4k1GnPualG1{~XsHH+l?BV6-1+QeO!MrK69JHmK|MIteLIPGd zFfa|!B8I_%z4}@M2|tr#A1?|QCUQkU;>mOlK5Y4R*;-P;-WKq>+H1xe;`I)e zf>?_@#_hJ%1E1`NyxAXg;74!$&J6JYiee#zkHaN=PwEfv3B$-Ht{&UiqJ!G%xlr0x zjy>WuZxQ$6hVef=xvX5ug;?pS+80G+Go*qpzb8luc@F=3KsR+4E$MaJn!9@Z?~eXg zMP%x1V+F65>!C>|rH|^0KU=}jd2o~umBSNYDg&;LOJx27!i%9WF}mSLh(gFU=t&ng z_J>@o-qA;2AlNMx-h|IlZ4QngSW_mdDBbt2Nl$;J+W+tvklq|wmNE9yG+WGYNykKD zCKQn<>@flR#OLQ=f|H2TGc9Bc_DJVSE`-7$#E|4*n$n6f^(X0~Mbh3h9?WO|-J=7h zyXshAo2wZFGtScrxIxOLgNMXKa_!hFUA#h;rY~g$kM_?+^Yry=qcgpqJXt?K2mWRD zdIS;I;xeOV&W2#f75?1Kzoh0ie2t+u5BvM?5Ht?m159lFs~hRLsPDvpo*dJ5MxW{gHX$mAAzJ6#xs zii)XMMQub2_7B6JXl0b2L>A_Ek}>blLY-z{M73%Ix63^@9X-_t@hgXogZUXZCTlRp6)g_522MD(AtMjn`FMY`--P>+$tI3>*ND??0)3nO znX`mV_YsVHbU%91EnoQqj!`AA{{U07t1bFS{yI`v$a-HpiB2(cDzFd{OYFJ9P#>8W z_RK3xkyo+!qsulvB=1)J0ijn-YH=zbZsuPq z-@H4vqe236AfaT^B`#o6MWB6Rh(*3!_V%5){h|{D-a$L9ZW((JnK7QV*b z-aYi&wp8-5-8;m|mdoIAvFcH`x^;K>vHeH=QL~y~uZhh)X|c@281?&SV5)x;9m~LonbCoVk&eHkkVl!cx3kBhi=3PGM zDMtYx_cn=;w;hXLPyO_(%qGfEC}$$K;LG(F>ggG|=MOU>7q3G;P)jocRy<3yyOLTS ziDd;$WNNihRCt z3v51T3qPH?RstvazBX7g@Rvo6JwnQkjiz%td~0nAD|T(djDrmP74yR|IKy^fVZt;< zp>S5q$Elwl){JK=Ef{o&d`y|}rA)&O&`84ZOh`#6%F*8+B@dB5X)$|b_`7mb{B04A zazY&IIBO%NmNyEnC4`QT_!p!`R4ZzSGf@5#rI<5C%^CNvl1pl;?4IFNt5;H~-D6Jy z)zqxfG{mBYy2Le0xn^2i#218Vh`=7@I z%ors3bCG3i@kG0DjEld@Z(2}tDL6D^L6M&gsIK5+_=i0?5wqvCCxb%j@T5;l#bdQH zRC(}^uPUPVbOPTp&ni`#EoxZE#;xOp*5l)0A;gGjj4aRHXueIv;-hK&Qp&Yn*S6~{(RkD4gPM}6d(>^ z2_Cm(9nfl~S?6$@A3nwCnN1Qk8%u!MMA>ykrar?`r|KJb*bv2+4ozC<(JCvWzmaam+|ZGRuvC8zK} z+PTV0nhCIQa+VqGW+Iz(=%jZUz(qKm0-|5;gm*m<4&X@+c>uQ#@}KJn2a}jrIBC-# zo5HN57~@cBu&?cBP6tKhG0az1Q_FaQj=&tT4-&O}7d^2ZKJYix!SeWqIiz68OZjDo z<(R1lJ&@FbOEEM-{V^W!E+{QGgJt{8Pp06~?C#3%3?{Cmo$8BCe!>1!N9w8VA~V^; zv_PjmZTiFG^%mK)V5y#BUac=rhEj_D$m5_Qdq=lBAqMe8!(-wm)Le{ZF8!hwx$U6I zMMnA^nqKXdGwUmtUL<)VqzjU&s+n&qNYE|w@(U>-5*b1jr&qVxv&46hx1VSSW|6o> z2Xn-mF+}RW-3nb^;X(A&Kd4$PUY=d!cC=%$3E}%yP!x}M?XK8IDPNzRMV4=pH_%`n|nrbP;s6 z@wK^!lf5cP=A@R<7KC~IN{#*Nq>@fb8=(9Xot6ZHSGAbatjmY9iSj*nlNV@pX+4Ut z9mE0jB(e1sc|pF(p1ao%e``K}D{+I=F2Q0I7+*jgWBnkylu4Pj_$LYb~`its3fsauoA84+V9Sc>?$_&__*1YO^dSpr@pTRJsO|!lVxu8hqKlwmQuAk zje%$c*?b5E^V}ovv5P_U*;(5$M}oMMIQuTwb3?J0bw>}UI(*HhLCvHsY_Ub-$*x@T zJwcDQ-f-+bQn)Q+%>PWGBMWQ$R*7K^pM`zsj(#7CDBJrK%jCXM!2h1aC}5PkjFBoo zff$f2a0_sME8pm);6~#fUAqkO2beAVtQXoE#^c8*!k9iKn3j&LWy5H9j?Bld{1|&bI+vPZGf?MBABa_2$Nv0(WQ5}J(EB+ zEWx^aETr&}wVv(jN-$xJaBNorw@K}j`lEr7rP(W89LP=lZHbWr3%CO6 zig%;r)(s<5I$yJIpGREYR`n2$9($293LJuf?1hV^u)39y-Rl*LH*zKxF~5`lx4Hbf z@egC%Hz(cA*e_lj2L$|IE82&vtLJ?AyYG)P;%{;rX)sA>v5sy}5YP!PIV)j>Ui39& zmQ}3+!(KKCJCMb6LTA;$idBdFD$4Pd;$8qsuZZYiVfFJb=R__!8{6BoYP8S^1Xzm> z97n1VZS!A(MCI>)*f7`Q<<)yyh2UF7LkbwfKIH)!mm1L~&LPjgv3Y{i!82JW#`xT* zc^DD#%z~IUc)N$MF33rJ?XXC!fX+2j)Mct3`{`1w`Tyre9oqxhICH^8Z2jhyuaM7V zvAyelC=_iKH8nM$?GA`+ni~a!HapwrvyiRnm@B)X>WSm&OU{K|ve$Cd%KmMrlaHcX%t$3YP_UO>g(Yner zT+6%on>#G{(jBEL>!FNlR(U!3wN0ck-hZ`xjqbm}EhF0}NiP4X4Ca6LrupEe!hH*YLn( zP)zj7NpZlfPmkRNlwu$6<^ccTumxZf_ec)S2d`rq_t9sW+5691)bn=xwOhc^8dXOX zd=9uyu513@u=yB2ORjW>qpa#fx++3s9EUEi%hRSi%-A^se2S|Y{UI1^~*Si zIZq|N;WkI9#f~f~=7N?D18}>CS#(7h;kmD(tyz9dXU+N%80o{RFC(HUtYz3%?e;kL zt>%kZ;40YEuxV_77qE8!dlmt#83>dfEz~#@p=OI@4&AklPiJsEZOej8a#ND|HZ0Wb+QFPa+w;?Yeyc&X1l?WS9Tx-T0 zkw2e&OvAkI-pcw~%N70!yQDevE1ue*2i(!L0CKF)HIi1%Rw*vgm`p_LCS)@CBBq^^ z7eSS5XQ%P1fIZSrTp=F2E+`^gn`W|4nlrq{vA8aXCDL&CEBu?Lx}n-z(MA!y>;yf7 ztEtWF^6-Sm6!K-lSaFo7CB;tSZQ=CK^{Z=*#c-@J84;|udDPzS>S21XM#R#}8lVg< z(Y3Z_!`NR{BWnGEaFoZEMf#scr|t3`s^*Afe%REd3h&%W9jbH~)uPDCrs1rbqty&V zXfVj7BcTywhHs41A;d|psixIAUv4+f4~ZPSl+v?O$MYGdC>tf#{N)%^`FvW>(Rne^$@6;7|DYrEU- zPR);^m^z`Yn=6*cTh{lcZeuomdZ!(M{4WVMDgCSyXZlzpWDLuQaj+YNZ1{7|s9;olHT0*ewb0zf~eg~2c%-Rw1 zfj$Ld?(%pO8^Cy%x}$WV^9T)VFb#W2RlFem!-FuV%%)anBgOHHmveD#wJ4x<$DjsV z0Km1u4yKFDLT_A%D;s&_&0Vw?1E7hgJHC8wN=2jA?h> z6c3Ezx|u;8l8vp>XH-NQyf=ZGmBemvJ4n@Z=l>FeI+J{A4%(kw?P2{~D3{0gNwJ~z z)t()aAT(x`MLBY3sEE0ObVphfdN-}Z$w35?S$3lO0A&dB`>SBBT4Cj0XibYOw zP0|x@s>KOHm&|o!Iknjz{u0RKM%{aA&J!_qRTbBHf$))8U$AQz(5~bo{w-GO{Q1D_ zcQW?YGw)OB;tIZR9796WknwO-N!L&`|H8f+&rJD|sXKwkl^CaDHVj;612|cnFs6OH zISKQKC*V%b9lI9#xU~)7bZG)%u0m&WOU;~U(ndJVHLs8OhGKOW3s?Tst{&Fvpo7s! zJK5GrZ1y6pmhuw-Y7#$aS7)>I>SA%Z|jeA3T?(XTMy%bIVL)V$+ z6hrXA^BwI?aNnXw$mo4-5kTjg#=9^HB@+0x|8&NV!2t+$(7Rj%sV2Y()#BUoPr8t7 z&)CBB|87POG3$!a7X3{WNaH$3B$v}1p)G2UnYv-aAe;dEDIL=ZK~W9yDFxMS&n`>h z#72zsm4Q;81(E`ObW0McsoXN!!(IFxe=c=1HQa@h2t~>|_l~NIY=bY%!aS=Nj z>;*~@2eTGy!K2@gijlv& zlC$h@p8oNamS@#&+f7%+JVeha3%ek|=Q&YM*~GP2EZjG%{H&h2gCor1MWm`0@J)

      ` element that has a ShaderMount available on it */ +export interface PaperShaderElement extends HTMLElement { + paperShaderMount: ShaderMount | undefined; +} +/** Check if an element is a Paper shader element */ +export declare function isPaperShaderElement(element: HTMLElement): element is PaperShaderElement; +/** + * Uniform types that we support to be auto-mapped into the fragment shader + * + * We accept undefined as a convenience for server rendering, when some things may be undefined + * We just skip setting the uniform if it's undefined. This allows the shader mount to still take up space during server rendering + */ +export interface ShaderMountUniforms { + [key: string]: boolean | number | number[] | number[][] | HTMLImageElement | undefined; +} +export interface ShaderMotionParams { + speed?: number; + frame?: number; +} +export type ShaderPreset = { + name: string; + params: Required; +}; +export type ImageShaderPreset = { + name: string; + /** + * Params for the shader excluding the image. + * Image is excluded as it isn't considered a preset, + * e.g. when switching between presets it shouldn't switch the image. + * + * While we exclude images from presets they should still be set with a default prop value so the code-first usage of shaders remains great. + */ + params: Required>; +}; diff --git a/public/vendor/paper-shaders/shader-mount.js b/public/vendor/paper-shaders/shader-mount.js new file mode 100644 index 0000000..5cf3dfe --- /dev/null +++ b/public/vendor/paper-shaders/shader-mount.js @@ -0,0 +1,510 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Paper Shaders * + * https://github.com/paper-design/shaders * + * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +import { vertexShaderSource } from "./vertex-shader.js"; +const DEFAULT_MAX_PIXEL_COUNT = 1920 * 1080 * 4; +class ShaderMount { + parentElement; + canvasElement; + gl; + program = null; + uniformLocations = {}; + /** The fragment shader that we are using */ + fragmentShader; + /** Stores the RAF for the render loop */ + rafId = null; + /** Time of the last rendered frame */ + lastRenderTime = 0; + /** Total time that we have played any animation, passed as a uniform to the shader for time-based VFX */ + currentFrame = 0; + /** The speed that we progress through animation time (multiplies by delta time every update). Allows negatives to play in reverse. If set to 0, rAF will stop entirely so static shaders have no recurring performance costs */ + speed = 0; + /** Actual speed used that accounts for visibility: we pause the shader if the tab is hidden or the element out of the viewport */ + currentSpeed = 0; + /** Uniforms that are provided by the user for the specific shader being mounted (not including uniforms that this Mount adds, like time and resolution) */ + providedUniforms; + /** Names of the uniforms that should have mipmaps generated for them */ + mipmaps = []; + /** Just a sanity check to make sure frames don't run after we're disposed */ + hasBeenDisposed = false; + /** If the resolution of the canvas has changed since the last render */ + resolutionChanged = true; + /** Store textures that are provided by the user */ + textures = /* @__PURE__ */ new Map(); + minPixelRatio; + maxPixelCount; + isSafari = isSafari(); + uniformCache = {}; + textureUnitMap = /* @__PURE__ */ new Map(); + ownerDocument; + constructor(parentElement, fragmentShader, uniforms, webGlContextAttributes, speed = 0, frame = 0, minPixelRatio = 2, maxPixelCount = DEFAULT_MAX_PIXEL_COUNT, mipmaps = []) { + if (parentElement?.nodeType === 1) { + this.parentElement = parentElement; + } else { + throw new Error("Paper Shaders: parent element must be an HTMLElement"); + } + this.ownerDocument = parentElement.ownerDocument; + if (!this.ownerDocument.querySelector("style[data-paper-shader]")) { + const styleElement = this.ownerDocument.createElement("style"); + styleElement.innerHTML = defaultStyle; + styleElement.setAttribute("data-paper-shader", ""); + this.ownerDocument.head.prepend(styleElement); + } + const canvasElement = this.ownerDocument.createElement("canvas"); + this.canvasElement = canvasElement; + this.parentElement.prepend(canvasElement); + this.fragmentShader = fragmentShader; + this.providedUniforms = uniforms; + this.mipmaps = mipmaps; + this.currentFrame = frame; + this.minPixelRatio = minPixelRatio; + this.maxPixelCount = maxPixelCount; + const gl = canvasElement.getContext("webgl2", webGlContextAttributes); + if (!gl) { + throw new Error("Paper Shaders: WebGL is not supported in this browser"); + } + this.gl = gl; + this.initProgram(); + this.setupPositionAttribute(); + this.setupUniforms(); + this.setUniformValues(this.providedUniforms); + this.setupResizeObserver(); + visualViewport?.addEventListener("resize", this.handleVisualViewportChange); + this.setupIntersectionObserver(); + this.setSpeed(speed); + this.parentElement.setAttribute("data-paper-shader", ""); + this.parentElement.paperShaderMount = this; + this.ownerDocument.addEventListener("visibilitychange", this.handleDocumentVisibilityChange); + } + initProgram = () => { + const program = createProgram(this.gl, vertexShaderSource, this.fragmentShader); + if (!program) return; + this.program = program; + }; + setupPositionAttribute = () => { + const positionAttributeLocation = this.gl.getAttribLocation(this.program, "a_position"); + const positionBuffer = this.gl.createBuffer(); + this.gl.bindBuffer(this.gl.ARRAY_BUFFER, positionBuffer); + const positions = [-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1]; + this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(positions), this.gl.STATIC_DRAW); + this.gl.enableVertexAttribArray(positionAttributeLocation); + this.gl.vertexAttribPointer(positionAttributeLocation, 2, this.gl.FLOAT, false, 0, 0); + }; + setupUniforms = () => { + const uniformLocations = { + u_time: this.gl.getUniformLocation(this.program, "u_time"), + u_pixelRatio: this.gl.getUniformLocation(this.program, "u_pixelRatio"), + u_resolution: this.gl.getUniformLocation(this.program, "u_resolution") + }; + Object.entries(this.providedUniforms).forEach(([key, value]) => { + uniformLocations[key] = this.gl.getUniformLocation(this.program, key); + if (value instanceof HTMLImageElement) { + const aspectRatioUniformName = `${key}AspectRatio`; + uniformLocations[aspectRatioUniformName] = this.gl.getUniformLocation(this.program, aspectRatioUniformName); + } + }); + this.uniformLocations = uniformLocations; + }; + /** + * The scale that we should render at. + * - Used to target 2x rendering even on 1x screens for better antialiasing + * - Prevents the virtual resolution from going beyond the maximum resolution + * - Accounts for the page zoom level so we render in physical device pixels rather than CSS pixels + */ + renderScale = 1; + parentWidth = 0; + parentHeight = 0; + parentDevicePixelWidth = 0; + parentDevicePixelHeight = 0; + devicePixelsSupported = false; + intersectionObserver = null; + isInViewport = true; + resizeObserver = null; + setupResizeObserver = () => { + this.resizeObserver = new ResizeObserver(([entry]) => { + if (entry?.borderBoxSize[0]) { + const physicalPixelSize = entry.devicePixelContentBoxSize?.[0]; + if (physicalPixelSize !== void 0) { + this.devicePixelsSupported = true; + this.parentDevicePixelWidth = physicalPixelSize.inlineSize; + this.parentDevicePixelHeight = physicalPixelSize.blockSize; + } + this.parentWidth = entry.borderBoxSize[0].inlineSize; + this.parentHeight = entry.borderBoxSize[0].blockSize; + } + this.handleResize(); + }); + this.resizeObserver.observe(this.parentElement); + }; + setupIntersectionObserver = () => { + const view = this.ownerDocument.defaultView; + if (!view?.IntersectionObserver) return; + this.intersectionObserver = new view.IntersectionObserver(([entry]) => { + this.isInViewport = entry?.isIntersecting ?? true; + this.updateCurrentSpeed(); + }); + this.intersectionObserver.observe(this.parentElement); + }; + // Visual viewport resize handler, mainly used to react to browser zoom changes. + // Resize observer by itself does not react to pinch zoom, and although it usually + // reacts to classic browser zoom, it's not guaranteed in edge cases. + // Since timing between visual viewport changes and resize observer is complex + // and because we'd like to know the device pixel sizes of elements, we just restart + // the observer to get a guaranteed fresh callback regardless if it would have triggered or not. + handleVisualViewportChange = () => { + this.resizeObserver?.disconnect(); + this.setupResizeObserver(); + }; + /** Resize handler for when the container div changes size or the max pixel count changes and we want to resize our canvas to match */ + handleResize = () => { + let targetPixelWidth = 0; + let targetPixelHeight = 0; + const dpr = Math.max(1, window.devicePixelRatio); + const pinchZoom = visualViewport?.scale ?? 1; + if (this.devicePixelsSupported) { + const scaleToMeetMinPixelRatio = Math.max(1, this.minPixelRatio / dpr); + targetPixelWidth = this.parentDevicePixelWidth * scaleToMeetMinPixelRatio * pinchZoom; + targetPixelHeight = this.parentDevicePixelHeight * scaleToMeetMinPixelRatio * pinchZoom; + } else { + let targetRenderScale = Math.max(dpr, this.minPixelRatio) * pinchZoom; + if (this.isSafari) { + const zoomLevel = bestGuessBrowserZoom(this.ownerDocument); + targetRenderScale *= Math.max(1, zoomLevel); + } + targetPixelWidth = Math.round(this.parentWidth) * targetRenderScale; + targetPixelHeight = Math.round(this.parentHeight) * targetRenderScale; + } + const maxPixelCountHeadroom = Math.sqrt(this.maxPixelCount) / Math.sqrt(targetPixelWidth * targetPixelHeight); + const scaleToMeetMaxPixelCount = Math.min(1, maxPixelCountHeadroom); + const newWidth = Math.round(targetPixelWidth * scaleToMeetMaxPixelCount); + const newHeight = Math.round(targetPixelHeight * scaleToMeetMaxPixelCount); + const newRenderScale = newWidth / Math.round(this.parentWidth); + if (this.canvasElement.width !== newWidth || this.canvasElement.height !== newHeight || this.renderScale !== newRenderScale) { + this.renderScale = newRenderScale; + this.canvasElement.width = newWidth; + this.canvasElement.height = newHeight; + this.resolutionChanged = true; + this.gl.viewport(0, 0, this.gl.canvas.width, this.gl.canvas.height); + this.render(performance.now()); + } + }; + render = (currentTime) => { + if (this.hasBeenDisposed) return; + if (this.program === null) { + console.warn("Tried to render before program or gl was initialized"); + return; + } + const dt = currentTime - this.lastRenderTime; + this.lastRenderTime = currentTime; + if (this.currentSpeed !== 0) { + this.currentFrame += dt * this.currentSpeed; + } + this.gl.clear(this.gl.COLOR_BUFFER_BIT); + this.gl.useProgram(this.program); + this.gl.uniform1f(this.uniformLocations.u_time, this.currentFrame * 1e-3); + if (this.resolutionChanged) { + this.gl.uniform2f(this.uniformLocations.u_resolution, this.gl.canvas.width, this.gl.canvas.height); + this.gl.uniform1f(this.uniformLocations.u_pixelRatio, this.renderScale); + this.resolutionChanged = false; + } + this.gl.drawArrays(this.gl.TRIANGLES, 0, 6); + if (this.currentSpeed !== 0) { + this.requestRender(); + } else { + this.rafId = null; + } + }; + requestRender = () => { + if (this.rafId !== null) { + cancelAnimationFrame(this.rafId); + } + this.rafId = requestAnimationFrame(this.render); + }; + /** Creates a texture from an image and sets it into a uniform value */ + setTextureUniform = (uniformName, image) => { + if (!image.complete || image.naturalWidth === 0) { + throw new Error(`Paper Shaders: image for uniform ${uniformName} must be fully loaded`); + } + const existingTexture = this.textures.get(uniformName); + if (existingTexture) { + this.gl.deleteTexture(existingTexture); + } + if (!this.textureUnitMap.has(uniformName)) { + this.textureUnitMap.set(uniformName, this.textureUnitMap.size); + } + const textureUnit = this.textureUnitMap.get(uniformName); + this.gl.activeTexture(this.gl.TEXTURE0 + textureUnit); + const texture = this.gl.createTexture(); + this.gl.bindTexture(this.gl.TEXTURE_2D, texture); + this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE); + this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE); + this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR); + this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.LINEAR); + this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, this.gl.RGBA, this.gl.UNSIGNED_BYTE, image); + if (this.mipmaps.includes(uniformName)) { + this.gl.generateMipmap(this.gl.TEXTURE_2D); + this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR_MIPMAP_LINEAR); + } + const error = this.gl.getError(); + if (error !== this.gl.NO_ERROR || texture === null) { + console.error("Paper Shaders: WebGL error when uploading texture:", error); + return; + } + this.textures.set(uniformName, texture); + const location = this.uniformLocations[uniformName]; + if (location) { + this.gl.uniform1i(location, textureUnit); + const aspectRatioUniformName = `${uniformName}AspectRatio`; + const aspectRatioLocation = this.uniformLocations[aspectRatioUniformName]; + if (aspectRatioLocation) { + const aspectRatio = image.naturalWidth / image.naturalHeight; + this.gl.uniform1f(aspectRatioLocation, aspectRatio); + } + } + }; + /** Utility: recursive equality test for all the uniforms */ + areUniformValuesEqual = (a, b) => { + if (a === b) return true; + if (Array.isArray(a) && Array.isArray(b) && a.length === b.length) { + return a.every((val, i) => this.areUniformValuesEqual(val, b[i])); + } + return false; + }; + /** Sets the provided uniform values into the WebGL program, can be a partial list of uniforms that have changed */ + setUniformValues = (updatedUniforms) => { + this.gl.useProgram(this.program); + Object.entries(updatedUniforms).forEach(([key, value]) => { + let cacheValue = value; + if (value instanceof HTMLImageElement) { + cacheValue = `${value.src.slice(0, 200)}|${value.naturalWidth}x${value.naturalHeight}`; + } + if (this.areUniformValuesEqual(this.uniformCache[key], cacheValue)) return; + this.uniformCache[key] = cacheValue; + const location = this.uniformLocations[key]; + if (!location) { + console.warn(`Uniform location for ${key} not found`); + return; + } + if (value instanceof HTMLImageElement) { + this.setTextureUniform(key, value); + } else if (Array.isArray(value)) { + let flatArray = null; + let valueLength = null; + if (value[0] !== void 0 && Array.isArray(value[0])) { + const firstChildLength = value[0].length; + if (value.every((arr) => arr.length === firstChildLength)) { + flatArray = value.flat(); + valueLength = firstChildLength; + } else { + console.warn(`All child arrays must be the same length for ${key}`); + return; + } + } else { + flatArray = value; + valueLength = flatArray.length; + } + switch (valueLength) { + case 2: + this.gl.uniform2fv(location, flatArray); + break; + case 3: + this.gl.uniform3fv(location, flatArray); + break; + case 4: + this.gl.uniform4fv(location, flatArray); + break; + case 9: + this.gl.uniformMatrix3fv(location, false, flatArray); + break; + case 16: + this.gl.uniformMatrix4fv(location, false, flatArray); + break; + default: + console.warn(`Unsupported uniform array length: ${valueLength}`); + } + } else if (typeof value === "number") { + this.gl.uniform1f(location, value); + } else if (typeof value === "boolean") { + this.gl.uniform1i(location, value ? 1 : 0); + } else { + console.warn(`Unsupported uniform type for ${key}: ${typeof value}`); + } + }); + }; + /** Gets the current total animation time from 0ms */ + getCurrentFrame = () => { + return this.currentFrame; + }; + /** Set a frame to get a deterministic result, frames are literally just milliseconds from zero since the animation started */ + setFrame = (newFrame) => { + this.currentFrame = newFrame; + this.lastRenderTime = performance.now(); + this.render(performance.now()); + }; + /** Set an animation speed (or 0 to stop animation) */ + setSpeed = (newSpeed = 1) => { + this.speed = newSpeed; + this.updateCurrentSpeed(); + }; + /** Apply the target speed, pausing (0) while the tab is hidden or the element is out of the viewport */ + updateCurrentSpeed = () => { + this.setCurrentSpeed(this.ownerDocument.hidden || !this.isInViewport ? 0 : this.speed); + }; + setCurrentSpeed = (newSpeed) => { + this.currentSpeed = newSpeed; + if (this.rafId === null && newSpeed !== 0) { + this.lastRenderTime = performance.now(); + this.rafId = requestAnimationFrame(this.render); + } + if (this.rafId !== null && newSpeed === 0) { + cancelAnimationFrame(this.rafId); + this.rafId = null; + } + }; + /** Set the maximum pixel count for the shader, this will limit the number of pixels that will be rendered */ + setMaxPixelCount = (newMaxPixelCount = DEFAULT_MAX_PIXEL_COUNT) => { + this.maxPixelCount = newMaxPixelCount; + this.handleResize(); + }; + /** Set the minimum pixel ratio for the shader */ + setMinPixelRatio = (newMinPixelRatio = 2) => { + this.minPixelRatio = newMinPixelRatio; + this.handleResize(); + }; + /** Update the uniforms that are provided by the outside shader, can be a partial set with only the uniforms that have changed */ + setUniforms = (newUniforms) => { + this.setUniformValues(newUniforms); + this.providedUniforms = { ...this.providedUniforms, ...newUniforms }; + this.render(performance.now()); + }; + handleDocumentVisibilityChange = () => { + this.updateCurrentSpeed(); + }; + /** Dispose of the shader mount, cleaning up all of the WebGL resources */ + dispose = () => { + this.hasBeenDisposed = true; + if (this.rafId !== null) { + cancelAnimationFrame(this.rafId); + this.rafId = null; + } + if (this.gl && this.program) { + this.textures.forEach((texture) => { + this.gl.deleteTexture(texture); + }); + this.textures.clear(); + this.gl.deleteProgram(this.program); + this.program = null; + this.gl.bindBuffer(this.gl.ARRAY_BUFFER, null); + this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, null); + this.gl.bindRenderbuffer(this.gl.RENDERBUFFER, null); + this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, null); + this.gl.getError(); + } + if (this.resizeObserver) { + this.resizeObserver.disconnect(); + this.resizeObserver = null; + } + if (this.intersectionObserver) { + this.intersectionObserver.disconnect(); + this.intersectionObserver = null; + } + visualViewport?.removeEventListener("resize", this.handleVisualViewportChange); + this.ownerDocument.removeEventListener("visibilitychange", this.handleDocumentVisibilityChange); + this.uniformLocations = {}; + this.canvasElement.remove(); + delete this.parentElement.paperShaderMount; + }; +} +function createShader(gl, type, source) { + const shader = gl.createShader(type); + if (!shader) return null; + gl.shaderSource(shader, source); + gl.compileShader(shader); + if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { + console.error("An error occurred compiling the shaders: " + gl.getShaderInfoLog(shader)); + gl.deleteShader(shader); + return null; + } + return shader; +} +function createProgram(gl, vertexShaderSource2, fragmentShaderSource) { + const format = gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT); + const precision = format ? format.precision : null; + if (precision && precision < 23) { + vertexShaderSource2 = vertexShaderSource2.replace(/precision\s+(lowp|mediump)\s+float;/g, "precision highp float;"); + fragmentShaderSource = fragmentShaderSource.replace(/precision\s+(lowp|mediump)\s+float/g, "precision highp float").replace(/\b(uniform|varying|attribute)\s+(lowp|mediump)\s+(\w+)/g, "$1 highp $3"); + } + const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource2); + const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource); + if (!vertexShader || !fragmentShader) return null; + const program = gl.createProgram(); + if (!program) return null; + gl.attachShader(program, vertexShader); + gl.attachShader(program, fragmentShader); + gl.linkProgram(program); + if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { + console.error("Unable to initialize the shader program: " + gl.getProgramInfoLog(program)); + gl.deleteProgram(program); + gl.deleteShader(vertexShader); + gl.deleteShader(fragmentShader); + return null; + } + gl.detachShader(program, vertexShader); + gl.detachShader(program, fragmentShader); + gl.deleteShader(vertexShader); + gl.deleteShader(fragmentShader); + return program; +} +const defaultStyle = `@layer paper-shaders { + :where([data-paper-shader]) { + isolation: isolate; + position: relative; + + & canvas { + contain: strict; + display: block; + position: absolute; + inset: 0; + z-index: -1; + width: 100%; + height: 100%; + border-radius: inherit; + corner-shape: inherit; + } + } +}`; +function isPaperShaderElement(element) { + return "paperShaderMount" in element; +} +function isSafari() { + const ua = navigator.userAgent.toLowerCase(); + return ua.includes("safari") && !ua.includes("chrome") && !ua.includes("android"); +} +function bestGuessBrowserZoom(doc) { + const viewportScale = visualViewport?.scale ?? 1; + const viewportWidth = visualViewport?.width ?? window.innerWidth; + const scrollbarWidth = window.innerWidth - doc.documentElement.clientWidth; + const innerWidth = viewportScale * viewportWidth + scrollbarWidth; + const ratio = outerWidth / innerWidth; + const zoomPercentageRounded = Math.round(100 * ratio); + if (zoomPercentageRounded % 5 === 0) { + return zoomPercentageRounded / 100; + } + if (zoomPercentageRounded === 33) { + return 1 / 3; + } + if (zoomPercentageRounded === 67) { + return 2 / 3; + } + if (zoomPercentageRounded === 133) { + return 4 / 3; + } + return ratio; +} +export { + ShaderMount, + isPaperShaderElement +}; +//# sourceMappingURL=shader-mount.js.map diff --git a/public/vendor/paper-shaders/shader-mount.js.map b/public/vendor/paper-shaders/shader-mount.js.map new file mode 100644 index 0000000..3e2d6f3 --- /dev/null +++ b/public/vendor/paper-shaders/shader-mount.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../src/shader-mount.ts"], + "sourcesContent": ["import { vertexShaderSource } from './vertex-shader.js';\n\nconst DEFAULT_MAX_PIXEL_COUNT: number = 1920 * 1080 * 4;\n\nexport class ShaderMount {\n public parentElement: PaperShaderElement;\n public canvasElement: HTMLCanvasElement;\n private gl: WebGL2RenderingContext;\n private program: WebGLProgram | null = null;\n private uniformLocations: Record = {};\n /** The fragment shader that we are using */\n private fragmentShader: string;\n /** Stores the RAF for the render loop */\n private rafId: number | null = null;\n /** Time of the last rendered frame */\n private lastRenderTime = 0;\n /** Total time that we have played any animation, passed as a uniform to the shader for time-based VFX */\n private currentFrame = 0;\n /** The speed that we progress through animation time (multiplies by delta time every update). Allows negatives to play in reverse. If set to 0, rAF will stop entirely so static shaders have no recurring performance costs */\n private speed = 0;\n /** Actual speed used that accounts for visibility: we pause the shader if the tab is hidden or the element out of the viewport */\n private currentSpeed = 0;\n /** Uniforms that are provided by the user for the specific shader being mounted (not including uniforms that this Mount adds, like time and resolution) */\n private providedUniforms: ShaderMountUniforms;\n /** Names of the uniforms that should have mipmaps generated for them */\n private mipmaps: string[] = [];\n /** Just a sanity check to make sure frames don't run after we're disposed */\n private hasBeenDisposed = false;\n /** If the resolution of the canvas has changed since the last render */\n private resolutionChanged = true;\n /** Store textures that are provided by the user */\n private textures: Map = new Map();\n private minPixelRatio;\n private maxPixelCount;\n private isSafari = isSafari();\n private uniformCache: Record = {};\n private textureUnitMap: Map = new Map();\n private ownerDocument: Document;\n\n constructor(\n /** The div you'd like to mount the shader to. The shader will match its size. */\n parentElement: HTMLElement,\n fragmentShader: string,\n uniforms: ShaderMountUniforms,\n webGlContextAttributes?: WebGLContextAttributes,\n /** The speed of the animation, or 0 to stop it. Supports negative values to play in reverse. */\n speed = 0,\n /** Pass a frame to offset the starting u_time value and give deterministic results*/\n frame = 0,\n /**\n * The minimum pixel ratio to render at, defaults to 2.\n * May be reduced to improve performance or increased together with `maxPixelCount` to improve antialiasing.\n */\n minPixelRatio = 2,\n /**\n * The maximum amount of physical device pixels to render for the shader,\n * by default it's 1920 * 1080 * 2x dpi (per each side) = 8,294,400 pixels of a 4K screen.\n * Actual DOM size of the canvas can be larger, it will just lose quality after this.\n *\n * May be reduced to improve performance or increased to improve quality on high-resolution screens.\n */\n maxPixelCount: number = DEFAULT_MAX_PIXEL_COUNT,\n /** Names of the uniforms that should have mipmaps generated for them */\n mipmaps: string[] = []\n ) {\n // nodeType check instead of `instanceof` to work across document boundaries (iframes, PiP windows)\n if (parentElement?.nodeType === 1) {\n this.parentElement = parentElement as PaperShaderElement;\n } else {\n throw new Error('Paper Shaders: parent element must be an HTMLElement');\n }\n\n this.ownerDocument = parentElement.ownerDocument;\n\n if (!this.ownerDocument.querySelector('style[data-paper-shader]')) {\n const styleElement = this.ownerDocument.createElement('style');\n styleElement.innerHTML = defaultStyle;\n styleElement.setAttribute('data-paper-shader', '');\n this.ownerDocument.head.prepend(styleElement);\n }\n\n // Create the canvas element and mount it into the provided element\n const canvasElement = this.ownerDocument.createElement('canvas');\n this.canvasElement = canvasElement;\n this.parentElement.prepend(canvasElement);\n this.fragmentShader = fragmentShader;\n this.providedUniforms = uniforms;\n this.mipmaps = mipmaps;\n // Base our starting animation time on the provided frame value\n this.currentFrame = frame;\n this.minPixelRatio = minPixelRatio;\n this.maxPixelCount = maxPixelCount;\n\n const gl = canvasElement.getContext('webgl2', webGlContextAttributes);\n if (!gl) {\n throw new Error('Paper Shaders: WebGL is not supported in this browser');\n }\n this.gl = gl;\n\n this.initProgram();\n this.setupPositionAttribute();\n // Grab the locations of the uniforms in the fragment shader\n this.setupUniforms();\n // Put the user provided values into the uniforms\n this.setUniformValues(this.providedUniforms);\n // Set up the resize observer to handle window resizing and set u_resolution\n this.setupResizeObserver();\n // Set up the visual viewport change listener to handle zoom changes (pinch zoom and classic browser zoom)\n visualViewport?.addEventListener('resize', this.handleVisualViewportChange);\n // Set up the intersection observer to pause animation when the element is scrolled out of view\n this.setupIntersectionObserver();\n\n // Set the animation speed after everything is ready to go\n this.setSpeed(speed);\n\n // Mark parent element as paper shader mount\n this.parentElement.setAttribute('data-paper-shader', '');\n\n // Add the shaderMount instance to the div mount element to make it easily accessible\n this.parentElement.paperShaderMount = this;\n\n // Listen for document visibility changes to pause the shader when the tab is hidden\n this.ownerDocument.addEventListener('visibilitychange', this.handleDocumentVisibilityChange);\n }\n\n private initProgram = () => {\n const program = createProgram(this.gl, vertexShaderSource, this.fragmentShader);\n if (!program) return;\n this.program = program;\n };\n\n private setupPositionAttribute = () => {\n const positionAttributeLocation = this.gl.getAttribLocation(this.program!, 'a_position');\n const positionBuffer = this.gl.createBuffer();\n this.gl.bindBuffer(this.gl.ARRAY_BUFFER, positionBuffer);\n const positions = [-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1];\n this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(positions), this.gl.STATIC_DRAW);\n this.gl.enableVertexAttribArray(positionAttributeLocation);\n this.gl.vertexAttribPointer(positionAttributeLocation, 2, this.gl.FLOAT, false, 0, 0);\n };\n\n private setupUniforms = () => {\n // Create a map to store all uniform locations\n const uniformLocations: Record = {\n u_time: this.gl.getUniformLocation(this.program!, 'u_time'),\n u_pixelRatio: this.gl.getUniformLocation(this.program!, 'u_pixelRatio'),\n u_resolution: this.gl.getUniformLocation(this.program!, 'u_resolution'),\n };\n\n // Add locations for all provided uniforms\n Object.entries(this.providedUniforms).forEach(([key, value]) => {\n uniformLocations[key] = this.gl.getUniformLocation(this.program!, key);\n\n // For texture uniforms, also look for the aspect ratio uniform\n if (value instanceof HTMLImageElement) {\n const aspectRatioUniformName = `${key}AspectRatio`;\n uniformLocations[aspectRatioUniformName] = this.gl.getUniformLocation(this.program!, aspectRatioUniformName);\n }\n });\n\n this.uniformLocations = uniformLocations;\n };\n\n /**\n * The scale that we should render at.\n * - Used to target 2x rendering even on 1x screens for better antialiasing\n * - Prevents the virtual resolution from going beyond the maximum resolution\n * - Accounts for the page zoom level so we render in physical device pixels rather than CSS pixels\n */\n private renderScale = 1;\n private parentWidth = 0;\n private parentHeight = 0;\n private parentDevicePixelWidth = 0;\n private parentDevicePixelHeight = 0;\n private devicePixelsSupported = false;\n\n private intersectionObserver: IntersectionObserver | null = null;\n private isInViewport = true;\n\n private resizeObserver: ResizeObserver | null = null;\n private setupResizeObserver = () => {\n this.resizeObserver = new ResizeObserver(([entry]) => {\n if (entry?.borderBoxSize[0]) {\n const physicalPixelSize = entry.devicePixelContentBoxSize?.[0];\n\n if (physicalPixelSize !== undefined) {\n this.devicePixelsSupported = true;\n this.parentDevicePixelWidth = physicalPixelSize.inlineSize;\n this.parentDevicePixelHeight = physicalPixelSize.blockSize;\n }\n\n this.parentWidth = entry.borderBoxSize[0].inlineSize;\n this.parentHeight = entry.borderBoxSize[0].blockSize;\n }\n\n this.handleResize();\n });\n\n this.resizeObserver.observe(this.parentElement);\n };\n\n private setupIntersectionObserver = () => {\n // we check element's own window to support shaders used within iframe/PiP elements\n const view = this.ownerDocument.defaultView;\n if (!view?.IntersectionObserver) return;\n\n this.intersectionObserver = new view.IntersectionObserver(([entry]) => {\n this.isInViewport = entry?.isIntersecting ?? true;\n this.updateCurrentSpeed();\n });\n\n this.intersectionObserver.observe(this.parentElement);\n };\n\n // Visual viewport resize handler, mainly used to react to browser zoom changes.\n // Resize observer by itself does not react to pinch zoom, and although it usually\n // reacts to classic browser zoom, it's not guaranteed in edge cases.\n // Since timing between visual viewport changes and resize observer is complex\n // and because we'd like to know the device pixel sizes of elements, we just restart\n // the observer to get a guaranteed fresh callback regardless if it would have triggered or not.\n private handleVisualViewportChange = () => {\n this.resizeObserver?.disconnect();\n this.setupResizeObserver();\n\n // In case of debugging timing, from here on:\n // - animation frame 1: a paint after the visual viewport resize\n // - animation frame 2: a paint after the resize observer has been handled, if it was ever triggered\n };\n\n /** Resize handler for when the container div changes size or the max pixel count changes and we want to resize our canvas to match */\n private handleResize = () => {\n // Aim to render at least as many pixels as physically displayed\n // This will overshoot when the user zooms out, but that's acceptable\n\n let targetPixelWidth = 0;\n let targetPixelHeight = 0;\n\n // If window.devicePixelRatio is below 1, it's safe to say the browser is just zoomed out\n // We can use 1 as the minimum value not to upscale it needlessly to meet the min pixel ratio param\n const dpr = Math.max(1, window.devicePixelRatio);\n const pinchZoom = visualViewport?.scale ?? 1;\n\n if (this.devicePixelsSupported) {\n // Use the real pixel size if we know it, plus meet the min pixel ratio requirement and add in pinch zoom\n const scaleToMeetMinPixelRatio = Math.max(1, this.minPixelRatio / dpr);\n targetPixelWidth = this.parentDevicePixelWidth * scaleToMeetMinPixelRatio * pinchZoom;\n targetPixelHeight = this.parentDevicePixelHeight * scaleToMeetMinPixelRatio * pinchZoom;\n } else {\n // Otherwise try to approximate the element size in device pixels using devicePixelRatio.\n // (devicePixelRatio is imprecise and element's width/height may be fractional CSS sizes, not real pixels).\n let targetRenderScale = Math.max(dpr, this.minPixelRatio) * pinchZoom;\n\n if (this.isSafari) {\n // As of 2025, Safari reports physical devicePixelRatio, but other browsers add the current zoom level:\n // https://bugs.webkit.org/show_bug.cgi?id=124862\n //\n // In Safari we need to factor in the zoom level manually in order to set the target resolution.\n // To avoid sidebars upscaling the target resolution, set a minimum zoom level of 1.\n // This will render at higher resolution when zoomed out, but that's fine.\n // (We mostly care about maintaining good quality when zoomed in).\n const zoomLevel = bestGuessBrowserZoom(this.ownerDocument);\n targetRenderScale *= Math.max(1, zoomLevel);\n }\n\n // Rounding the client width/height since they may be fractional in CSS layout values\n targetPixelWidth = Math.round(this.parentWidth) * targetRenderScale;\n targetPixelHeight = Math.round(this.parentHeight) * targetRenderScale;\n }\n\n // Prevent the total rendered pixel count from exceeding maxPixelCount\n const maxPixelCountHeadroom = Math.sqrt(this.maxPixelCount) / Math.sqrt(targetPixelWidth * targetPixelHeight);\n const scaleToMeetMaxPixelCount = Math.min(1, maxPixelCountHeadroom);\n const newWidth = Math.round(targetPixelWidth * scaleToMeetMaxPixelCount);\n const newHeight = Math.round(targetPixelHeight * scaleToMeetMaxPixelCount);\n const newRenderScale = newWidth / Math.round(this.parentWidth);\n\n if (\n this.canvasElement.width !== newWidth ||\n this.canvasElement.height !== newHeight ||\n this.renderScale !== newRenderScale // Usually, only render scale changes when the user zooms in/out\n ) {\n this.renderScale = newRenderScale;\n this.canvasElement.width = newWidth;\n this.canvasElement.height = newHeight;\n this.resolutionChanged = true;\n this.gl.viewport(0, 0, this.gl.canvas.width, this.gl.canvas.height);\n\n // this is necessary to avoid flashes while resizing (the next scheduled render will set uniforms)\n this.render(performance.now());\n }\n };\n\n private render = (currentTime: number) => {\n if (this.hasBeenDisposed) return;\n\n if (this.program === null) {\n console.warn('Tried to render before program or gl was initialized');\n return;\n }\n\n // Calculate the delta time\n const dt = currentTime - this.lastRenderTime;\n this.lastRenderTime = currentTime;\n // Increase the total animation time by dt * animationSpeed\n if (this.currentSpeed !== 0) {\n this.currentFrame += dt * this.currentSpeed;\n }\n\n // Clear the canvas\n this.gl.clear(this.gl.COLOR_BUFFER_BIT);\n\n // Update uniforms\n this.gl.useProgram(this.program);\n\n // Update the time uniform\n this.gl.uniform1f(this.uniformLocations.u_time!, this.currentFrame * 0.001);\n\n // If the resolution has changed, we need to update the uniform\n if (this.resolutionChanged) {\n this.gl.uniform2f(this.uniformLocations.u_resolution!, this.gl.canvas.width, this.gl.canvas.height);\n this.gl.uniform1f(this.uniformLocations.u_pixelRatio!, this.renderScale);\n this.resolutionChanged = false;\n }\n\n this.gl.drawArrays(this.gl.TRIANGLES, 0, 6);\n\n // Loop if we're animating\n if (this.currentSpeed !== 0) {\n this.requestRender();\n } else {\n this.rafId = null;\n }\n };\n\n private requestRender = () => {\n if (this.rafId !== null) {\n cancelAnimationFrame(this.rafId);\n }\n this.rafId = requestAnimationFrame(this.render);\n };\n\n /** Creates a texture from an image and sets it into a uniform value */\n private setTextureUniform = (uniformName: string, image: HTMLImageElement): void => {\n if (!image.complete || image.naturalWidth === 0) {\n throw new Error(`Paper Shaders: image for uniform ${uniformName} must be fully loaded`);\n }\n\n // Clean up existing texture if present\n const existingTexture = this.textures.get(uniformName);\n if (existingTexture) {\n this.gl.deleteTexture(existingTexture);\n }\n\n // Get texture unit\n if (!this.textureUnitMap.has(uniformName)) {\n this.textureUnitMap.set(uniformName, this.textureUnitMap.size);\n }\n const textureUnit = this.textureUnitMap.get(uniformName)!;\n // Activate correct texture unit before creating the texture\n this.gl.activeTexture(this.gl.TEXTURE0 + textureUnit);\n\n // Create and set up the new texture\n const texture = this.gl.createTexture();\n this.gl.bindTexture(this.gl.TEXTURE_2D, texture);\n\n // Set texture parameters\n this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);\n this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);\n this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR);\n this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.LINEAR);\n\n // Upload image to texture\n this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, this.gl.RGBA, this.gl.UNSIGNED_BYTE, image);\n\n // Generate mipmaps if the uniform is in the mipmaps list\n if (this.mipmaps.includes(uniformName)) {\n this.gl.generateMipmap(this.gl.TEXTURE_2D);\n this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR_MIPMAP_LINEAR);\n }\n\n const error = this.gl.getError();\n if (error !== this.gl.NO_ERROR || texture === null) {\n console.error('Paper Shaders: WebGL error when uploading texture:', error);\n return;\n }\n\n // Store the texture\n this.textures.set(uniformName, texture);\n\n // Set up texture unit and uniform\n const location = this.uniformLocations[uniformName];\n if (location) {\n this.gl.uniform1i(location, textureUnit);\n\n // Calculate and set the aspect ratio uniform\n const aspectRatioUniformName = `${uniformName}AspectRatio`;\n const aspectRatioLocation = this.uniformLocations[aspectRatioUniformName];\n if (aspectRatioLocation) {\n const aspectRatio = image.naturalWidth / image.naturalHeight;\n this.gl.uniform1f(aspectRatioLocation, aspectRatio);\n }\n }\n };\n\n /** Utility: recursive equality test for all the uniforms */\n private areUniformValuesEqual = (a: any, b: any): boolean => {\n if (a === b) return true;\n if (Array.isArray(a) && Array.isArray(b) && a.length === b.length) {\n return a.every((val, i) => this.areUniformValuesEqual(val, (b as any)[i]));\n }\n return false;\n };\n\n /** Sets the provided uniform values into the WebGL program, can be a partial list of uniforms that have changed */\n private setUniformValues = (updatedUniforms: ShaderMountUniforms) => {\n this.gl.useProgram(this.program);\n Object.entries(updatedUniforms).forEach(([key, value]) => {\n // Grab the value to use in the uniform cache\n let cacheValue: ShaderMountUniforms[keyof ShaderMountUniforms] | string = value;\n if (value instanceof HTMLImageElement) {\n // Images use their src for the cache value to save memory\n cacheValue = `${value.src.slice(0, 200)}|${value.naturalWidth}x${value.naturalHeight}`;\n }\n\n // Check if the uniform value has changed and, if not, bail early to avoid extra work\n if (this.areUniformValuesEqual(this.uniformCache[key], cacheValue)) return;\n // Update the uniform cache if we are still here\n this.uniformCache[key] = cacheValue;\n\n const location = this.uniformLocations[key];\n if (!location) {\n console.warn(`Uniform location for ${key} not found`);\n return;\n }\n\n if (value instanceof HTMLImageElement) {\n // Texture case, requires a good amount of code so it gets its own function:\n this.setTextureUniform(key, value);\n } else if (Array.isArray(value)) {\n // Array case\n let flatArray: number[] | null = null;\n let valueLength: number | null = null;\n\n // If it's an array of same-sized arrays, flatten it down so we can set the uniform\n if (value[0] !== undefined && Array.isArray(value[0])) {\n const firstChildLength = value[0].length;\n if (value.every((arr) => (arr as number[]).length === firstChildLength)) {\n // Array of same-sized arrays case, flattens the array sets it\n flatArray = value.flat();\n valueLength = firstChildLength;\n } else {\n console.warn(`All child arrays must be the same length for ${key}`);\n return;\n }\n } else {\n // Array of primitive values case, supports 2, 3, 4, 9, 16 length arrays\n flatArray = value as number[];\n valueLength = flatArray.length;\n }\n\n // Set the uniform based on array length... supports 2, 3, 4, 9, 16 length arrays of primitive values\n // or arbitrary length arrays of arrays\n switch (valueLength) {\n case 2:\n this.gl.uniform2fv(location, flatArray);\n break;\n case 3:\n this.gl.uniform3fv(location, flatArray);\n break;\n case 4:\n this.gl.uniform4fv(location, flatArray);\n break;\n case 9:\n this.gl.uniformMatrix3fv(location, false, flatArray);\n break;\n case 16:\n this.gl.uniformMatrix4fv(location, false, flatArray);\n break;\n default:\n console.warn(`Unsupported uniform array length: ${valueLength}`);\n }\n } else if (typeof value === 'number') {\n // Number case, supports floats and ints\n this.gl.uniform1f(location, value);\n } else if (typeof value === 'boolean') {\n // Boolean case, supports true and false\n this.gl.uniform1i(location, value ? 1 : 0);\n } else {\n // May happen on the server for SSR when undefined images are passed in\n console.warn(`Unsupported uniform type for ${key}: ${typeof value}`);\n }\n });\n };\n\n /** Gets the current total animation time from 0ms */\n public getCurrentFrame = (): number => {\n return this.currentFrame;\n };\n\n /** Set a frame to get a deterministic result, frames are literally just milliseconds from zero since the animation started */\n public setFrame = (newFrame: number): void => {\n this.currentFrame = newFrame;\n this.lastRenderTime = performance.now();\n this.render(performance.now());\n };\n\n /** Set an animation speed (or 0 to stop animation) */\n public setSpeed = (newSpeed = 1): void => {\n // Set the new animation speed\n this.speed = newSpeed;\n this.updateCurrentSpeed();\n };\n\n /** Apply the target speed, pausing (0) while the tab is hidden or the element is out of the viewport */\n private updateCurrentSpeed = (): void => {\n this.setCurrentSpeed(this.ownerDocument.hidden || !this.isInViewport ? 0 : this.speed);\n };\n\n private setCurrentSpeed = (newSpeed: number): void => {\n this.currentSpeed = newSpeed;\n\n if (this.rafId === null && newSpeed !== 0) {\n // Moving from 0 to animating, kick off a new rAF loop\n this.lastRenderTime = performance.now();\n this.rafId = requestAnimationFrame(this.render);\n }\n\n if (this.rafId !== null && newSpeed === 0) {\n // Moving from animating to not animating, cancel the rAF loop\n cancelAnimationFrame(this.rafId);\n this.rafId = null;\n }\n };\n\n /** Set the maximum pixel count for the shader, this will limit the number of pixels that will be rendered */\n public setMaxPixelCount = (newMaxPixelCount: number = DEFAULT_MAX_PIXEL_COUNT): void => {\n this.maxPixelCount = newMaxPixelCount;\n\n this.handleResize();\n };\n\n /** Set the minimum pixel ratio for the shader */\n public setMinPixelRatio = (newMinPixelRatio: number = 2): void => {\n this.minPixelRatio = newMinPixelRatio;\n\n this.handleResize();\n };\n\n /** Update the uniforms that are provided by the outside shader, can be a partial set with only the uniforms that have changed */\n public setUniforms = (newUniforms: ShaderMountUniforms): void => {\n this.setUniformValues(newUniforms);\n this.providedUniforms = { ...this.providedUniforms, ...newUniforms };\n\n this.render(performance.now());\n };\n\n private handleDocumentVisibilityChange = () => {\n this.updateCurrentSpeed();\n };\n\n /** Dispose of the shader mount, cleaning up all of the WebGL resources */\n public dispose = (): void => {\n // Immediately mark as disposed to prevent future renders from leaking in\n this.hasBeenDisposed = true;\n\n // Cancel the rAF loop\n if (this.rafId !== null) {\n cancelAnimationFrame(this.rafId);\n this.rafId = null;\n }\n\n if (this.gl && this.program) {\n // Clean up all textures\n this.textures.forEach((texture) => {\n this.gl.deleteTexture(texture);\n });\n this.textures.clear();\n\n this.gl.deleteProgram(this.program);\n this.program = null;\n\n // Reset the WebGL context\n this.gl.bindBuffer(this.gl.ARRAY_BUFFER, null);\n this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, null);\n this.gl.bindRenderbuffer(this.gl.RENDERBUFFER, null);\n this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, null);\n\n // Clear any errors\n this.gl.getError();\n }\n\n if (this.resizeObserver) {\n this.resizeObserver.disconnect();\n this.resizeObserver = null;\n }\n\n if (this.intersectionObserver) {\n this.intersectionObserver.disconnect();\n this.intersectionObserver = null;\n }\n\n visualViewport?.removeEventListener('resize', this.handleVisualViewportChange);\n this.ownerDocument.removeEventListener('visibilitychange', this.handleDocumentVisibilityChange);\n\n this.uniformLocations = {};\n\n // Remove the shader from the div wrapper element\n this.canvasElement.remove();\n // Free up the reference to self to enable garbage collection\n delete this.parentElement.paperShaderMount;\n };\n}\n\nfunction createShader(gl: WebGL2RenderingContext, type: number, source: string): WebGLShader | null {\n const shader = gl.createShader(type);\n if (!shader) return null;\n\n gl.shaderSource(shader, source);\n gl.compileShader(shader);\n\n if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {\n console.error('An error occurred compiling the shaders: ' + gl.getShaderInfoLog(shader));\n gl.deleteShader(shader);\n return null;\n }\n\n return shader;\n}\n\nfunction createProgram(\n gl: WebGL2RenderingContext,\n vertexShaderSource: string,\n fragmentShaderSource: string\n): WebGLProgram | null {\n const format = gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT);\n const precision = format ? format.precision : null;\n // MEDIUM_FLOAT precision can be 10, 16 or 23 bits depending on device;\n // Shaders fail on 10 bit (and 16 bit is hard to test) => we force 23-bit by switching to highp\n if (precision && precision < 23) {\n vertexShaderSource = vertexShaderSource.replace(/precision\\s+(lowp|mediump)\\s+float;/g, 'precision highp float;');\n fragmentShaderSource = fragmentShaderSource\n .replace(/precision\\s+(lowp|mediump)\\s+float/g, 'precision highp float')\n .replace(/\\b(uniform|varying|attribute)\\s+(lowp|mediump)\\s+(\\w+)/g, '$1 highp $3');\n }\n\n const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource);\n const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);\n\n if (!vertexShader || !fragmentShader) return null;\n\n const program = gl.createProgram();\n if (!program) return null;\n\n gl.attachShader(program, vertexShader);\n gl.attachShader(program, fragmentShader);\n gl.linkProgram(program);\n\n if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {\n console.error('Unable to initialize the shader program: ' + gl.getProgramInfoLog(program));\n gl.deleteProgram(program);\n gl.deleteShader(vertexShader);\n gl.deleteShader(fragmentShader);\n return null;\n }\n\n // Clean up shaders after successful linking\n gl.detachShader(program, vertexShader);\n gl.detachShader(program, fragmentShader);\n gl.deleteShader(vertexShader);\n gl.deleteShader(fragmentShader);\n\n return program;\n}\n\nconst defaultStyle = `@layer paper-shaders {\n :where([data-paper-shader]) {\n isolation: isolate;\n position: relative;\n\n & canvas {\n contain: strict;\n display: block;\n position: absolute;\n inset: 0;\n z-index: -1;\n width: 100%;\n height: 100%;\n border-radius: inherit;\n corner-shape: inherit;\n }\n }\n}`;\n\n/** The parent `
      ` element that has a ShaderMount available on it */\nexport interface PaperShaderElement extends HTMLElement {\n paperShaderMount: ShaderMount | undefined;\n}\n\n/** Check if an element is a Paper shader element */\nexport function isPaperShaderElement(element: HTMLElement): element is PaperShaderElement {\n return 'paperShaderMount' in element;\n}\n\n/**\n * Uniform types that we support to be auto-mapped into the fragment shader\n *\n * We accept undefined as a convenience for server rendering, when some things may be undefined\n * We just skip setting the uniform if it's undefined. This allows the shader mount to still take up space during server rendering\n */\nexport interface ShaderMountUniforms {\n [key: string]: boolean | number | number[] | number[][] | HTMLImageElement | undefined;\n}\n\nexport interface ShaderMotionParams {\n speed?: number;\n frame?: number;\n}\n\nexport type ShaderPreset = {\n name: string;\n params: Required;\n};\n\nexport type ImageShaderPreset = {\n name: string;\n /**\n * Params for the shader excluding the image.\n * Image is excluded as it isn't considered a preset,\n * e.g. when switching between presets it shouldn't switch the image.\n *\n * While we exclude images from presets they should still be set with a default prop value so the code-first usage of shaders remains great.\n */\n params: Required>;\n};\n\nfunction isSafari() {\n const ua = navigator.userAgent.toLowerCase();\n return ua.includes('safari') && !ua.includes('chrome') && !ua.includes('android');\n}\n\n// Zoom level can be estimated comparing the browser's outerWidth and the viewport width.\n// It's nowhere near perfect because it's affected by the presence of browser sidebars,\n// like a vertical web inspector or Arc's sidebar. Also, both outerWidth and innerWidth\n// are integers, which would almost never give us a perfect ratio at face values.\n//\n// Still, this is pretty accurate in the vast majority of cases.\n//\n// Note 1:\n// Avoid innerWidth, use visualViewport.width instead.\n// - innerWidth is affected by pinch zoom in Safari, but not other browsers.\n// visualViewport.width works consistently in all browsers.\n// - innerWidth is rounded to integer, but not visualViewport.width.\n// - visualViewport.width is affected by hard scrollbars, so they need to be added manually\n//\n// Note 2:\n// Opening a sidebar in Safari like web inspector or bookmarks will throw off the zoom\n// level detection and result in a larger target resolution. Not a concern in real-world usage\n// with Safari, but we'd rather not try to detect zoom levels with other browsers\n// (e.g. Arc always has a sidebar, which affects outerWidth vs visualViewport.width).\nfunction bestGuessBrowserZoom(doc: Document) {\n const viewportScale = visualViewport?.scale ?? 1;\n const viewportWidth = visualViewport?.width ?? window.innerWidth;\n const scrollbarWidth = window.innerWidth - doc.documentElement.clientWidth;\n const innerWidth = viewportScale * viewportWidth + scrollbarWidth;\n\n // outerWidth and innerWidth are always integers so we won't often get the original zoom ratio\n // E.g. given a 125% zoom, outerWidth = 1657, innerWidth = 1325, 1657 / 1325 = 1.2505660377\n // We check for common zoom levels and return the closest one if found.\n\n const ratio = outerWidth / innerWidth;\n const zoomPercentageRounded = Math.round(100 * ratio);\n\n // All zoom levels divisible by 5%\n if (zoomPercentageRounded % 5 === 0) {\n return zoomPercentageRounded / 100;\n }\n\n // 33% zoom\n if (zoomPercentageRounded === 33) {\n return 1 / 3;\n }\n\n // 67% zoom\n if (zoomPercentageRounded === 67) {\n return 2 / 3;\n }\n\n // 133% zoom\n if (zoomPercentageRounded === 133) {\n return 4 / 3;\n }\n\n return ratio;\n}\n"], + "mappings": "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", + "names": ["vertexShaderSource"] +} diff --git a/public/vendor/paper-shaders/shader-sizing.d.ts b/public/vendor/paper-shaders/shader-sizing.d.ts new file mode 100644 index 0000000..5640031 --- /dev/null +++ b/public/vendor/paper-shaders/shader-sizing.d.ts @@ -0,0 +1,30 @@ +export interface ShaderSizingUniforms { + u_fit: (typeof ShaderFitOptions)[ShaderFit]; + u_scale: number; + u_rotation: number; + u_originX: number; + u_originY: number; + u_offsetX: number; + u_offsetY: number; + u_worldWidth: number; + u_worldHeight: number; +} +export interface ShaderSizingParams { + fit?: 'none' | 'contain' | 'cover'; + scale?: number; + rotation?: number; + originX?: number; + originY?: number; + offsetX?: number; + offsetY?: number; + worldWidth?: number; + worldHeight?: number; +} +export declare const defaultObjectSizing: Required; +export declare const defaultPatternSizing: Required; +export declare const ShaderFitOptions: { + readonly none: 0; + readonly contain: 1; + readonly cover: 2; +}; +export type ShaderFit = keyof typeof ShaderFitOptions; diff --git a/public/vendor/paper-shaders/shader-sizing.js b/public/vendor/paper-shaders/shader-sizing.js new file mode 100644 index 0000000..bf7a798 --- /dev/null +++ b/public/vendor/paper-shaders/shader-sizing.js @@ -0,0 +1,38 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Paper Shaders * + * https://github.com/paper-design/shaders * + * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +const defaultObjectSizing = { + fit: "contain", + scale: 1, + rotation: 0, + offsetX: 0, + offsetY: 0, + originX: 0.5, + originY: 0.5, + worldWidth: 0, + worldHeight: 0 +}; +const defaultPatternSizing = { + fit: "none", + scale: 1, + rotation: 0, + offsetX: 0, + offsetY: 0, + originX: 0.5, + originY: 0.5, + worldWidth: 0, + worldHeight: 0 +}; +const ShaderFitOptions = { + none: 0, + contain: 1, + cover: 2 +}; +export { + ShaderFitOptions, + defaultObjectSizing, + defaultPatternSizing +}; +//# sourceMappingURL=shader-sizing.js.map diff --git a/public/vendor/paper-shaders/shader-sizing.js.map b/public/vendor/paper-shaders/shader-sizing.js.map new file mode 100644 index 0000000..a082fe9 --- /dev/null +++ b/public/vendor/paper-shaders/shader-sizing.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../src/shader-sizing.ts"], + "sourcesContent": ["export interface ShaderSizingUniforms {\n u_fit: (typeof ShaderFitOptions)[ShaderFit];\n u_scale: number;\n u_rotation: number;\n u_originX: number;\n u_originY: number;\n u_offsetX: number;\n u_offsetY: number;\n u_worldWidth: number;\n u_worldHeight: number;\n}\n\nexport interface ShaderSizingParams {\n fit?: 'none' | 'contain' | 'cover';\n scale?: number;\n rotation?: number;\n originX?: number;\n originY?: number;\n offsetX?: number;\n offsetY?: number;\n worldWidth?: number;\n worldHeight?: number;\n}\n\nexport const defaultObjectSizing: Required = {\n fit: 'contain',\n scale: 1,\n rotation: 0,\n offsetX: 0,\n offsetY: 0,\n originX: 0.5,\n originY: 0.5,\n worldWidth: 0,\n worldHeight: 0,\n};\n\nexport const defaultPatternSizing: Required = {\n fit: 'none',\n scale: 1,\n rotation: 0,\n offsetX: 0,\n offsetY: 0,\n originX: 0.5,\n originY: 0.5,\n worldWidth: 0,\n worldHeight: 0,\n};\n\nexport const ShaderFitOptions = {\n none: 0,\n contain: 1,\n cover: 2,\n} as const;\n\nexport type ShaderFit = keyof typeof ShaderFitOptions;\n"], + "mappings": ";;;;;AAwBO,MAAM,sBAAoD;AAAA,EAC/D,KAAK;AAAA,EACL,OAAO;AAAA,EACP,UAAU;AAAA,EACV,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,aAAa;AACf;AAEO,MAAM,uBAAqD;AAAA,EAChE,KAAK;AAAA,EACL,OAAO;AAAA,EACP,UAAU;AAAA,EACV,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,aAAa;AACf;AAEO,MAAM,mBAAmB;AAAA,EAC9B,MAAM;AAAA,EACN,SAAS;AAAA,EACT,OAAO;AACT;", + "names": [] +} diff --git a/public/vendor/paper-shaders/shader-utils.d.ts b/public/vendor/paper-shaders/shader-utils.d.ts new file mode 100644 index 0000000..07a242b --- /dev/null +++ b/public/vendor/paper-shaders/shader-utils.d.ts @@ -0,0 +1,10 @@ +export declare const declarePI = "\n#define TWO_PI 6.28318530718\n#define PI 3.14159265358979323846\n"; +export declare const rotation2 = "\nvec2 rotate(vec2 uv, float th) {\n return mat2(cos(th), sin(th), -sin(th), cos(th)) * uv;\n}\n"; +export declare const proceduralHash11 = "\n float hash11(float p) {\n p = fract(p * 0.3183099) + 0.1;\n p *= p + 19.19;\n return fract(p * p);\n }\n"; +export declare const proceduralHash21 = "\n float hash21(vec2 p) {\n p = fract(p * vec2(0.3183099, 0.3678794)) + 0.1;\n p += dot(p, p + 19.19);\n return fract(p.x * p.y);\n }\n"; +export declare const proceduralHash22 = "\n vec2 hash22(vec2 p) {\n p = fract(p * vec2(0.3183099, 0.3678794)) + 0.1;\n p += dot(p, p.yx + 19.19);\n return fract(vec2(p.x * p.y, p.x + p.y));\n }\n"; +export declare const textureRandomizerR = "\n float randomR(vec2 p) {\n vec2 uv = floor(p) / 100. + .5;\n return texture(u_noiseTexture, fract(uv)).r;\n }\n"; +export declare const textureRandomizerGB = "\n vec2 randomGB(vec2 p) {\n vec2 uv = floor(p) / 100. + .5;\n return texture(u_noiseTexture, fract(uv)).gb;\n }\n"; +export declare const colorBandingFix = "\n color += 1. / 256. * (fract(sin(dot(.014 * gl_FragCoord.xy, vec2(12.9898, 78.233))) * 43758.5453123) - .5);\n"; +export declare const simplexNoise = "\nvec3 permute(vec3 x) { return mod(((x * 34.0) + 1.0) * x, 289.0); }\nfloat snoise(vec2 v) {\n const vec4 C = vec4(0.211324865405187, 0.366025403784439,\n -0.577350269189626, 0.024390243902439);\n vec2 i = floor(v + dot(v, C.yy));\n vec2 x0 = v - i + dot(i, C.xx);\n vec2 i1;\n i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);\n vec4 x12 = x0.xyxy + C.xxzz;\n x12.xy -= i1;\n i = mod(i, 289.0);\n vec3 p = permute(permute(i.y + vec3(0.0, i1.y, 1.0))\n + i.x + vec3(0.0, i1.x, 1.0));\n vec3 m = max(0.5 - vec3(dot(x0, x0), dot(x12.xy, x12.xy),\n dot(x12.zw, x12.zw)), 0.0);\n m = m * m;\n m = m * m;\n vec3 x = 2.0 * fract(p * C.www) - 1.0;\n vec3 h = abs(x) - 0.5;\n vec3 ox = floor(x + 0.5);\n vec3 a0 = x - ox;\n m *= 1.79284291400159 - 0.85373472095314 * (a0 * a0 + h * h);\n vec3 g;\n g.x = a0.x * x0.x + h.x * x0.y;\n g.yz = a0.yz * x12.xz + h.yz * x12.yw;\n return 130.0 * dot(m, g);\n}\n"; +export declare const fiberNoise = "\nfloat fiberRandom(vec2 p) {\n vec2 uv = floor(p) / 100.;\n return texture(u_noiseTexture, fract(uv)).b;\n}\n\nfloat fiberValueNoise(vec2 st) {\n vec2 i = floor(st);\n vec2 f = fract(st);\n float a = fiberRandom(i);\n float b = fiberRandom(i + vec2(1.0, 0.0));\n float c = fiberRandom(i + vec2(0.0, 1.0));\n float d = fiberRandom(i + vec2(1.0, 1.0));\n vec2 u = f * f * (3.0 - 2.0 * f);\n float x1 = mix(a, b, u.x);\n float x2 = mix(c, d, u.x);\n return mix(x1, x2, u.y);\n}\n\nfloat fiberNoiseFbm(in vec2 n, vec2 seedOffset) {\n float total = 0.0, amplitude = 1.;\n for (int i = 0; i < 4; i++) {\n n = rotate(n, .7);\n total += fiberValueNoise(n + seedOffset) * amplitude;\n n *= 2.;\n amplitude *= 0.6;\n }\n return total;\n}\n\nfloat fiberNoise(vec2 uv, vec2 seedOffset) {\n float epsilon = 0.001;\n float n1 = fiberNoiseFbm(uv + vec2(epsilon, 0.0), seedOffset);\n float n2 = fiberNoiseFbm(uv - vec2(epsilon, 0.0), seedOffset);\n float n3 = fiberNoiseFbm(uv + vec2(0.0, epsilon), seedOffset);\n float n4 = fiberNoiseFbm(uv - vec2(0.0, epsilon), seedOffset);\n return length(vec2(n1 - n2, n3 - n4)) / (2.0 * epsilon);\n}\n"; diff --git a/public/vendor/paper-shaders/shader-utils.js b/public/vendor/paper-shaders/shader-utils.js new file mode 100644 index 0000000..262fcd4 --- /dev/null +++ b/public/vendor/paper-shaders/shader-utils.js @@ -0,0 +1,131 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Paper Shaders * + * https://github.com/paper-design/shaders * + * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +const declarePI = ` +#define TWO_PI 6.28318530718 +#define PI 3.14159265358979323846 +`; +const rotation2 = ` +vec2 rotate(vec2 uv, float th) { + return mat2(cos(th), sin(th), -sin(th), cos(th)) * uv; +} +`; +const proceduralHash11 = ` + float hash11(float p) { + p = fract(p * 0.3183099) + 0.1; + p *= p + 19.19; + return fract(p * p); + } +`; +const proceduralHash21 = ` + float hash21(vec2 p) { + p = fract(p * vec2(0.3183099, 0.3678794)) + 0.1; + p += dot(p, p + 19.19); + return fract(p.x * p.y); + } +`; +const proceduralHash22 = ` + vec2 hash22(vec2 p) { + p = fract(p * vec2(0.3183099, 0.3678794)) + 0.1; + p += dot(p, p.yx + 19.19); + return fract(vec2(p.x * p.y, p.x + p.y)); + } +`; +const textureRandomizerR = ` + float randomR(vec2 p) { + vec2 uv = floor(p) / 100. + .5; + return texture(u_noiseTexture, fract(uv)).r; + } +`; +const textureRandomizerGB = ` + vec2 randomGB(vec2 p) { + vec2 uv = floor(p) / 100. + .5; + return texture(u_noiseTexture, fract(uv)).gb; + } +`; +const colorBandingFix = ` + color += 1. / 256. * (fract(sin(dot(.014 * gl_FragCoord.xy, vec2(12.9898, 78.233))) * 43758.5453123) - .5); +`; +const simplexNoise = ` +vec3 permute(vec3 x) { return mod(((x * 34.0) + 1.0) * x, 289.0); } +float snoise(vec2 v) { + const vec4 C = vec4(0.211324865405187, 0.366025403784439, + -0.577350269189626, 0.024390243902439); + vec2 i = floor(v + dot(v, C.yy)); + vec2 x0 = v - i + dot(i, C.xx); + vec2 i1; + i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0); + vec4 x12 = x0.xyxy + C.xxzz; + x12.xy -= i1; + i = mod(i, 289.0); + vec3 p = permute(permute(i.y + vec3(0.0, i1.y, 1.0)) + + i.x + vec3(0.0, i1.x, 1.0)); + vec3 m = max(0.5 - vec3(dot(x0, x0), dot(x12.xy, x12.xy), + dot(x12.zw, x12.zw)), 0.0); + m = m * m; + m = m * m; + vec3 x = 2.0 * fract(p * C.www) - 1.0; + vec3 h = abs(x) - 0.5; + vec3 ox = floor(x + 0.5); + vec3 a0 = x - ox; + m *= 1.79284291400159 - 0.85373472095314 * (a0 * a0 + h * h); + vec3 g; + g.x = a0.x * x0.x + h.x * x0.y; + g.yz = a0.yz * x12.xz + h.yz * x12.yw; + return 130.0 * dot(m, g); +} +`; +const fiberNoise = ` +float fiberRandom(vec2 p) { + vec2 uv = floor(p) / 100.; + return texture(u_noiseTexture, fract(uv)).b; +} + +float fiberValueNoise(vec2 st) { + vec2 i = floor(st); + vec2 f = fract(st); + float a = fiberRandom(i); + float b = fiberRandom(i + vec2(1.0, 0.0)); + float c = fiberRandom(i + vec2(0.0, 1.0)); + float d = fiberRandom(i + vec2(1.0, 1.0)); + vec2 u = f * f * (3.0 - 2.0 * f); + float x1 = mix(a, b, u.x); + float x2 = mix(c, d, u.x); + return mix(x1, x2, u.y); +} + +float fiberNoiseFbm(in vec2 n, vec2 seedOffset) { + float total = 0.0, amplitude = 1.; + for (int i = 0; i < 4; i++) { + n = rotate(n, .7); + total += fiberValueNoise(n + seedOffset) * amplitude; + n *= 2.; + amplitude *= 0.6; + } + return total; +} + +float fiberNoise(vec2 uv, vec2 seedOffset) { + float epsilon = 0.001; + float n1 = fiberNoiseFbm(uv + vec2(epsilon, 0.0), seedOffset); + float n2 = fiberNoiseFbm(uv - vec2(epsilon, 0.0), seedOffset); + float n3 = fiberNoiseFbm(uv + vec2(0.0, epsilon), seedOffset); + float n4 = fiberNoiseFbm(uv - vec2(0.0, epsilon), seedOffset); + return length(vec2(n1 - n2, n3 - n4)) / (2.0 * epsilon); +} +`; +export { + colorBandingFix, + declarePI, + fiberNoise, + proceduralHash11, + proceduralHash21, + proceduralHash22, + rotation2, + simplexNoise, + textureRandomizerGB, + textureRandomizerR +}; +//# sourceMappingURL=shader-utils.js.map diff --git a/public/vendor/paper-shaders/shader-utils.js.map b/public/vendor/paper-shaders/shader-utils.js.map new file mode 100644 index 0000000..d0cdc67 --- /dev/null +++ b/public/vendor/paper-shaders/shader-utils.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../src/shader-utils.ts"], + "sourcesContent": ["// language=GLSL\nexport const declarePI = `\n#define TWO_PI 6.28318530718\n#define PI 3.14159265358979323846\n`;\n\n// language=GLSL\nexport const rotation2 = `\nvec2 rotate(vec2 uv, float th) {\n return mat2(cos(th), sin(th), -sin(th), cos(th)) * uv;\n}\n`;\n\n// language=GLSL\nexport const proceduralHash11 = `\n float hash11(float p) {\n p = fract(p * 0.3183099) + 0.1;\n p *= p + 19.19;\n return fract(p * p);\n }\n`;\n\n// language=GLSL\nexport const proceduralHash21 = `\n float hash21(vec2 p) {\n p = fract(p * vec2(0.3183099, 0.3678794)) + 0.1;\n p += dot(p, p + 19.19);\n return fract(p.x * p.y);\n }\n`;\n\n// language=GLSL\nexport const proceduralHash22 = `\n vec2 hash22(vec2 p) {\n p = fract(p * vec2(0.3183099, 0.3678794)) + 0.1;\n p += dot(p, p.yx + 19.19);\n return fract(vec2(p.x * p.y, p.x + p.y));\n }\n`;\n\n// language=GLSL\nexport const textureRandomizerR = `\n float randomR(vec2 p) {\n vec2 uv = floor(p) / 100. + .5;\n return texture(u_noiseTexture, fract(uv)).r;\n }\n`;\n\n// language=GLSL\nexport const textureRandomizerGB = `\n vec2 randomGB(vec2 p) {\n vec2 uv = floor(p) / 100. + .5;\n return texture(u_noiseTexture, fract(uv)).gb;\n }\n`;\n\n// language=GLSL\nexport const colorBandingFix = `\n color += 1. / 256. * (fract(sin(dot(.014 * gl_FragCoord.xy, vec2(12.9898, 78.233))) * 43758.5453123) - .5);\n`;\n\n// language=GLSL\nexport const simplexNoise = `\nvec3 permute(vec3 x) { return mod(((x * 34.0) + 1.0) * x, 289.0); }\nfloat snoise(vec2 v) {\n const vec4 C = vec4(0.211324865405187, 0.366025403784439,\n -0.577350269189626, 0.024390243902439);\n vec2 i = floor(v + dot(v, C.yy));\n vec2 x0 = v - i + dot(i, C.xx);\n vec2 i1;\n i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);\n vec4 x12 = x0.xyxy + C.xxzz;\n x12.xy -= i1;\n i = mod(i, 289.0);\n vec3 p = permute(permute(i.y + vec3(0.0, i1.y, 1.0))\n + i.x + vec3(0.0, i1.x, 1.0));\n vec3 m = max(0.5 - vec3(dot(x0, x0), dot(x12.xy, x12.xy),\n dot(x12.zw, x12.zw)), 0.0);\n m = m * m;\n m = m * m;\n vec3 x = 2.0 * fract(p * C.www) - 1.0;\n vec3 h = abs(x) - 0.5;\n vec3 ox = floor(x + 0.5);\n vec3 a0 = x - ox;\n m *= 1.79284291400159 - 0.85373472095314 * (a0 * a0 + h * h);\n vec3 g;\n g.x = a0.x * x0.x + h.x * x0.y;\n g.yz = a0.yz * x12.xz + h.yz * x12.yw;\n return 130.0 * dot(m, g);\n}\n`;\n\n// language=GLSL\nexport const fiberNoise = `\nfloat fiberRandom(vec2 p) {\n vec2 uv = floor(p) / 100.;\n return texture(u_noiseTexture, fract(uv)).b;\n}\n\nfloat fiberValueNoise(vec2 st) {\n vec2 i = floor(st);\n vec2 f = fract(st);\n float a = fiberRandom(i);\n float b = fiberRandom(i + vec2(1.0, 0.0));\n float c = fiberRandom(i + vec2(0.0, 1.0));\n float d = fiberRandom(i + vec2(1.0, 1.0));\n vec2 u = f * f * (3.0 - 2.0 * f);\n float x1 = mix(a, b, u.x);\n float x2 = mix(c, d, u.x);\n return mix(x1, x2, u.y);\n}\n\nfloat fiberNoiseFbm(in vec2 n, vec2 seedOffset) {\n float total = 0.0, amplitude = 1.;\n for (int i = 0; i < 4; i++) {\n n = rotate(n, .7);\n total += fiberValueNoise(n + seedOffset) * amplitude;\n n *= 2.;\n amplitude *= 0.6;\n }\n return total;\n}\n\nfloat fiberNoise(vec2 uv, vec2 seedOffset) {\n float epsilon = 0.001;\n float n1 = fiberNoiseFbm(uv + vec2(epsilon, 0.0), seedOffset);\n float n2 = fiberNoiseFbm(uv - vec2(epsilon, 0.0), seedOffset);\n float n3 = fiberNoiseFbm(uv + vec2(0.0, epsilon), seedOffset);\n float n4 = fiberNoiseFbm(uv - vec2(0.0, epsilon), seedOffset);\n return length(vec2(n1 - n2, n3 - n4)) / (2.0 * epsilon);\n}\n`;\n"], + "mappings": ";;;;;AACO,MAAM,YAAY;AAAA;AAAA;AAAA;AAMlB,MAAM,YAAY;AAAA;AAAA;AAAA;AAAA;AAOlB,MAAM,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASzB,MAAM,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASzB,MAAM,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASzB,MAAM,qBAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAQ3B,MAAM,sBAAsB;AAAA;AAAA;AAAA;AAAA;AAAA;AAQ5B,MAAM,kBAAkB;AAAA;AAAA;AAKxB,MAAM,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA+BrB,MAAM,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;", + "names": [] +} diff --git a/public/vendor/paper-shaders/shaders/color-panels.d.ts b/public/vendor/paper-shaders/shaders/color-panels.d.ts new file mode 100644 index 0000000..20868f1 --- /dev/null +++ b/public/vendor/paper-shaders/shaders/color-panels.d.ts @@ -0,0 +1,70 @@ +import type { vec4 } from '../types.js'; +import type { ShaderMotionParams } from '../shader-mount.js'; +import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js'; +export declare const colorPanelsMeta: { + readonly maxColorCount: 7; +}; +/** + * Pseudo-3D semi-transparent panels rotating around a central axis + * + * Fragment shader uniforms: + * - u_time (float): Animation time + * - u_scale (float): Overall zoom level, used for anti-aliasing calculations + * - u_colors (vec4[]): Up to 7 RGBA colors used to color the panels + * - u_colorsCount (float): Number of active colors + * - u_colorBack (vec4): Background color in RGBA + * - u_density (float): Angle between every 2 panels (0.25 to 7) + * - u_angle1 (float): Skew angle applied to all panes (-1 to 1) + * - u_angle2 (float): Skew angle applied to all panes (-1 to 1) + * - u_length (float): Panel length relative to total height (0 to 3) + * - u_edges (bool): Color highlight on the panels edges + * - u_blur (float): Side blur, 0 for sharp edges (0 to 0.5) + * - u_fadeIn (float): Transparency near central axis (0 to 1) + * - u_fadeOut (float): Transparency near viewer (0 to 1) + * - u_gradient (float): Color mixing within a panel, 0 = solid, 1 = gradient (0 to 1) + * + * Vertex shader outputs (used in fragment shader): + * - v_objectUV (vec2): Object box UV coordinates with global sizing (scale, rotation, offsets, etc) applied + * + * Vertex shader uniforms: + * - u_resolution (vec2): Canvas resolution in pixels + * - u_pixelRatio (float): Device pixel ratio + * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1) + * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1) + * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas + * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas + * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover) + * - u_scale (float): Overall zoom level of the graphics (0.01 to 4) + * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360) + * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1) + * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1) + * + */ +export declare const colorPanelsFragmentShader: string; +export interface ColorPanelsUniforms extends ShaderSizingUniforms { + u_colors: vec4[]; + u_colorsCount: number; + u_colorBack: [number, number, number, number]; + u_angle1: number; + u_angle2: number; + u_length: number; + u_edges: boolean; + u_blur: number; + u_fadeIn: number; + u_fadeOut: number; + u_density: number; + u_gradient: number; +} +export interface ColorPanelsParams extends ShaderSizingParams, ShaderMotionParams { + colors?: string[]; + colorBack?: string; + angle1?: number; + angle2?: number; + length?: number; + edges?: boolean; + blur?: number; + fadeIn?: number; + fadeOut?: number; + density?: number; + gradient?: number; +} diff --git a/public/vendor/paper-shaders/shaders/color-panels.js b/public/vendor/paper-shaders/shaders/color-panels.js new file mode 100644 index 0000000..ed8fcbd --- /dev/null +++ b/public/vendor/paper-shaders/shaders/color-panels.js @@ -0,0 +1,224 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Paper Shaders * + * https://github.com/paper-design/shaders * + * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +import {} from "../shader-sizing.js"; +import { declarePI, colorBandingFix } from "../shader-utils.js"; +const colorPanelsMeta = { + maxColorCount: 7 +}; +const colorPanelsFragmentShader = `#version 300 es +precision lowp float; + +uniform float u_time; +uniform mediump float u_scale; + +uniform vec4 u_colors[${colorPanelsMeta.maxColorCount}]; +uniform float u_colorsCount; +uniform vec4 u_colorBack; +uniform float u_density; +uniform float u_angle1; +uniform float u_angle2; +uniform float u_length; +uniform bool u_edges; +uniform float u_blur; +uniform float u_fadeIn; +uniform float u_fadeOut; +uniform float u_gradient; + +in vec2 v_objectUV; + +out vec4 fragColor; + +${declarePI} + +const float zLimit = .5; + +vec2 getPanel(float angle, vec2 uv, float invLength, float aa) { + float sinA = sin(angle); + float cosA = cos(angle); + + float denom = sinA - uv.y * cosA; + if (abs(denom) < .01) return vec2(0.); + + float z = uv.y / denom; + + if (z <= 0. || z > zLimit) return vec2(0.); + + float zRatio = z / zLimit; + float panelMap = 1. - zRatio; + float x = uv.x * (cosA * z + 1.) * invLength; + + float zOffset = zRatio - .5; + float left = -.5 + zOffset * u_angle1; + float right = .5 - zOffset * u_angle2; + float blurX = aa + 2. * panelMap * u_blur; + + float leftEdge1 = left - blurX; + float leftEdge2 = left + .25 * blurX; + float rightEdge1 = right - .25 * blurX; + float rightEdge2 = right + blurX; + + float panel = smoothstep(leftEdge1, leftEdge2, x) * (1.0 - smoothstep(rightEdge1, rightEdge2, x)); + panel *= mix(0., panel, smoothstep(0., .01 / max(u_scale, 1e-6), panelMap)); + + float midScreen = abs(sinA); + if (u_edges == true) { + panelMap = mix(.99, panelMap, panel * clamp(panelMap / (.15 * (1. - pow(midScreen, .1))), 0.0, 1.0)); + } else if (midScreen < .07) { + panel *= (midScreen * 15.); + } + + return vec2(panel, panelMap); +} + +vec4 blendColor(vec4 colorA, float panelMask, float panelMap) { + float fade = 1. - smoothstep(.97 - .97 * u_fadeIn, 1., panelMap); + + fade *= smoothstep(-.2 * (1. - u_fadeOut), u_fadeOut, panelMap); + + vec3 blendedRGB = mix(vec3(0.), colorA.rgb, fade); + float blendedAlpha = mix(0., colorA.a, fade); + + return vec4(blendedRGB, blendedAlpha) * panelMask; +} + +void main() { + vec2 uv = v_objectUV; + uv *= 1.25; + + float t = .02 * u_time; + t = fract(t); + bool reverseTime = (t < 0.5); + + vec3 color = vec3(0.); + float opacity = 0.; + + float aa = .005 / u_scale; + int colorsCount = int(u_colorsCount); + + vec4 premultipliedColors[${colorPanelsMeta.maxColorCount}]; + for (int i = 0; i < ${colorPanelsMeta.maxColorCount}; i++) { + if (i >= colorsCount) break; + vec4 c = u_colors[i]; + c.rgb *= c.a; + premultipliedColors[i] = c; + } + + float invLength = 1.5 / max(u_length, .001); + + float totalColorWeight = 0.; + int panelsNumber = 12; + + float densityNormalizer = 1.; + if (colorsCount == 4) { + panelsNumber = 16; + densityNormalizer = 1.34; + } else if (colorsCount == 5) { + panelsNumber = 20; + densityNormalizer = 1.67; + } else if (colorsCount == 7) { + panelsNumber = 14; + densityNormalizer = 1.17; + } + + float fPanelsNumber = float(panelsNumber); + + float totalPanelsShape = 0.; + float panelGrad = 1. - clamp(u_gradient, 0., 1.); + + for (int set = 0; set < 2; set++) { + bool isForward = (set == 0 && !reverseTime) || (set == 1 && reverseTime); + if (!isForward) continue; + + for (int i = 0; i <= 20; i++) { + if (i >= panelsNumber) break; + + int idx = panelsNumber - 1 - i; + + float offset = float(idx) / fPanelsNumber; + if (set == 1) { + offset += .5; + } + + float densityFract = densityNormalizer * fract(t + offset); + float angleNorm = densityFract / u_density; + if (densityFract >= .5 || angleNorm >= .3) continue; + + float smoothDensity = clamp((.5 - densityFract) / .1, 0., 1.) * clamp(densityFract / .01, 0., 1.); + float smoothAngle = clamp((.3 - angleNorm) / .05, 0., 1.); + if (smoothDensity * smoothAngle < .001) continue; + + if (angleNorm > .5) { + angleNorm = 0.5; + } + vec2 panel = getPanel(angleNorm * TWO_PI + PI, uv, invLength, aa); + if (panel[0] <= .001) continue; + float panelMask = panel[0] * smoothDensity * smoothAngle; + float panelMap = panel[1]; + + int colorIdx = idx % colorsCount; + int nextColorIdx = (idx + 1) % colorsCount; + + vec4 colorA = premultipliedColors[colorIdx]; + vec4 colorB = premultipliedColors[nextColorIdx]; + + colorA = mix(colorA, colorB, max(0., smoothstep(.0, .45, panelMap) - panelGrad)); + vec4 blended = blendColor(colorA, panelMask, panelMap); + color = blended.rgb + color * (1. - blended.a); + opacity = blended.a + opacity * (1. - blended.a); + } + + + for (int i = 0; i <= 20; i++) { + if (i >= panelsNumber) break; + + int idx = panelsNumber - 1 - i; + + float offset = float(idx) / fPanelsNumber; + if (set == 0) { + offset += .5; + } + + float densityFract = densityNormalizer * fract(-t + offset); + float angleNorm = -densityFract / u_density; + if (densityFract >= .5 || angleNorm < -.3) continue; + + float smoothDensity = clamp((.5 - densityFract) / .1, 0., 1.) * clamp(densityFract / .01, 0., 1.); + float smoothAngle = clamp((angleNorm + .3) / .05, 0., 1.); + if (smoothDensity * smoothAngle < .001) continue; + + vec2 panel = getPanel(angleNorm * TWO_PI + PI, uv, invLength, aa); + float panelMask = panel[0] * smoothDensity * smoothAngle; + if (panelMask <= .001) continue; + float panelMap = panel[1]; + + int colorIdx = (colorsCount - (idx % colorsCount)) % colorsCount; + if (colorIdx < 0) colorIdx += colorsCount; + int nextColorIdx = (colorIdx + 1) % colorsCount; + + vec4 colorA = premultipliedColors[colorIdx]; + vec4 colorB = premultipliedColors[nextColorIdx]; + + colorA = mix(colorA, colorB, max(0., smoothstep(.0, .45, panelMap) - panelGrad)); + vec4 blended = blendColor(colorA, panelMask, panelMap); + color = blended.rgb + color * (1. - blended.a); + opacity = blended.a + opacity * (1. - blended.a); + } + } + + vec3 bgColor = u_colorBack.rgb * u_colorBack.a; + color = color + bgColor * (1.0 - opacity); + opacity = opacity + u_colorBack.a * (1.0 - opacity); + + ${colorBandingFix} + + fragColor = vec4(color, opacity); +} +`; +export { + colorPanelsFragmentShader, + colorPanelsMeta +}; +//# sourceMappingURL=color-panels.js.map diff --git a/public/vendor/paper-shaders/shaders/color-panels.js.map b/public/vendor/paper-shaders/shaders/color-panels.js.map new file mode 100644 index 0000000..286797e --- /dev/null +++ b/public/vendor/paper-shaders/shaders/color-panels.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../../src/shaders/color-panels.ts"], + "sourcesContent": ["import type { vec4 } from '../types.js';\nimport type { ShaderMotionParams } from '../shader-mount.js';\nimport { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { declarePI, colorBandingFix } from '../shader-utils.js';\n\nexport const colorPanelsMeta = {\n maxColorCount: 7,\n} as const;\n\n/**\n * Pseudo-3D semi-transparent panels rotating around a central axis\n *\n * Fragment shader uniforms:\n * - u_time (float): Animation time\n * - u_scale (float): Overall zoom level, used for anti-aliasing calculations\n * - u_colors (vec4[]): Up to 7 RGBA colors used to color the panels\n * - u_colorsCount (float): Number of active colors\n * - u_colorBack (vec4): Background color in RGBA\n * - u_density (float): Angle between every 2 panels (0.25 to 7)\n * - u_angle1 (float): Skew angle applied to all panes (-1 to 1)\n * - u_angle2 (float): Skew angle applied to all panes (-1 to 1)\n * - u_length (float): Panel length relative to total height (0 to 3)\n * - u_edges (bool): Color highlight on the panels edges\n * - u_blur (float): Side blur, 0 for sharp edges (0 to 0.5)\n * - u_fadeIn (float): Transparency near central axis (0 to 1)\n * - u_fadeOut (float): Transparency near viewer (0 to 1)\n * - u_gradient (float): Color mixing within a panel, 0 = solid, 1 = gradient (0 to 1)\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_objectUV (vec2): Object box UV coordinates with global sizing (scale, rotation, offsets, etc) applied\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n *\n */\n\n// language=GLSL\nexport const colorPanelsFragmentShader: string = `#version 300 es\nprecision lowp float;\n\nuniform float u_time;\nuniform mediump float u_scale;\n\nuniform vec4 u_colors[${ colorPanelsMeta.maxColorCount }];\nuniform float u_colorsCount;\nuniform vec4 u_colorBack;\nuniform float u_density;\nuniform float u_angle1;\nuniform float u_angle2;\nuniform float u_length;\nuniform bool u_edges;\nuniform float u_blur;\nuniform float u_fadeIn;\nuniform float u_fadeOut;\nuniform float u_gradient;\n\nin vec2 v_objectUV;\n\nout vec4 fragColor;\n\n${ declarePI }\n\nconst float zLimit = .5;\n\nvec2 getPanel(float angle, vec2 uv, float invLength, float aa) {\n float sinA = sin(angle);\n float cosA = cos(angle);\n\n float denom = sinA - uv.y * cosA;\n if (abs(denom) < .01) return vec2(0.);\n\n float z = uv.y / denom;\n\n if (z <= 0. || z > zLimit) return vec2(0.);\n\n float zRatio = z / zLimit;\n float panelMap = 1. - zRatio;\n float x = uv.x * (cosA * z + 1.) * invLength;\n\n float zOffset = zRatio - .5;\n float left = -.5 + zOffset * u_angle1;\n float right = .5 - zOffset * u_angle2;\n float blurX = aa + 2. * panelMap * u_blur;\n\n float leftEdge1 = left - blurX;\n float leftEdge2 = left + .25 * blurX;\n float rightEdge1 = right - .25 * blurX;\n float rightEdge2 = right + blurX;\n\n float panel = smoothstep(leftEdge1, leftEdge2, x) * (1.0 - smoothstep(rightEdge1, rightEdge2, x));\n panel *= mix(0., panel, smoothstep(0., .01 / max(u_scale, 1e-6), panelMap));\n\n float midScreen = abs(sinA);\n if (u_edges == true) {\n panelMap = mix(.99, panelMap, panel * clamp(panelMap / (.15 * (1. - pow(midScreen, .1))), 0.0, 1.0));\n } else if (midScreen < .07) {\n panel *= (midScreen * 15.);\n }\n\n return vec2(panel, panelMap);\n}\n\nvec4 blendColor(vec4 colorA, float panelMask, float panelMap) {\n float fade = 1. - smoothstep(.97 - .97 * u_fadeIn, 1., panelMap);\n\n fade *= smoothstep(-.2 * (1. - u_fadeOut), u_fadeOut, panelMap);\n\n vec3 blendedRGB = mix(vec3(0.), colorA.rgb, fade);\n float blendedAlpha = mix(0., colorA.a, fade);\n\n return vec4(blendedRGB, blendedAlpha) * panelMask;\n}\n\nvoid main() {\n vec2 uv = v_objectUV;\n uv *= 1.25;\n\n float t = .02 * u_time;\n t = fract(t);\n bool reverseTime = (t < 0.5);\n\n vec3 color = vec3(0.);\n float opacity = 0.;\n\n float aa = .005 / u_scale;\n int colorsCount = int(u_colorsCount);\n\n vec4 premultipliedColors[${ colorPanelsMeta.maxColorCount }];\n for (int i = 0; i < ${ colorPanelsMeta.maxColorCount }; i++) {\n if (i >= colorsCount) break;\n vec4 c = u_colors[i];\n c.rgb *= c.a;\n premultipliedColors[i] = c;\n }\n\n float invLength = 1.5 / max(u_length, .001);\n\n float totalColorWeight = 0.;\n int panelsNumber = 12;\n\n float densityNormalizer = 1.;\n if (colorsCount == 4) {\n panelsNumber = 16;\n densityNormalizer = 1.34;\n } else if (colorsCount == 5) {\n panelsNumber = 20;\n densityNormalizer = 1.67;\n } else if (colorsCount == 7) {\n panelsNumber = 14;\n densityNormalizer = 1.17;\n }\n\n float fPanelsNumber = float(panelsNumber);\n\n float totalPanelsShape = 0.;\n float panelGrad = 1. - clamp(u_gradient, 0., 1.);\n\n for (int set = 0; set < 2; set++) {\n bool isForward = (set == 0 && !reverseTime) || (set == 1 && reverseTime);\n if (!isForward) continue;\n\n for (int i = 0; i <= 20; i++) {\n if (i >= panelsNumber) break;\n\n int idx = panelsNumber - 1 - i;\n\n float offset = float(idx) / fPanelsNumber;\n if (set == 1) {\n offset += .5;\n }\n\n float densityFract = densityNormalizer * fract(t + offset);\n float angleNorm = densityFract / u_density;\n if (densityFract >= .5 || angleNorm >= .3) continue;\n\n float smoothDensity = clamp((.5 - densityFract) / .1, 0., 1.) * clamp(densityFract / .01, 0., 1.);\n float smoothAngle = clamp((.3 - angleNorm) / .05, 0., 1.);\n if (smoothDensity * smoothAngle < .001) continue;\n\n if (angleNorm > .5) {\n angleNorm = 0.5;\n }\n vec2 panel = getPanel(angleNorm * TWO_PI + PI, uv, invLength, aa);\n if (panel[0] <= .001) continue;\n float panelMask = panel[0] * smoothDensity * smoothAngle;\n float panelMap = panel[1];\n\n int colorIdx = idx % colorsCount;\n int nextColorIdx = (idx + 1) % colorsCount;\n\n vec4 colorA = premultipliedColors[colorIdx];\n vec4 colorB = premultipliedColors[nextColorIdx];\n\n colorA = mix(colorA, colorB, max(0., smoothstep(.0, .45, panelMap) - panelGrad));\n vec4 blended = blendColor(colorA, panelMask, panelMap);\n color = blended.rgb + color * (1. - blended.a);\n opacity = blended.a + opacity * (1. - blended.a);\n }\n\n\n for (int i = 0; i <= 20; i++) {\n if (i >= panelsNumber) break;\n\n int idx = panelsNumber - 1 - i;\n\n float offset = float(idx) / fPanelsNumber;\n if (set == 0) {\n offset += .5;\n }\n\n float densityFract = densityNormalizer * fract(-t + offset);\n float angleNorm = -densityFract / u_density;\n if (densityFract >= .5 || angleNorm < -.3) continue;\n\n float smoothDensity = clamp((.5 - densityFract) / .1, 0., 1.) * clamp(densityFract / .01, 0., 1.);\n float smoothAngle = clamp((angleNorm + .3) / .05, 0., 1.);\n if (smoothDensity * smoothAngle < .001) continue;\n\n vec2 panel = getPanel(angleNorm * TWO_PI + PI, uv, invLength, aa);\n float panelMask = panel[0] * smoothDensity * smoothAngle;\n if (panelMask <= .001) continue;\n float panelMap = panel[1];\n\n int colorIdx = (colorsCount - (idx % colorsCount)) % colorsCount;\n if (colorIdx < 0) colorIdx += colorsCount;\n int nextColorIdx = (colorIdx + 1) % colorsCount;\n\n vec4 colorA = premultipliedColors[colorIdx];\n vec4 colorB = premultipliedColors[nextColorIdx];\n\n colorA = mix(colorA, colorB, max(0., smoothstep(.0, .45, panelMap) - panelGrad));\n vec4 blended = blendColor(colorA, panelMask, panelMap);\n color = blended.rgb + color * (1. - blended.a);\n opacity = blended.a + opacity * (1. - blended.a);\n }\n }\n\n vec3 bgColor = u_colorBack.rgb * u_colorBack.a;\n color = color + bgColor * (1.0 - opacity);\n opacity = opacity + u_colorBack.a * (1.0 - opacity);\n\n ${ colorBandingFix }\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface ColorPanelsUniforms extends ShaderSizingUniforms {\n u_colors: vec4[];\n u_colorsCount: number;\n u_colorBack: [number, number, number, number];\n u_angle1: number;\n u_angle2: number;\n u_length: number;\n u_edges: boolean;\n u_blur: number;\n u_fadeIn: number;\n u_fadeOut: number;\n u_density: number;\n u_gradient: number;\n}\n\nexport interface ColorPanelsParams extends ShaderSizingParams, ShaderMotionParams {\n colors?: string[];\n colorBack?: string;\n angle1?: number;\n angle2?: number;\n length?: number;\n edges?: boolean;\n blur?: number;\n fadeIn?: number;\n fadeOut?: number;\n density?: number;\n gradient?: number;\n}\n"], + "mappings": ";;;;;AAEA,eAAmE;AACnE,SAAS,WAAW,uBAAuB;AAEpC,MAAM,kBAAkB;AAAA,EAC7B,eAAe;AACjB;AAwCO,MAAM,4BAAoC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAMxB,gBAAgB,aAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBpD,SAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,6BAmEiB,gBAAgB,aAAc;AAAA,wBACnC,gBAAgB,aAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAiHlD,eAAgB;AAAA;AAAA;AAAA;AAAA;", + "names": [] +} diff --git a/public/vendor/paper-shaders/shaders/dithering.d.ts b/public/vendor/paper-shaders/shaders/dithering.d.ts new file mode 100644 index 0000000..d9f8dc8 --- /dev/null +++ b/public/vendor/paper-shaders/shaders/dithering.d.ts @@ -0,0 +1,62 @@ +import type { ShaderMotionParams } from '../shader-mount.js'; +import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js'; +/** + * Animated 2-color dithering over multiple pattern sources (noise, warp, dots, waves, ripple, swirl, sphere). + * + * SIZING NOTE: This shader performs sizing in the fragment shader (not vertex shader) to keep + * u_pxSize in consistent actual pixels. The pixel grid is computed from gl_FragCoord before any + * transforms, so scaling/rotating only affects the underlying pattern shape. + * No vertex shader outputs (v_objectUV, v_patternUV, etc.) are used. + * + * Fragment shader uniforms: + * - u_time (float): Animation time + * - u_resolution (vec2): Canvas resolution in pixels + * - u_pixelRatio (float): Device pixel ratio + * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1) + * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1) + * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas + * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas + * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover) + * - u_scale (float): Overall zoom level of the graphics (0.01 to 4) + * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360) + * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1) + * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1) + * - u_colorBack (vec4): Background color in RGBA + * - u_colorFront (vec4): Foreground (ink) color in RGBA + * - u_shape (float): Shape pattern type (1 = simplex, 2 = warp, 3 = dots, 4 = wave, 5 = ripple, 6 = swirl, 7 = sphere) + * - u_type (float): Dithering type (1 = random, 2 = 2x2 Bayer, 3 = 4x4 Bayer, 4 = 8x8 Bayer) + * - u_pxSize (float): Pixel size of dithering grid (0.5 to 20) + * + * */ +export declare const ditheringFragmentShader: string; +export interface DitheringUniforms extends ShaderSizingUniforms { + u_colorBack: [number, number, number, number]; + u_colorFront: [number, number, number, number]; + u_shape: (typeof DitheringShapes)[DitheringShape]; + u_type: (typeof DitheringTypes)[DitheringType]; + u_pxSize: number; +} +export interface DitheringParams extends ShaderSizingParams, ShaderMotionParams { + colorBack?: string; + colorFront?: string; + shape?: DitheringShape; + type?: DitheringType; + size?: number; +} +export declare const DitheringShapes: { + readonly simplex: 1; + readonly warp: 2; + readonly dots: 3; + readonly wave: 4; + readonly ripple: 5; + readonly swirl: 6; + readonly sphere: 7; +}; +export type DitheringShape = keyof typeof DitheringShapes; +export declare const DitheringTypes: { + readonly random: 1; + readonly '2x2': 2; + readonly '4x4': 3; + readonly '8x8': 4; +}; +export type DitheringType = keyof typeof DitheringTypes; diff --git a/public/vendor/paper-shaders/shaders/dithering.js b/public/vendor/paper-shaders/shaders/dithering.js new file mode 100644 index 0000000..9802517 --- /dev/null +++ b/public/vendor/paper-shaders/shaders/dithering.js @@ -0,0 +1,271 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Paper Shaders * + * https://github.com/paper-design/shaders * + * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +import { +} from "../shader-sizing.js"; +import { simplexNoise, declarePI, proceduralHash11, proceduralHash21 } from "../shader-utils.js"; +const ditheringFragmentShader = `#version 300 es +precision mediump float; + +uniform float u_time; + +uniform vec2 u_resolution; +uniform float u_pixelRatio; +uniform float u_originX; +uniform float u_originY; +uniform float u_worldWidth; +uniform float u_worldHeight; +uniform float u_fit; +uniform float u_scale; +uniform float u_rotation; +uniform float u_offsetX; +uniform float u_offsetY; + +uniform float u_pxSize; +uniform vec4 u_colorBack; +uniform vec4 u_colorFront; +uniform float u_shape; +uniform float u_type; + +out vec4 fragColor; + +${simplexNoise} +${declarePI} +${proceduralHash11} +${proceduralHash21} + +float getSimplexNoise(vec2 uv, float t) { + float noise = .5 * snoise(uv - vec2(0., .3 * t)); + noise += .5 * snoise(2. * uv + vec2(0., .32 * t)); + + return noise; +} + +const int bayer2x2[4] = int[4](0, 2, 3, 1); +const int bayer4x4[16] = int[16]( +0, 8, 2, 10, +12, 4, 14, 6, +3, 11, 1, 9, +15, 7, 13, 5 +); + +const int bayer8x8[64] = int[64]( +0, 32, 8, 40, 2, 34, 10, 42, +48, 16, 56, 24, 50, 18, 58, 26, +12, 44, 4, 36, 14, 46, 6, 38, +60, 28, 52, 20, 62, 30, 54, 22, +3, 35, 11, 43, 1, 33, 9, 41, +51, 19, 59, 27, 49, 17, 57, 25, +15, 47, 7, 39, 13, 45, 5, 37, +63, 31, 55, 23, 61, 29, 53, 21 +); + +float getBayerValue(vec2 uv, int size) { + ivec2 pos = ivec2(fract(uv / float(size)) * float(size)); + int index = pos.y * size + pos.x; + + if (size == 2) { + return float(bayer2x2[index]) / 4.0; + } else if (size == 4) { + return float(bayer4x4[index]) / 16.0; + } else if (size == 8) { + return float(bayer8x8[index]) / 64.0; + } + return 0.0; +} + + +void main() { + float t = .5 * u_time; + + float pxSize = u_pxSize * u_pixelRatio; + vec2 pxSizeUV = gl_FragCoord.xy - .5 * u_resolution; + pxSizeUV /= pxSize; + vec2 canvasPixelizedUV = (floor(pxSizeUV) + .5) * pxSize; + vec2 normalizedUV = canvasPixelizedUV / u_resolution; + + vec2 ditheringNoiseUV = canvasPixelizedUV; + vec2 shapeUV = normalizedUV; + + vec2 boxOrigin = vec2(.5 - u_originX, u_originY - .5); + vec2 givenBoxSize = vec2(u_worldWidth, u_worldHeight); + givenBoxSize = max(givenBoxSize, vec2(1.)) * u_pixelRatio; + float r = u_rotation * PI / 180.; + mat2 graphicRotation = mat2(cos(r), sin(r), -sin(r), cos(r)); + vec2 graphicOffset = vec2(-u_offsetX, u_offsetY); + + float patternBoxRatio = givenBoxSize.x / givenBoxSize.y; + vec2 boxSize = vec2( + (u_worldWidth == 0.) ? u_resolution.x : givenBoxSize.x, + (u_worldHeight == 0.) ? u_resolution.y : givenBoxSize.y + ); + + if (u_shape > 3.5) { + vec2 objectBoxSize = vec2(0.); + // fit = none + objectBoxSize.x = min(boxSize.x, boxSize.y); + if (u_fit == 1.) { // fit = contain + objectBoxSize.x = min(u_resolution.x, u_resolution.y); + } else if (u_fit == 2.) { // fit = cover + objectBoxSize.x = max(u_resolution.x, u_resolution.y); + } + objectBoxSize.y = objectBoxSize.x; + vec2 objectWorldScale = u_resolution.xy / objectBoxSize; + + shapeUV *= objectWorldScale; + shapeUV += boxOrigin * (objectWorldScale - 1.); + shapeUV += vec2(-u_offsetX, u_offsetY); + shapeUV /= u_scale; + shapeUV = graphicRotation * shapeUV; + } else { + vec2 patternBoxSize = vec2(0.); + // fit = none + patternBoxSize.x = patternBoxRatio * min(boxSize.x / patternBoxRatio, boxSize.y); + float patternWorldNoFitBoxWidth = patternBoxSize.x; + if (u_fit == 1.) { // fit = contain + patternBoxSize.x = patternBoxRatio * min(u_resolution.x / patternBoxRatio, u_resolution.y); + } else if (u_fit == 2.) { // fit = cover + patternBoxSize.x = patternBoxRatio * max(u_resolution.x / patternBoxRatio, u_resolution.y); + } + patternBoxSize.y = patternBoxSize.x / patternBoxRatio; + vec2 patternWorldScale = u_resolution.xy / patternBoxSize; + + shapeUV += vec2(-u_offsetX, u_offsetY) / patternWorldScale; + shapeUV += boxOrigin; + shapeUV -= boxOrigin / patternWorldScale; + shapeUV *= u_resolution.xy; + shapeUV /= u_pixelRatio; + if (u_fit > 0.) { + shapeUV *= (patternWorldNoFitBoxWidth / patternBoxSize.x); + } + shapeUV /= u_scale; + shapeUV = graphicRotation * shapeUV; + shapeUV += boxOrigin / patternWorldScale; + shapeUV -= boxOrigin; + shapeUV += .5; + } + + float shape = 0.; + if (u_shape < 1.5) { + // Simplex noise + shapeUV *= .001; + + shape = 0.5 + 0.5 * getSimplexNoise(shapeUV, t); + shape = smoothstep(0.3, 0.9, shape); + + } else if (u_shape < 2.5) { + // Warp + shapeUV *= .003; + + for (float i = 1.0; i < 6.0; i++) { + shapeUV.x += 0.6 / i * cos(i * 2.5 * shapeUV.y + t); + shapeUV.y += 0.6 / i * cos(i * 1.5 * shapeUV.x + t); + } + + shape = .15 / max(0.001, abs(sin(t - shapeUV.y - shapeUV.x))); + shape = smoothstep(0.02, 1., shape); + + } else if (u_shape < 3.5) { + // Dots + shapeUV *= .05; + + float stripeIdx = floor(2. * shapeUV.x / TWO_PI); + float rand = hash11(stripeIdx * 10.); + rand = sign(rand - .5) * pow(.1 + abs(rand), .4); + shape = sin(shapeUV.x) * cos(shapeUV.y - 5. * rand * t); + shape = pow(abs(shape), 6.); + + } else if (u_shape < 4.5) { + // Sine wave + shapeUV *= 4.; + + float wave = cos(.5 * shapeUV.x - 2. * t) * sin(1.5 * shapeUV.x + t) * (.75 + .25 * cos(3. * t)); + shape = 1. - smoothstep(-1., 1., shapeUV.y + wave); + + } else if (u_shape < 5.5) { + // Ripple + + float dist = length(shapeUV); + float waves = sin(pow(dist, 1.7) * 7. - 3. * t) * .5 + .5; + shape = waves; + + } else if (u_shape < 6.5) { + // Swirl + + float l = length(shapeUV); + float angle = 6. * atan(shapeUV.y, shapeUV.x) + 4. * t; + float twist = 1.2; + float offset = 1. / pow(max(l, 1e-6), twist) + angle / TWO_PI; + float mid = smoothstep(0., 1., pow(l, twist)); + shape = mix(0., fract(offset), mid); + + } else { + // Sphere + shapeUV *= 2.; + + float d = 1. - pow(length(shapeUV), 2.); + vec3 pos = vec3(shapeUV, sqrt(max(0., d))); + vec3 lightPos = normalize(vec3(cos(1.5 * t), .8, sin(1.25 * t))); + shape = .5 + .5 * dot(lightPos, pos); + shape *= step(0., d); + } + + + int type = int(floor(u_type)); + float dithering = 0.0; + + switch (type) { + case 1: { + dithering = step(hash21(ditheringNoiseUV), shape); + } break; + case 2: + dithering = getBayerValue(pxSizeUV, 2); + break; + case 3: + dithering = getBayerValue(pxSizeUV, 4); + break; + default : + dithering = getBayerValue(pxSizeUV, 8); + break; + } + + dithering -= .5; + float res = step(.5, shape + dithering); + + vec3 fgColor = u_colorFront.rgb * u_colorFront.a; + float fgOpacity = u_colorFront.a; + vec3 bgColor = u_colorBack.rgb * u_colorBack.a; + float bgOpacity = u_colorBack.a; + + vec3 color = fgColor * res; + float opacity = fgOpacity * res; + + color += bgColor * (1. - opacity); + opacity += bgOpacity * (1. - opacity); + + fragColor = vec4(color, opacity); +} +`; +const DitheringShapes = { + simplex: 1, + warp: 2, + dots: 3, + wave: 4, + ripple: 5, + swirl: 6, + sphere: 7 +}; +const DitheringTypes = { + "random": 1, + "2x2": 2, + "4x4": 3, + "8x8": 4 +}; +export { + DitheringShapes, + DitheringTypes, + ditheringFragmentShader +}; +//# sourceMappingURL=dithering.js.map diff --git a/public/vendor/paper-shaders/shaders/dithering.js.map b/public/vendor/paper-shaders/shaders/dithering.js.map new file mode 100644 index 0000000..322a46e --- /dev/null +++ b/public/vendor/paper-shaders/shaders/dithering.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../../src/shaders/dithering.ts"], + "sourcesContent": ["import type { ShaderMotionParams } from '../shader-mount.js';\nimport {\n type ShaderSizingParams,\n type ShaderSizingUniforms,\n} from '../shader-sizing.js';\nimport { simplexNoise, declarePI, proceduralHash11, proceduralHash21 } from '../shader-utils.js';\n\n/**\n * Animated 2-color dithering over multiple pattern sources (noise, warp, dots, waves, ripple, swirl, sphere).\n *\n * SIZING NOTE: This shader performs sizing in the fragment shader (not vertex shader) to keep\n * u_pxSize in consistent actual pixels. The pixel grid is computed from gl_FragCoord before any\n * transforms, so scaling/rotating only affects the underlying pattern shape.\n * No vertex shader outputs (v_objectUV, v_patternUV, etc.) are used.\n *\n * Fragment shader uniforms:\n * - u_time (float): Animation time\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n * - u_colorBack (vec4): Background color in RGBA\n * - u_colorFront (vec4): Foreground (ink) color in RGBA\n * - u_shape (float): Shape pattern type (1 = simplex, 2 = warp, 3 = dots, 4 = wave, 5 = ripple, 6 = swirl, 7 = sphere)\n * - u_type (float): Dithering type (1 = random, 2 = 2x2 Bayer, 3 = 4x4 Bayer, 4 = 8x8 Bayer)\n * - u_pxSize (float): Pixel size of dithering grid (0.5 to 20)\n *\n * */\n\n// language=GLSL\nexport const ditheringFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform float u_time;\n\nuniform vec2 u_resolution;\nuniform float u_pixelRatio;\nuniform float u_originX;\nuniform float u_originY;\nuniform float u_worldWidth;\nuniform float u_worldHeight;\nuniform float u_fit;\nuniform float u_scale;\nuniform float u_rotation;\nuniform float u_offsetX;\nuniform float u_offsetY;\n\nuniform float u_pxSize;\nuniform vec4 u_colorBack;\nuniform vec4 u_colorFront;\nuniform float u_shape;\nuniform float u_type;\n\nout vec4 fragColor;\n\n${ simplexNoise }\n${ declarePI }\n${ proceduralHash11 }\n${ proceduralHash21 }\n\nfloat getSimplexNoise(vec2 uv, float t) {\n float noise = .5 * snoise(uv - vec2(0., .3 * t));\n noise += .5 * snoise(2. * uv + vec2(0., .32 * t));\n\n return noise;\n}\n\nconst int bayer2x2[4] = int[4](0, 2, 3, 1);\nconst int bayer4x4[16] = int[16](\n0, 8, 2, 10,\n12, 4, 14, 6,\n3, 11, 1, 9,\n15, 7, 13, 5\n);\n\nconst int bayer8x8[64] = int[64](\n0, 32, 8, 40, 2, 34, 10, 42,\n48, 16, 56, 24, 50, 18, 58, 26,\n12, 44, 4, 36, 14, 46, 6, 38,\n60, 28, 52, 20, 62, 30, 54, 22,\n3, 35, 11, 43, 1, 33, 9, 41,\n51, 19, 59, 27, 49, 17, 57, 25,\n15, 47, 7, 39, 13, 45, 5, 37,\n63, 31, 55, 23, 61, 29, 53, 21\n);\n\nfloat getBayerValue(vec2 uv, int size) {\n ivec2 pos = ivec2(fract(uv / float(size)) * float(size));\n int index = pos.y * size + pos.x;\n\n if (size == 2) {\n return float(bayer2x2[index]) / 4.0;\n } else if (size == 4) {\n return float(bayer4x4[index]) / 16.0;\n } else if (size == 8) {\n return float(bayer8x8[index]) / 64.0;\n }\n return 0.0;\n}\n\n\nvoid main() {\n float t = .5 * u_time;\n\n float pxSize = u_pxSize * u_pixelRatio;\n vec2 pxSizeUV = gl_FragCoord.xy - .5 * u_resolution;\n pxSizeUV /= pxSize;\n vec2 canvasPixelizedUV = (floor(pxSizeUV) + .5) * pxSize;\n vec2 normalizedUV = canvasPixelizedUV / u_resolution;\n\n vec2 ditheringNoiseUV = canvasPixelizedUV;\n vec2 shapeUV = normalizedUV;\n\n vec2 boxOrigin = vec2(.5 - u_originX, u_originY - .5);\n vec2 givenBoxSize = vec2(u_worldWidth, u_worldHeight);\n givenBoxSize = max(givenBoxSize, vec2(1.)) * u_pixelRatio;\n float r = u_rotation * PI / 180.;\n mat2 graphicRotation = mat2(cos(r), sin(r), -sin(r), cos(r));\n vec2 graphicOffset = vec2(-u_offsetX, u_offsetY);\n\n float patternBoxRatio = givenBoxSize.x / givenBoxSize.y;\n vec2 boxSize = vec2(\n (u_worldWidth == 0.) ? u_resolution.x : givenBoxSize.x,\n (u_worldHeight == 0.) ? u_resolution.y : givenBoxSize.y\n );\n \n if (u_shape > 3.5) {\n vec2 objectBoxSize = vec2(0.);\n // fit = none\n objectBoxSize.x = min(boxSize.x, boxSize.y);\n if (u_fit == 1.) { // fit = contain\n objectBoxSize.x = min(u_resolution.x, u_resolution.y);\n } else if (u_fit == 2.) { // fit = cover\n objectBoxSize.x = max(u_resolution.x, u_resolution.y);\n }\n objectBoxSize.y = objectBoxSize.x;\n vec2 objectWorldScale = u_resolution.xy / objectBoxSize;\n\n shapeUV *= objectWorldScale;\n shapeUV += boxOrigin * (objectWorldScale - 1.);\n shapeUV += vec2(-u_offsetX, u_offsetY);\n shapeUV /= u_scale;\n shapeUV = graphicRotation * shapeUV;\n } else {\n vec2 patternBoxSize = vec2(0.);\n // fit = none\n patternBoxSize.x = patternBoxRatio * min(boxSize.x / patternBoxRatio, boxSize.y);\n float patternWorldNoFitBoxWidth = patternBoxSize.x;\n if (u_fit == 1.) { // fit = contain\n patternBoxSize.x = patternBoxRatio * min(u_resolution.x / patternBoxRatio, u_resolution.y);\n } else if (u_fit == 2.) { // fit = cover\n patternBoxSize.x = patternBoxRatio * max(u_resolution.x / patternBoxRatio, u_resolution.y);\n }\n patternBoxSize.y = patternBoxSize.x / patternBoxRatio;\n vec2 patternWorldScale = u_resolution.xy / patternBoxSize;\n\n shapeUV += vec2(-u_offsetX, u_offsetY) / patternWorldScale;\n shapeUV += boxOrigin;\n shapeUV -= boxOrigin / patternWorldScale;\n shapeUV *= u_resolution.xy;\n shapeUV /= u_pixelRatio;\n if (u_fit > 0.) {\n shapeUV *= (patternWorldNoFitBoxWidth / patternBoxSize.x);\n }\n shapeUV /= u_scale;\n shapeUV = graphicRotation * shapeUV;\n shapeUV += boxOrigin / patternWorldScale;\n shapeUV -= boxOrigin;\n shapeUV += .5;\n }\n\n float shape = 0.;\n if (u_shape < 1.5) {\n // Simplex noise\n shapeUV *= .001;\n\n shape = 0.5 + 0.5 * getSimplexNoise(shapeUV, t);\n shape = smoothstep(0.3, 0.9, shape);\n\n } else if (u_shape < 2.5) {\n // Warp\n shapeUV *= .003;\n\n for (float i = 1.0; i < 6.0; i++) {\n shapeUV.x += 0.6 / i * cos(i * 2.5 * shapeUV.y + t);\n shapeUV.y += 0.6 / i * cos(i * 1.5 * shapeUV.x + t);\n }\n\n shape = .15 / max(0.001, abs(sin(t - shapeUV.y - shapeUV.x)));\n shape = smoothstep(0.02, 1., shape);\n\n } else if (u_shape < 3.5) {\n // Dots\n shapeUV *= .05;\n\n float stripeIdx = floor(2. * shapeUV.x / TWO_PI);\n float rand = hash11(stripeIdx * 10.);\n rand = sign(rand - .5) * pow(.1 + abs(rand), .4);\n shape = sin(shapeUV.x) * cos(shapeUV.y - 5. * rand * t);\n shape = pow(abs(shape), 6.);\n\n } else if (u_shape < 4.5) {\n // Sine wave\n shapeUV *= 4.;\n\n float wave = cos(.5 * shapeUV.x - 2. * t) * sin(1.5 * shapeUV.x + t) * (.75 + .25 * cos(3. * t));\n shape = 1. - smoothstep(-1., 1., shapeUV.y + wave);\n\n } else if (u_shape < 5.5) {\n // Ripple\n\n float dist = length(shapeUV);\n float waves = sin(pow(dist, 1.7) * 7. - 3. * t) * .5 + .5;\n shape = waves;\n\n } else if (u_shape < 6.5) {\n // Swirl\n\n float l = length(shapeUV);\n float angle = 6. * atan(shapeUV.y, shapeUV.x) + 4. * t;\n float twist = 1.2;\n float offset = 1. / pow(max(l, 1e-6), twist) + angle / TWO_PI;\n float mid = smoothstep(0., 1., pow(l, twist));\n shape = mix(0., fract(offset), mid);\n\n } else {\n // Sphere\n shapeUV *= 2.;\n\n float d = 1. - pow(length(shapeUV), 2.);\n vec3 pos = vec3(shapeUV, sqrt(max(0., d)));\n vec3 lightPos = normalize(vec3(cos(1.5 * t), .8, sin(1.25 * t)));\n shape = .5 + .5 * dot(lightPos, pos);\n shape *= step(0., d);\n }\n\n\n int type = int(floor(u_type));\n float dithering = 0.0;\n\n switch (type) {\n case 1: {\n dithering = step(hash21(ditheringNoiseUV), shape);\n } break;\n case 2:\n dithering = getBayerValue(pxSizeUV, 2);\n break;\n case 3:\n dithering = getBayerValue(pxSizeUV, 4);\n break;\n default :\n dithering = getBayerValue(pxSizeUV, 8);\n break;\n }\n\n dithering -= .5;\n float res = step(.5, shape + dithering);\n\n vec3 fgColor = u_colorFront.rgb * u_colorFront.a;\n float fgOpacity = u_colorFront.a;\n vec3 bgColor = u_colorBack.rgb * u_colorBack.a;\n float bgOpacity = u_colorBack.a;\n\n vec3 color = fgColor * res;\n float opacity = fgOpacity * res;\n\n color += bgColor * (1. - opacity);\n opacity += bgOpacity * (1. - opacity);\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface DitheringUniforms extends ShaderSizingUniforms {\n u_colorBack: [number, number, number, number];\n u_colorFront: [number, number, number, number];\n u_shape: (typeof DitheringShapes)[DitheringShape];\n u_type: (typeof DitheringTypes)[DitheringType];\n u_pxSize: number;\n}\n\nexport interface DitheringParams extends ShaderSizingParams, ShaderMotionParams {\n colorBack?: string;\n colorFront?: string;\n shape?: DitheringShape;\n type?: DitheringType;\n size?: number;\n}\n\nexport const DitheringShapes = {\n simplex: 1,\n warp: 2,\n dots: 3,\n wave: 4,\n ripple: 5,\n swirl: 6,\n sphere: 7,\n} as const;\n\nexport type DitheringShape = keyof typeof DitheringShapes;\n\nexport const DitheringTypes = {\n 'random': 1,\n '2x2': 2,\n '4x4': 3,\n '8x8': 4,\n} as const;\n\nexport type DitheringType = keyof typeof DitheringTypes;\n"], + "mappings": ";;;;;AACA;AAAA,OAGO;AACP,SAAS,cAAc,WAAW,kBAAkB,wBAAwB;AAgCrE,MAAM,0BAAkC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAyB5C,YAAa;AAAA,EACb,SAAU;AAAA,EACV,gBAAiB;AAAA,EACjB,gBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAuOb,MAAM,kBAAkB;AAAA,EAC7B,SAAS;AAAA,EACT,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,QAAQ;AACV;AAIO,MAAM,iBAAiB;AAAA,EAC5B,UAAU;AAAA,EACV,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AACT;", + "names": [] +} diff --git a/public/vendor/paper-shaders/shaders/dot-grid.d.ts b/public/vendor/paper-shaders/shaders/dot-grid.d.ts new file mode 100644 index 0000000..31d5d35 --- /dev/null +++ b/public/vendor/paper-shaders/shaders/dot-grid.d.ts @@ -0,0 +1,65 @@ +import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js'; +/** + * Static grid pattern made of circles, diamonds, squares or triangles. + * + * Fragment shader uniforms: + * - u_colorBack (vec4): Background color in RGBA + * - u_colorFill (vec4): Shape fill color in RGBA + * - u_colorStroke (vec4): Shape stroke color in RGBA + * - u_dotSize (float): Base size of each shape in pixels (1 to 100) + * - u_gapX (float): Pattern horizontal spacing in pixels (2 to 500) + * - u_gapY (float): Pattern vertical spacing in pixels (2 to 500) + * - u_strokeWidth (float): Outline stroke width in pixels (0 to 50) + * - u_sizeRange (float): Random variation in shape size, 0 = uniform, higher = random up to base size (0 to 1) + * - u_opacityRange (float): Random variation in shape opacity, 0 = opaque, higher = semi-transparent (0 to 1) + * - u_shape (float): Shape type (0 = circle, 1 = diamond, 2 = square, 3 = triangle) + * + * Vertex shader outputs (used in fragment shader): + * - v_patternUV (vec2): UV coordinates in pixels (scaled by 0.01 for precision), with scale, rotation and offset applied + * + * Vertex shader uniforms: + * - u_resolution (vec2): Canvas resolution in pixels + * - u_pixelRatio (float): Device pixel ratio + * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1) + * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1) + * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas + * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas + * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover) + * - u_scale (float): Overall zoom level of the graphics (0.01 to 4) + * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360) + * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1) + * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1) + * + */ +export declare const dotGridFragmentShader: string; +export interface DotGridUniforms extends ShaderSizingUniforms { + u_colorBack: [number, number, number, number]; + u_colorFill: [number, number, number, number]; + u_colorStroke: [number, number, number, number]; + u_dotSize: number; + u_gapX: number; + u_gapY: number; + u_strokeWidth: number; + u_sizeRange: number; + u_opacityRange: number; + u_shape: (typeof DotGridShapes)[DotGridShape]; +} +export interface DotGridParams extends ShaderSizingParams { + colorBack?: string; + colorFill?: string; + colorStroke?: string; + size?: number; + gapX?: number; + gapY?: number; + strokeWidth?: number; + sizeRange?: number; + opacityRange?: number; + shape?: DotGridShape; +} +export declare const DotGridShapes: { + readonly circle: 0; + readonly diamond: 1; + readonly square: 2; + readonly triangle: 3; +}; +export type DotGridShape = keyof typeof DotGridShapes; diff --git a/public/vendor/paper-shaders/shaders/dot-grid.js b/public/vendor/paper-shaders/shaders/dot-grid.js new file mode 100644 index 0000000..e657564 --- /dev/null +++ b/public/vendor/paper-shaders/shaders/dot-grid.js @@ -0,0 +1,110 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Paper Shaders * + * https://github.com/paper-design/shaders * + * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +import {} from "../shader-sizing.js"; +import { declarePI, simplexNoise } from "../shader-utils.js"; +const dotGridFragmentShader = `#version 300 es +precision mediump float; + +uniform vec4 u_colorBack; +uniform vec4 u_colorFill; +uniform vec4 u_colorStroke; +uniform float u_dotSize; +uniform float u_gapX; +uniform float u_gapY; +uniform float u_strokeWidth; +uniform float u_sizeRange; +uniform float u_opacityRange; +uniform float u_shape; + +in vec2 v_patternUV; + +out vec4 fragColor; + +${declarePI} +${simplexNoise} + +float polygon(vec2 p, float N, float rot) { + float a = atan(p.x, p.y) + rot; + float r = TWO_PI / float(N); + + return cos(floor(.5 + a / r) * r - a) * length(p); +} + +void main() { + + // x100 is a default multiplier between vertex and fragmant shaders + // we use it to avoid UV presision issues + vec2 shape_uv = 100. * v_patternUV; + + vec2 gap = max(abs(vec2(u_gapX, u_gapY)), vec2(1e-6)); + vec2 grid = fract(shape_uv / gap) + 1e-4; + vec2 grid_idx = floor(shape_uv / gap); + float sizeRandomizer = .5 + .8 * snoise(2. * vec2(grid_idx.x * 100., grid_idx.y)); + float opacity_randomizer = .5 + .7 * snoise(2. * vec2(grid_idx.y, grid_idx.x)); + + vec2 center = vec2(0.5) - 1e-3; + vec2 p = (grid - center) * vec2(u_gapX, u_gapY); + + float baseSize = u_dotSize * (1. - sizeRandomizer * u_sizeRange); + float strokeWidth = u_strokeWidth * (1. - sizeRandomizer * u_sizeRange); + + float dist; + if (u_shape < 0.5) { + // Circle + dist = length(p); + } else if (u_shape < 1.5) { + // Diamond + strokeWidth *= 1.5; + dist = polygon(1.5 * p, 4., .25 * PI); + } else if (u_shape < 2.5) { + // Square + dist = polygon(1.03 * p, 4., 1e-3); + } else { + // Triangle + strokeWidth *= 1.5; + p = p * 2. - 1.; + p *= .9; + p.y = 1. - p.y; + p.y -= .75 * baseSize; + dist = polygon(p, 3., 1e-3); + } + + float edgeWidth = fwidth(dist); + float shapeOuter = 1. - smoothstep(baseSize - edgeWidth, baseSize + edgeWidth, dist - strokeWidth); + float shapeInner = 1. - smoothstep(baseSize - edgeWidth, baseSize + edgeWidth, dist); + float stroke = shapeOuter - shapeInner; + + float dotOpacity = max(0., 1. - opacity_randomizer * u_opacityRange); + stroke *= dotOpacity; + shapeInner *= dotOpacity; + + stroke *= u_colorStroke.a; + shapeInner *= u_colorFill.a; + + vec3 color = vec3(0.); + color += stroke * u_colorStroke.rgb; + color += shapeInner * u_colorFill.rgb; + color += (1. - shapeInner - stroke) * u_colorBack.rgb * u_colorBack.a; + + float opacity = 0.; + opacity += stroke; + opacity += shapeInner; + opacity += (1. - opacity) * u_colorBack.a; + + fragColor = vec4(color, opacity); +} +`; +const DotGridShapes = { + circle: 0, + diamond: 1, + square: 2, + triangle: 3 +}; +export { + DotGridShapes, + dotGridFragmentShader +}; +//# sourceMappingURL=dot-grid.js.map diff --git a/public/vendor/paper-shaders/shaders/dot-grid.js.map b/public/vendor/paper-shaders/shaders/dot-grid.js.map new file mode 100644 index 0000000..3de1213 --- /dev/null +++ b/public/vendor/paper-shaders/shaders/dot-grid.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../../src/shaders/dot-grid.ts"], + "sourcesContent": ["import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { declarePI, simplexNoise } from '../shader-utils.js';\n\n/**\n * Static grid pattern made of circles, diamonds, squares or triangles.\n *\n * Fragment shader uniforms:\n * - u_colorBack (vec4): Background color in RGBA\n * - u_colorFill (vec4): Shape fill color in RGBA\n * - u_colorStroke (vec4): Shape stroke color in RGBA\n * - u_dotSize (float): Base size of each shape in pixels (1 to 100)\n * - u_gapX (float): Pattern horizontal spacing in pixels (2 to 500)\n * - u_gapY (float): Pattern vertical spacing in pixels (2 to 500)\n * - u_strokeWidth (float): Outline stroke width in pixels (0 to 50)\n * - u_sizeRange (float): Random variation in shape size, 0 = uniform, higher = random up to base size (0 to 1)\n * - u_opacityRange (float): Random variation in shape opacity, 0 = opaque, higher = semi-transparent (0 to 1)\n * - u_shape (float): Shape type (0 = circle, 1 = diamond, 2 = square, 3 = triangle)\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_patternUV (vec2): UV coordinates in pixels (scaled by 0.01 for precision), with scale, rotation and offset applied\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n *\n */\n\n// language=GLSL\nexport const dotGridFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform vec4 u_colorBack;\nuniform vec4 u_colorFill;\nuniform vec4 u_colorStroke;\nuniform float u_dotSize;\nuniform float u_gapX;\nuniform float u_gapY;\nuniform float u_strokeWidth;\nuniform float u_sizeRange;\nuniform float u_opacityRange;\nuniform float u_shape;\n\nin vec2 v_patternUV;\n\nout vec4 fragColor;\n\n${ declarePI }\n${ simplexNoise }\n\nfloat polygon(vec2 p, float N, float rot) {\n float a = atan(p.x, p.y) + rot;\n float r = TWO_PI / float(N);\n\n return cos(floor(.5 + a / r) * r - a) * length(p);\n}\n\nvoid main() {\n\n // x100 is a default multiplier between vertex and fragmant shaders\n // we use it to avoid UV presision issues\n vec2 shape_uv = 100. * v_patternUV;\n\n vec2 gap = max(abs(vec2(u_gapX, u_gapY)), vec2(1e-6));\n vec2 grid = fract(shape_uv / gap) + 1e-4;\n vec2 grid_idx = floor(shape_uv / gap);\n float sizeRandomizer = .5 + .8 * snoise(2. * vec2(grid_idx.x * 100., grid_idx.y));\n float opacity_randomizer = .5 + .7 * snoise(2. * vec2(grid_idx.y, grid_idx.x));\n\n vec2 center = vec2(0.5) - 1e-3;\n vec2 p = (grid - center) * vec2(u_gapX, u_gapY);\n\n float baseSize = u_dotSize * (1. - sizeRandomizer * u_sizeRange);\n float strokeWidth = u_strokeWidth * (1. - sizeRandomizer * u_sizeRange);\n\n float dist;\n if (u_shape < 0.5) {\n // Circle\n dist = length(p);\n } else if (u_shape < 1.5) {\n // Diamond\n strokeWidth *= 1.5;\n dist = polygon(1.5 * p, 4., .25 * PI);\n } else if (u_shape < 2.5) {\n // Square\n dist = polygon(1.03 * p, 4., 1e-3);\n } else {\n // Triangle\n strokeWidth *= 1.5;\n p = p * 2. - 1.;\n p *= .9;\n p.y = 1. - p.y;\n p.y -= .75 * baseSize;\n dist = polygon(p, 3., 1e-3);\n }\n\n float edgeWidth = fwidth(dist);\n float shapeOuter = 1. - smoothstep(baseSize - edgeWidth, baseSize + edgeWidth, dist - strokeWidth);\n float shapeInner = 1. - smoothstep(baseSize - edgeWidth, baseSize + edgeWidth, dist);\n float stroke = shapeOuter - shapeInner;\n\n float dotOpacity = max(0., 1. - opacity_randomizer * u_opacityRange);\n stroke *= dotOpacity;\n shapeInner *= dotOpacity;\n\n stroke *= u_colorStroke.a;\n shapeInner *= u_colorFill.a;\n\n vec3 color = vec3(0.);\n color += stroke * u_colorStroke.rgb;\n color += shapeInner * u_colorFill.rgb;\n color += (1. - shapeInner - stroke) * u_colorBack.rgb * u_colorBack.a;\n\n float opacity = 0.;\n opacity += stroke;\n opacity += shapeInner;\n opacity += (1. - opacity) * u_colorBack.a;\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface DotGridUniforms extends ShaderSizingUniforms {\n u_colorBack: [number, number, number, number];\n u_colorFill: [number, number, number, number];\n u_colorStroke: [number, number, number, number];\n u_dotSize: number;\n u_gapX: number;\n u_gapY: number;\n u_strokeWidth: number;\n u_sizeRange: number;\n u_opacityRange: number;\n u_shape: (typeof DotGridShapes)[DotGridShape];\n}\n\nexport interface DotGridParams extends ShaderSizingParams {\n colorBack?: string;\n colorFill?: string;\n colorStroke?: string;\n size?: number;\n gapX?: number;\n gapY?: number;\n strokeWidth?: number;\n sizeRange?: number;\n opacityRange?: number;\n shape?: DotGridShape;\n}\n\nexport const DotGridShapes = {\n circle: 0,\n diamond: 1,\n square: 2,\n triangle: 3,\n} as const;\n\nexport type DotGridShape = keyof typeof DotGridShapes;\n"], + "mappings": ";;;;;AAAA,eAAmE;AACnE,SAAS,WAAW,oBAAoB;AAoCjC,MAAM,wBAAgC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkB1C,SAAU;AAAA,EACV,YAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAoGT,MAAM,gBAAgB;AAAA,EAC3B,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,UAAU;AACZ;", + "names": [] +} diff --git a/public/vendor/paper-shaders/shaders/dot-orbit.d.ts b/public/vendor/paper-shaders/shaders/dot-orbit.d.ts new file mode 100644 index 0000000..ef3818b --- /dev/null +++ b/public/vendor/paper-shaders/shaders/dot-orbit.d.ts @@ -0,0 +1,57 @@ +import type { vec4 } from '../types.js'; +import type { ShaderMotionParams } from '../shader-mount.js'; +import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js'; +export declare const dotOrbitMeta: { + readonly maxColorCount: 10; +}; +/** + * Animated multi-color dots pattern with each dot orbiting around its cell center. + * Supports up to 10 colors and various shape and motion controls. + * + * Fragment shader uniforms: + * - u_time (float): Animation time + * - u_colorBack (vec4): Background color in RGBA + * - u_colors (vec4[]): Up to 10 base colors in RGBA + * - u_colorsCount (float): Number of active colors + * - u_stepsPerColor (float): Number of extra colors between base colors, 1 = N colors, 2 = 2×N, etc. (1 to 4) + * - u_size (float): Dot radius relative to cell size (0 to 1) + * - u_sizeRange (float): Random variation in shape size, 0 = uniform, higher = random up to base size (0 to 1) + * - u_spreading (float): Maximum orbit distance around cell center (0 to 1) + * - u_noiseTexture (sampler2D): Pre-computed randomizer source texture + * + * Vertex shader outputs (used in fragment shader): + * - v_patternUV (vec2): UV coordinates in pixels (scaled by 0.01 for precision), with rotation and offset applied + * + * Vertex shader uniforms: + * - u_resolution (vec2): Canvas resolution in pixels + * - u_pixelRatio (float): Device pixel ratio + * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1) + * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1) + * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas + * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas + * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover) + * - u_scale (float): Overall zoom level of the graphics (0.01 to 4) + * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360) + * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1) + * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1) + * + */ +export declare const dotOrbitFragmentShader: string; +export interface DotOrbitUniforms extends ShaderSizingUniforms { + u_colorBack: [number, number, number, number]; + u_colors: vec4[]; + u_colorsCount: number; + u_size: number; + u_sizeRange: number; + u_spreading: number; + u_stepsPerColor: number; + u_noiseTexture?: HTMLImageElement; +} +export interface DotOrbitParams extends ShaderSizingParams, ShaderMotionParams { + colorBack?: string; + colors?: string[]; + size?: number; + sizeRange?: number; + spreading?: number; + stepsPerColor?: number; +} diff --git a/public/vendor/paper-shaders/shaders/dot-orbit.js b/public/vendor/paper-shaders/shaders/dot-orbit.js new file mode 100644 index 0000000..edee2e7 --- /dev/null +++ b/public/vendor/paper-shaders/shaders/dot-orbit.js @@ -0,0 +1,123 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Paper Shaders * + * https://github.com/paper-design/shaders * + * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +import {} from "../shader-sizing.js"; +import { declarePI, rotation2, textureRandomizerR, textureRandomizerGB } from "../shader-utils.js"; +const dotOrbitMeta = { + maxColorCount: 10 +}; +const dotOrbitFragmentShader = `#version 300 es +precision mediump float; + +uniform float u_time; + +uniform sampler2D u_noiseTexture; + +uniform vec4 u_colorBack; +uniform vec4 u_colors[${dotOrbitMeta.maxColorCount}]; +uniform float u_colorsCount; +uniform float u_stepsPerColor; +uniform float u_size; +uniform float u_sizeRange; +uniform float u_spreading; + +in vec2 v_patternUV; + +out vec4 fragColor; + +${declarePI} +${rotation2} +${textureRandomizerR} +${textureRandomizerGB} + + +vec3 voronoiShape(vec2 uv, float time) { + vec2 i_uv = floor(uv); + vec2 f_uv = fract(uv); + + float spreading = .25 * clamp(u_spreading, 0., 1.); + + float minDist = 1.; + vec2 randomizer = vec2(0.); + for (int y = -1; y <= 1; y++) { + for (int x = -1; x <= 1; x++) { + vec2 tileOffset = vec2(float(x), float(y)); + vec2 rand = randomGB(i_uv + tileOffset); + vec2 cellCenter = vec2(.5 + 1e-4); + cellCenter += spreading * cos(time + TWO_PI * rand); + cellCenter -= .5; + cellCenter = rotate(cellCenter, randomR(vec2(rand.x, rand.y)) + .1 * time); + cellCenter += .5; + float dist = length(tileOffset + cellCenter - f_uv); + if (dist < minDist) { + minDist = dist; + randomizer = rand; + } + } + } + + return vec3(minDist, randomizer); +} + +void main() { + + vec2 shape_uv = v_patternUV; + shape_uv *= 1.5; + + const float firstFrameOffset = -10.; + float t = u_time + firstFrameOffset; + + vec3 voronoi = voronoiShape(shape_uv, t) + 1e-4; + + float radius = .25 * clamp(u_size, 0., 1.) - .5 * clamp(u_sizeRange, 0., 1.) * voronoi[2]; + float dist = voronoi[0]; + float edgeWidth = fwidth(dist); + float dots = 1. - smoothstep(radius - edgeWidth, radius + edgeWidth, dist); + + float shape = voronoi[1]; + + float mixer = shape * (u_colorsCount - 1.); + mixer = (shape - .5 / u_colorsCount) * u_colorsCount; + float steps = max(1., u_stepsPerColor); + + vec4 gradient = u_colors[0]; + gradient.rgb *= gradient.a; + for (int i = 1; i < ${dotOrbitMeta.maxColorCount}; i++) { + if (i >= int(u_colorsCount)) break; + float localT = clamp(mixer - float(i - 1), 0.0, 1.0); + localT = round(localT * steps) / steps; + vec4 c = u_colors[i]; + c.rgb *= c.a; + gradient = mix(gradient, c, localT); + } + + if ((mixer < 0.) || (mixer > (u_colorsCount - 1.))) { + float localT = mixer + 1.; + if (mixer > (u_colorsCount - 1.)) { + localT = mixer - (u_colorsCount - 1.); + } + localT = round(localT * steps) / steps; + vec4 cFst = u_colors[0]; + cFst.rgb *= cFst.a; + vec4 cLast = u_colors[int(u_colorsCount - 1.)]; + cLast.rgb *= cLast.a; + gradient = mix(cLast, cFst, localT); + } + + vec3 color = gradient.rgb * dots; + float opacity = gradient.a * dots; + + vec3 bgColor = u_colorBack.rgb * u_colorBack.a; + color = color + bgColor * (1. - opacity); + opacity = opacity + u_colorBack.a * (1. - opacity); + + fragColor = vec4(color, opacity); +} +`; +export { + dotOrbitFragmentShader, + dotOrbitMeta +}; +//# sourceMappingURL=dot-orbit.js.map diff --git a/public/vendor/paper-shaders/shaders/dot-orbit.js.map b/public/vendor/paper-shaders/shaders/dot-orbit.js.map new file mode 100644 index 0000000..e0a18c9 --- /dev/null +++ b/public/vendor/paper-shaders/shaders/dot-orbit.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../../src/shaders/dot-orbit.ts"], + "sourcesContent": ["import type { vec4 } from '../types.js';\nimport type { ShaderMotionParams } from '../shader-mount.js';\nimport { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { declarePI, rotation2, textureRandomizerR, textureRandomizerGB } from '../shader-utils.js';\n\nexport const dotOrbitMeta = {\n maxColorCount: 10,\n} as const;\n\n/**\n * Animated multi-color dots pattern with each dot orbiting around its cell center.\n * Supports up to 10 colors and various shape and motion controls.\n *\n * Fragment shader uniforms:\n * - u_time (float): Animation time\n * - u_colorBack (vec4): Background color in RGBA\n * - u_colors (vec4[]): Up to 10 base colors in RGBA\n * - u_colorsCount (float): Number of active colors\n * - u_stepsPerColor (float): Number of extra colors between base colors, 1 = N colors, 2 = 2\u00D7N, etc. (1 to 4)\n * - u_size (float): Dot radius relative to cell size (0 to 1)\n * - u_sizeRange (float): Random variation in shape size, 0 = uniform, higher = random up to base size (0 to 1)\n * - u_spreading (float): Maximum orbit distance around cell center (0 to 1)\n * - u_noiseTexture (sampler2D): Pre-computed randomizer source texture\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_patternUV (vec2): UV coordinates in pixels (scaled by 0.01 for precision), with rotation and offset applied\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n *\n */\n\n// language=GLSL\nexport const dotOrbitFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform float u_time;\n\nuniform sampler2D u_noiseTexture;\n\nuniform vec4 u_colorBack;\nuniform vec4 u_colors[${ dotOrbitMeta.maxColorCount }];\nuniform float u_colorsCount;\nuniform float u_stepsPerColor;\nuniform float u_size;\nuniform float u_sizeRange;\nuniform float u_spreading;\n\nin vec2 v_patternUV;\n\nout vec4 fragColor;\n\n${ declarePI }\n${ rotation2 }\n${ textureRandomizerR }\n${ textureRandomizerGB }\n\n\nvec3 voronoiShape(vec2 uv, float time) {\n vec2 i_uv = floor(uv);\n vec2 f_uv = fract(uv);\n\n float spreading = .25 * clamp(u_spreading, 0., 1.);\n\n float minDist = 1.;\n vec2 randomizer = vec2(0.);\n for (int y = -1; y <= 1; y++) {\n for (int x = -1; x <= 1; x++) {\n vec2 tileOffset = vec2(float(x), float(y));\n vec2 rand = randomGB(i_uv + tileOffset);\n vec2 cellCenter = vec2(.5 + 1e-4);\n cellCenter += spreading * cos(time + TWO_PI * rand);\n cellCenter -= .5;\n cellCenter = rotate(cellCenter, randomR(vec2(rand.x, rand.y)) + .1 * time);\n cellCenter += .5;\n float dist = length(tileOffset + cellCenter - f_uv);\n if (dist < minDist) {\n minDist = dist;\n randomizer = rand;\n }\n }\n }\n\n return vec3(minDist, randomizer);\n}\n\nvoid main() {\n\n vec2 shape_uv = v_patternUV;\n shape_uv *= 1.5;\n\n const float firstFrameOffset = -10.;\n float t = u_time + firstFrameOffset;\n\n vec3 voronoi = voronoiShape(shape_uv, t) + 1e-4;\n\n float radius = .25 * clamp(u_size, 0., 1.) - .5 * clamp(u_sizeRange, 0., 1.) * voronoi[2];\n float dist = voronoi[0];\n float edgeWidth = fwidth(dist);\n float dots = 1. - smoothstep(radius - edgeWidth, radius + edgeWidth, dist);\n\n float shape = voronoi[1];\n\n float mixer = shape * (u_colorsCount - 1.);\n mixer = (shape - .5 / u_colorsCount) * u_colorsCount;\n float steps = max(1., u_stepsPerColor);\n\n vec4 gradient = u_colors[0];\n gradient.rgb *= gradient.a;\n for (int i = 1; i < ${ dotOrbitMeta.maxColorCount }; i++) {\n if (i >= int(u_colorsCount)) break;\n float localT = clamp(mixer - float(i - 1), 0.0, 1.0);\n localT = round(localT * steps) / steps;\n vec4 c = u_colors[i];\n c.rgb *= c.a;\n gradient = mix(gradient, c, localT);\n }\n\n if ((mixer < 0.) || (mixer > (u_colorsCount - 1.))) {\n float localT = mixer + 1.;\n if (mixer > (u_colorsCount - 1.)) {\n localT = mixer - (u_colorsCount - 1.);\n }\n localT = round(localT * steps) / steps;\n vec4 cFst = u_colors[0];\n cFst.rgb *= cFst.a;\n vec4 cLast = u_colors[int(u_colorsCount - 1.)];\n cLast.rgb *= cLast.a;\n gradient = mix(cLast, cFst, localT);\n }\n\n vec3 color = gradient.rgb * dots;\n float opacity = gradient.a * dots;\n\n vec3 bgColor = u_colorBack.rgb * u_colorBack.a;\n color = color + bgColor * (1. - opacity);\n opacity = opacity + u_colorBack.a * (1. - opacity);\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface DotOrbitUniforms extends ShaderSizingUniforms {\n u_colorBack: [number, number, number, number];\n u_colors: vec4[];\n u_colorsCount: number;\n u_size: number;\n u_sizeRange: number;\n u_spreading: number;\n u_stepsPerColor: number;\n u_noiseTexture?: HTMLImageElement;\n}\n\nexport interface DotOrbitParams extends ShaderSizingParams, ShaderMotionParams {\n colorBack?: string;\n colors?: string[];\n size?: number;\n sizeRange?: number;\n spreading?: number;\n stepsPerColor?: number;\n}\n"], + "mappings": ";;;;;AAEA,eAAmE;AACnE,SAAS,WAAW,WAAW,oBAAoB,2BAA2B;AAEvE,MAAM,eAAe;AAAA,EAC1B,eAAe;AACjB;AAoCO,MAAM,yBAAiC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAQrB,aAAa,aAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWjD,SAAU;AAAA,EACV,SAAU;AAAA,EACV,kBAAmB;AAAA,EACnB,mBAAoB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAsDE,aAAa,aAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;", + "names": [] +} diff --git a/public/vendor/paper-shaders/shaders/fluted-glass.d.ts b/public/vendor/paper-shaders/shaders/fluted-glass.d.ts new file mode 100644 index 0000000..18dc387 --- /dev/null +++ b/public/vendor/paper-shaders/shaders/fluted-glass.d.ts @@ -0,0 +1,114 @@ +import type { ShaderMotionParams } from '../shader-mount.js'; +import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js'; +/** + * Fluted glass image filter that transforms an image into streaked, ribbed distortions, + * giving a mix of clarity and obscurity. + * + * Fragment shader uniforms: + * - u_resolution (vec2): Canvas resolution in pixels + * - u_pixelRatio (float): Device pixel ratio + * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360) + * - u_image (sampler2D): Source image texture + * - u_imageAspectRatio (float): Aspect ratio of the source image + * - u_colorBack (vec4): Background color in RGBA + * - u_colorShadow (vec4): Shadows color in RGBA + * - u_colorHighlight (vec4): Highlights color in RGBA + * - u_shadows (float): Color gradient added over image and background, following distortion shape (0 to 1) + * - u_highlights (float): Thin strokes along distortion shape, useful for antialiasing on small grid (0 to 1) + * - u_size (float): Size of the distortion shape grid (0 to 1) + * - u_shape (float): Grid shape (1 = lines, 2 = linesIrregular, 3 = wave, 4 = zigzag, 5 = pattern) + * - u_angle (float): Direction of the grid relative to the image in degrees (0 to 180) + * - u_distortionShape (float): Shape of distortion (1 = prism, 2 = lens, 3 = contour, 4 = cascade, 5 = flat) + * - u_distortion (float): Power of distortion applied within each stripe (0 to 1) + * - u_shift (float): Texture shift in direction opposite to the grid (-1 to 1) + * - u_stretch (float): Extra distortion along the grid lines (0 to 1) + * - u_blur (float): One-directional blur over the image and extra blur around edges (0 to 1) + * - u_edges (float): Glass distortion and softness on the image edges (0 to 1) + * - u_marginLeft (float): Distance from the left edge to the effect (0 to 1) + * - u_marginRight (float): Distance from the right edge to the effect (0 to 1) + * - u_marginTop (float): Distance from the top edge to the effect (0 to 1) + * - u_marginBottom (float): Distance from the bottom edge to the effect (0 to 1) + * - u_grainMixer (float): Strength of grain distortion applied to shape edges (0 to 1) + * - u_grainOverlay (float): Post-processing black/white grain overlay (0 to 1) + * + * Vertex shader outputs (used in fragment shader): + * - v_imageUV (vec2): Image UV coordinates with global sizing (rotation, scale, offset, etc) applied + * + * Vertex shader uniforms: + * - u_resolution (vec2): Canvas resolution in pixels + * - u_pixelRatio (float): Device pixel ratio + * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1) + * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1) + * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover) + * - u_scale (float): Overall zoom level of the graphics (0.01 to 4) + * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360) + * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1) + * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1) + * - u_imageAspectRatio (float): Aspect ratio of the source image + * + */ +export declare const flutedGlassFragmentShader: string; +export interface FlutedGlassUniforms extends ShaderSizingUniforms { + u_image: HTMLImageElement | string | undefined; + u_colorBack: [number, number, number, number]; + u_colorShadow: [number, number, number, number]; + u_colorHighlight: [number, number, number, number]; + u_shadows: number; + u_size: number; + u_angle: number; + u_distortion: number; + u_shift: number; + u_blur: number; + u_edges: number; + u_marginLeft: number; + u_marginRight: number; + u_marginTop: number; + u_marginBottom: number; + u_stretch: number; + u_distortionShape: (typeof GlassDistortionShapes)[GlassDistortionShape]; + u_highlights: number; + u_shape: (typeof GlassGridShapes)[GlassGridShape]; + u_grainMixer: number; + u_grainOverlay: number; + u_noiseTexture?: HTMLImageElement; +} +export interface FlutedGlassParams extends ShaderSizingParams, ShaderMotionParams { + image?: HTMLImageElement | string; + colorBack?: string; + colorShadow?: string; + colorHighlight?: string; + shadows?: number; + size?: number; + angle?: number; + distortion?: number; + shift?: number; + blur?: number; + edges?: number; + margin?: number; + marginLeft?: number; + marginRight?: number; + marginTop?: number; + marginBottom?: number; + stretch?: number; + distortionShape?: GlassDistortionShape; + highlights?: number; + shape?: GlassGridShape; + grainMixer?: number; + grainOverlay?: number; +} +export declare const GlassGridShapes: { + readonly lines: 1; + readonly linesIrregular: 2; + readonly wave: 3; + readonly zigzag: 4; + readonly pattern: 5; +}; +export declare const GlassDistortionShapes: { + readonly prism: 1; + readonly lens: 2; + readonly contour: 3; + readonly cascade: 4; + readonly flat: 5; +}; +export type GlassDistortionShape = keyof typeof GlassDistortionShapes; +export type GlassGridShape = keyof typeof GlassGridShapes; diff --git a/public/vendor/paper-shaders/shaders/fluted-glass.js b/public/vendor/paper-shaders/shaders/fluted-glass.js new file mode 100644 index 0000000..5f4a788 --- /dev/null +++ b/public/vendor/paper-shaders/shaders/fluted-glass.js @@ -0,0 +1,358 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Paper Shaders * + * https://github.com/paper-design/shaders * + * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +import {} from "../shader-sizing.js"; +import { declarePI, rotation2, proceduralHash21 } from "../shader-utils.js"; +const flutedGlassFragmentShader = `#version 300 es +precision mediump float; + +uniform vec2 u_resolution; +uniform float u_pixelRatio; +uniform float u_rotation; + +uniform vec4 u_colorBack; +uniform vec4 u_colorShadow; +uniform vec4 u_colorHighlight; + +uniform sampler2D u_image; +uniform float u_imageAspectRatio; + +uniform float u_size; +uniform float u_shadows; +uniform float u_angle; +uniform float u_stretch; +uniform float u_shape; +uniform float u_distortion; +uniform float u_highlights; +uniform float u_distortionShape; +uniform float u_shift; +uniform float u_blur; +uniform float u_edges; +uniform float u_marginLeft; +uniform float u_marginRight; +uniform float u_marginTop; +uniform float u_marginBottom; +uniform float u_grainMixer; +uniform float u_grainOverlay; + +in vec2 v_imageUV; + +out vec4 fragColor; + +${declarePI} +${rotation2} +${proceduralHash21} + +float valueNoise(vec2 st) { + vec2 i = floor(st); + vec2 f = fract(st); + float a = hash21(i); + float b = hash21(i + vec2(1.0, 0.0)); + float c = hash21(i + vec2(0.0, 1.0)); + float d = hash21(i + vec2(1.0, 1.0)); + vec2 u = f * f * (3.0 - 2.0 * f); + float x1 = mix(a, b, u.x); + float x2 = mix(c, d, u.x); + return mix(x1, x2, u.y); +} + +float getUvFrame(vec2 uv, float softness) { + float aax = 2. * fwidth(uv.x); + float aay = 2. * fwidth(uv.y); + float left = smoothstep(0., aax + softness, uv.x); + float right = 1. - smoothstep(1. - softness - aax, 1., uv.x); + float bottom = smoothstep(0., aay + softness, uv.y); + float top = 1. - smoothstep(1. - softness - aay, 1., uv.y); + return left * right * bottom * top; +} + +const int MAX_RADIUS = 50; +vec4 samplePremultiplied(sampler2D tex, vec2 uv) { + vec4 c = texture(tex, uv); + c.rgb *= c.a; + return c; +} +vec4 getBlur(sampler2D tex, vec2 uv, vec2 texelSize, vec2 dir, float sigma) { + if (sigma <= .5) return texture(tex, uv); + int radius = int(min(float(MAX_RADIUS), ceil(3.0 * sigma))); + + float twoSigma2 = 2.0 * sigma * sigma; + float gaussianNorm = 1.0 / sqrt(TWO_PI * sigma * sigma); + + vec4 sum = samplePremultiplied(tex, uv) * gaussianNorm; + float weightSum = gaussianNorm; + + for (int i = 1; i <= MAX_RADIUS; i++) { + if (i > radius) break; + + float x = float(i); + float w = exp(-(x * x) / twoSigma2) * gaussianNorm; + + vec2 offset = dir * texelSize * x; + vec4 s1 = samplePremultiplied(tex, uv + offset); + vec4 s2 = samplePremultiplied(tex, uv - offset); + + sum += (s1 + s2) * w; + weightSum += 2.0 * w; + } + + vec4 result = sum / weightSum; + if (result.a > 0.) { + result.rgb /= result.a; + } + + return result; +} + +vec2 rotateAspect(vec2 p, float a, float aspect) { + p.x *= aspect; + p = rotate(p, a); + p.x /= aspect; + return p; +} + +float smoothFract(float x) { + float f = fract(x); + float w = fwidth(x); + + float edge = abs(f - 0.5) - 0.5; + float band = smoothstep(-w, w, edge); + + return mix(f, 1.0 - f, band); +} + +void main() { + + float patternRotation = -u_angle * PI / 180.; + float patternSize = mix(200., 5., u_size); + + vec2 uv = v_imageUV; + + vec2 uvMask = gl_FragCoord.xy / u_resolution.xy; + vec2 sw = vec2(.005); + vec4 margins = vec4(u_marginLeft, u_marginTop, u_marginRight, u_marginBottom); + float mask = + smoothstep(margins[0], margins[0] + sw.x, uvMask.x + sw.x) * + smoothstep(margins[2], margins[2] + sw.x, 1.0 - uvMask.x + sw.x) * + smoothstep(margins[1], margins[1] + sw.y, uvMask.y + sw.y) * + smoothstep(margins[3], margins[3] + sw.y, 1.0 - uvMask.y + sw.y); + float maskOuter = + smoothstep(margins[0] - sw.x, margins[0], uvMask.x + sw.x) * + smoothstep(margins[2] - sw.x, margins[2], 1.0 - uvMask.x + sw.x) * + smoothstep(margins[1] - sw.y, margins[1], uvMask.y + sw.y) * + smoothstep(margins[3] - sw.y, margins[3], 1.0 - uvMask.y + sw.y); + float maskStroke = maskOuter - mask; + float maskInner = + smoothstep(margins[0] - 2. * sw.x, margins[0], uvMask.x) * + smoothstep(margins[2] - 2. * sw.x, margins[2], 1.0 - uvMask.x) * + smoothstep(margins[1] - 2. * sw.y, margins[1], uvMask.y) * + smoothstep(margins[3] - 2. * sw.y, margins[3], 1.0 - uvMask.y); + float maskStrokeInner = maskInner - mask; + + uv -= .5; + uv *= patternSize; + uv = rotateAspect(uv, patternRotation, u_imageAspectRatio); + + float curve = 0.; + float patternY = uv.y / u_imageAspectRatio; + if (u_shape > 4.5) { + // pattern + curve = .5 + .5 * sin(.5 * PI * uv.x) * cos(.5 * PI * patternY); + } else if (u_shape > 3.5) { + // zigzag + curve = 10. * abs(fract(.1 * patternY) - .5); + } else if (u_shape > 2.5) { + // wave + curve = 4. * sin(.23 * patternY); + } else if (u_shape > 1.5) { + // lines irregular + curve = .5 + .5 * sin(.5 * uv.x) * sin(1.7 * uv.x); + } else { + // lines + } + + vec2 UvToFract = uv + curve; + vec2 fractOrigUV = fract(uv); + vec2 floorOrigUV = floor(uv); + + float x = smoothFract(UvToFract.x); + float xNonSmooth = fract(UvToFract.x) + .0001; + + float highlightsWidth = 2. * max(.001, fwidth(UvToFract.x)); + highlightsWidth += 2. * maskStrokeInner; + float highlights = smoothstep(0., highlightsWidth, xNonSmooth); + highlights *= smoothstep(1., 1. - highlightsWidth, xNonSmooth); + highlights = 1. - highlights; + highlights *= u_highlights; + highlights = clamp(highlights, 0., 1.); + highlights *= mask; + + float shadows = pow(x, 1.3); + float distortion = 0.; + float fadeX = 1.; + float frameFade = 0.; + + float aa = fwidth(xNonSmooth); + aa = max(aa, fwidth(uv.x)); + aa = max(aa, fwidth(UvToFract.x)); + aa = max(aa, .0001); + + if (u_distortionShape == 1.) { + distortion = -pow(1.5 * x, 3.); + distortion += (.5 - u_shift); + + frameFade = pow(1.5 * x, 3.); + aa = max(.2, aa); + aa += mix(.2, 0., u_size); + fadeX = smoothstep(0., aa, xNonSmooth) * smoothstep(1., 1. - aa, xNonSmooth); + distortion = mix(.5, distortion, fadeX); + } else if (u_distortionShape == 2.) { + distortion = 2. * pow(x, 2.); + distortion -= (.5 + u_shift); + + frameFade = pow(abs(x - .5), 4.); + aa = max(.2, aa); + aa += mix(.2, 0., u_size); + fadeX = smoothstep(0., aa, xNonSmooth) * smoothstep(1., 1. - aa, xNonSmooth); + distortion = mix(.5, distortion, fadeX); + frameFade = mix(1., frameFade, .5 * fadeX); + } else if (u_distortionShape == 3.) { + distortion = pow(2. * (xNonSmooth - .5), 6.); + distortion -= .25; + distortion -= u_shift; + + frameFade = 1. - 2. * pow(abs(x - .4), 2.); + aa = .15; + aa += mix(.1, 0., u_size); + fadeX = smoothstep(0., aa, xNonSmooth) * smoothstep(1., 1. - aa, xNonSmooth); + frameFade = mix(1., frameFade, fadeX); + + } else if (u_distortionShape == 4.) { + x = xNonSmooth; + distortion = sin((x + .25) * TWO_PI); + shadows = .5 + .5 * asin(distortion) / (.5 * PI); + distortion *= .5; + distortion -= u_shift; + frameFade = .5 + .5 * sin(x * TWO_PI); + } else if (u_distortionShape == 5.) { + distortion -= pow(abs(x), .2) * x; + distortion += .33; + distortion -= 3. * u_shift; + distortion *= .33; + + frameFade = .3 * (smoothstep(.0, 1., x)); + shadows = pow(x, 2.5); + + aa = max(.1, aa); + aa += mix(.1, 0., u_size); + fadeX = smoothstep(0., aa, xNonSmooth) * smoothstep(1., 1. - aa, xNonSmooth); + distortion *= fadeX; + } + + vec2 dudx = dFdx(v_imageUV); + vec2 dudy = dFdy(v_imageUV); + vec2 grainUV = v_imageUV - .5; + grainUV *= (.8 / vec2(length(dudx), length(dudy))); + grainUV += .5; + float grain = valueNoise(grainUV); + grain = smoothstep(.4, .7, grain); + grain *= u_grainMixer; + distortion = mix(distortion, 0., grain); + + shadows = min(shadows, 1.); + shadows += maskStrokeInner; + shadows *= mask; + shadows = min(shadows, 1.); + shadows *= pow(u_shadows, 2.); + shadows = clamp(shadows, 0., 1.); + + distortion *= 3. * u_distortion; + frameFade *= u_distortion; + + fractOrigUV.x += distortion; + floorOrigUV = rotateAspect(floorOrigUV, -patternRotation, u_imageAspectRatio); + fractOrigUV = rotateAspect(fractOrigUV, -patternRotation, u_imageAspectRatio); + + uv = (floorOrigUV + fractOrigUV) / patternSize; + uv += pow(maskStroke, 4.); + + uv += vec2(.5); + + uv = mix(v_imageUV, uv, smoothstep(0., .7, mask)); + float blur = mix(0., 50., u_blur); + blur = mix(0., blur, smoothstep(.5, 1., mask)); + + float edgeDistortion = mix(.0, .04, u_edges); + edgeDistortion += .06 * frameFade * u_edges; + edgeDistortion *= mask; + float frame = getUvFrame(uv, edgeDistortion); + + float stretch = 1. - smoothstep(0., .5, xNonSmooth) * smoothstep(1., 1. - .5, xNonSmooth); + stretch = pow(stretch, 2.); + stretch *= mask; + stretch *= getUvFrame(uv, .1 + .05 * mask * frameFade); + uv.y = mix(uv.y, .5, u_stretch * stretch); + + vec4 image = getBlur(u_image, uv, 1. / u_resolution / u_pixelRatio, vec2(0., 1.), blur); + image.rgb *= image.a; + vec4 backColor = u_colorBack; + backColor.rgb *= backColor.a; + vec4 highlightColor = u_colorHighlight; + highlightColor.rgb *= highlightColor.a; + vec4 shadowColor = u_colorShadow; + + vec3 color = highlightColor.rgb * highlights; + float opacity = highlightColor.a * highlights; + + shadows = mix(shadows * shadowColor.a, 0., highlights); + color = mix(color, shadowColor.rgb * shadowColor.a, .5 * shadows); + color += .5 * pow(shadows, .5) * shadowColor.rgb; + opacity += shadows; + color = clamp(color, vec3(0.), vec3(1.)); + opacity = clamp(opacity, 0., 1.); + + color += image.rgb * (1. - opacity) * frame; + opacity += image.a * (1. - opacity) * frame; + + color += backColor.rgb * (1. - opacity); + opacity += backColor.a * (1. - opacity); + + float grainOverlay = valueNoise(rotate(grainUV, 1.) + vec2(3.)); + grainOverlay = mix(grainOverlay, valueNoise(rotate(grainUV, 2.) + vec2(-1.)), .5); + grainOverlay = pow(grainOverlay, 1.3); + + float grainOverlayV = grainOverlay * 2. - 1.; + vec3 grainOverlayColor = vec3(step(0., grainOverlayV)); + float grainOverlayStrength = u_grainOverlay * abs(grainOverlayV); + grainOverlayStrength = pow(grainOverlayStrength, .8); + grainOverlayStrength *= mask; + color = mix(color, grainOverlayColor, .35 * grainOverlayStrength); + + opacity += .5 * grainOverlayStrength; + opacity = clamp(opacity, 0., 1.); + + fragColor = vec4(color, opacity); +} +`; +const GlassGridShapes = { + lines: 1, + linesIrregular: 2, + wave: 3, + zigzag: 4, + pattern: 5 +}; +const GlassDistortionShapes = { + prism: 1, + lens: 2, + contour: 3, + cascade: 4, + flat: 5 +}; +export { + GlassDistortionShapes, + GlassGridShapes, + flutedGlassFragmentShader +}; +//# sourceMappingURL=fluted-glass.js.map diff --git a/public/vendor/paper-shaders/shaders/fluted-glass.js.map b/public/vendor/paper-shaders/shaders/fluted-glass.js.map new file mode 100644 index 0000000..888b1ca --- /dev/null +++ b/public/vendor/paper-shaders/shaders/fluted-glass.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../../src/shaders/fluted-glass.ts"], + "sourcesContent": ["import type { ShaderMotionParams } from '../shader-mount.js';\nimport { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { declarePI, rotation2, proceduralHash21 } from '../shader-utils.js';\n\n/**\n * Fluted glass image filter that transforms an image into streaked, ribbed distortions,\n * giving a mix of clarity and obscurity.\n *\n * Fragment shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_image (sampler2D): Source image texture\n * - u_imageAspectRatio (float): Aspect ratio of the source image\n * - u_colorBack (vec4): Background color in RGBA\n * - u_colorShadow (vec4): Shadows color in RGBA\n * - u_colorHighlight (vec4): Highlights color in RGBA\n * - u_shadows (float): Color gradient added over image and background, following distortion shape (0 to 1)\n * - u_highlights (float): Thin strokes along distortion shape, useful for antialiasing on small grid (0 to 1)\n * - u_size (float): Size of the distortion shape grid (0 to 1)\n * - u_shape (float): Grid shape (1 = lines, 2 = linesIrregular, 3 = wave, 4 = zigzag, 5 = pattern)\n * - u_angle (float): Direction of the grid relative to the image in degrees (0 to 180)\n * - u_distortionShape (float): Shape of distortion (1 = prism, 2 = lens, 3 = contour, 4 = cascade, 5 = flat)\n * - u_distortion (float): Power of distortion applied within each stripe (0 to 1)\n * - u_shift (float): Texture shift in direction opposite to the grid (-1 to 1)\n * - u_stretch (float): Extra distortion along the grid lines (0 to 1)\n * - u_blur (float): One-directional blur over the image and extra blur around edges (0 to 1)\n * - u_edges (float): Glass distortion and softness on the image edges (0 to 1)\n * - u_marginLeft (float): Distance from the left edge to the effect (0 to 1)\n * - u_marginRight (float): Distance from the right edge to the effect (0 to 1)\n * - u_marginTop (float): Distance from the top edge to the effect (0 to 1)\n * - u_marginBottom (float): Distance from the bottom edge to the effect (0 to 1)\n * - u_grainMixer (float): Strength of grain distortion applied to shape edges (0 to 1)\n * - u_grainOverlay (float): Post-processing black/white grain overlay (0 to 1)\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_imageUV (vec2): Image UV coordinates with global sizing (rotation, scale, offset, etc) applied\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n * - u_imageAspectRatio (float): Aspect ratio of the source image\n *\n */\n\n// language=GLSL\nexport const flutedGlassFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform vec2 u_resolution;\nuniform float u_pixelRatio;\nuniform float u_rotation;\n\nuniform vec4 u_colorBack;\nuniform vec4 u_colorShadow;\nuniform vec4 u_colorHighlight;\n\nuniform sampler2D u_image;\nuniform float u_imageAspectRatio;\n\nuniform float u_size;\nuniform float u_shadows;\nuniform float u_angle;\nuniform float u_stretch;\nuniform float u_shape;\nuniform float u_distortion;\nuniform float u_highlights;\nuniform float u_distortionShape;\nuniform float u_shift;\nuniform float u_blur;\nuniform float u_edges;\nuniform float u_marginLeft;\nuniform float u_marginRight;\nuniform float u_marginTop;\nuniform float u_marginBottom;\nuniform float u_grainMixer;\nuniform float u_grainOverlay;\n\nin vec2 v_imageUV;\n\nout vec4 fragColor;\n\n${ declarePI }\n${ rotation2 }\n${ proceduralHash21 }\n\nfloat valueNoise(vec2 st) {\n vec2 i = floor(st);\n vec2 f = fract(st);\n float a = hash21(i);\n float b = hash21(i + vec2(1.0, 0.0));\n float c = hash21(i + vec2(0.0, 1.0));\n float d = hash21(i + vec2(1.0, 1.0));\n vec2 u = f * f * (3.0 - 2.0 * f);\n float x1 = mix(a, b, u.x);\n float x2 = mix(c, d, u.x);\n return mix(x1, x2, u.y);\n}\n\nfloat getUvFrame(vec2 uv, float softness) {\n float aax = 2. * fwidth(uv.x);\n float aay = 2. * fwidth(uv.y);\n float left = smoothstep(0., aax + softness, uv.x);\n float right = 1. - smoothstep(1. - softness - aax, 1., uv.x);\n float bottom = smoothstep(0., aay + softness, uv.y);\n float top = 1. - smoothstep(1. - softness - aay, 1., uv.y);\n return left * right * bottom * top;\n}\n\nconst int MAX_RADIUS = 50;\nvec4 samplePremultiplied(sampler2D tex, vec2 uv) {\n vec4 c = texture(tex, uv);\n c.rgb *= c.a;\n return c;\n}\nvec4 getBlur(sampler2D tex, vec2 uv, vec2 texelSize, vec2 dir, float sigma) {\n if (sigma <= .5) return texture(tex, uv);\n int radius = int(min(float(MAX_RADIUS), ceil(3.0 * sigma)));\n\n float twoSigma2 = 2.0 * sigma * sigma;\n float gaussianNorm = 1.0 / sqrt(TWO_PI * sigma * sigma);\n\n vec4 sum = samplePremultiplied(tex, uv) * gaussianNorm;\n float weightSum = gaussianNorm;\n\n for (int i = 1; i <= MAX_RADIUS; i++) {\n if (i > radius) break;\n\n float x = float(i);\n float w = exp(-(x * x) / twoSigma2) * gaussianNorm;\n\n vec2 offset = dir * texelSize * x;\n vec4 s1 = samplePremultiplied(tex, uv + offset);\n vec4 s2 = samplePremultiplied(tex, uv - offset);\n\n sum += (s1 + s2) * w;\n weightSum += 2.0 * w;\n }\n\n vec4 result = sum / weightSum;\n if (result.a > 0.) {\n result.rgb /= result.a;\n }\n\n return result;\n}\n\nvec2 rotateAspect(vec2 p, float a, float aspect) {\n p.x *= aspect;\n p = rotate(p, a);\n p.x /= aspect;\n return p;\n}\n\nfloat smoothFract(float x) {\n float f = fract(x);\n float w = fwidth(x);\n\n float edge = abs(f - 0.5) - 0.5;\n float band = smoothstep(-w, w, edge);\n\n return mix(f, 1.0 - f, band);\n}\n\nvoid main() {\n\n float patternRotation = -u_angle * PI / 180.;\n float patternSize = mix(200., 5., u_size);\n\n vec2 uv = v_imageUV;\n\n vec2 uvMask = gl_FragCoord.xy / u_resolution.xy;\n vec2 sw = vec2(.005);\n vec4 margins = vec4(u_marginLeft, u_marginTop, u_marginRight, u_marginBottom);\n float mask =\n smoothstep(margins[0], margins[0] + sw.x, uvMask.x + sw.x) *\n smoothstep(margins[2], margins[2] + sw.x, 1.0 - uvMask.x + sw.x) *\n smoothstep(margins[1], margins[1] + sw.y, uvMask.y + sw.y) *\n smoothstep(margins[3], margins[3] + sw.y, 1.0 - uvMask.y + sw.y);\n float maskOuter =\n smoothstep(margins[0] - sw.x, margins[0], uvMask.x + sw.x) *\n smoothstep(margins[2] - sw.x, margins[2], 1.0 - uvMask.x + sw.x) *\n smoothstep(margins[1] - sw.y, margins[1], uvMask.y + sw.y) *\n smoothstep(margins[3] - sw.y, margins[3], 1.0 - uvMask.y + sw.y);\n float maskStroke = maskOuter - mask;\n float maskInner =\n smoothstep(margins[0] - 2. * sw.x, margins[0], uvMask.x) *\n smoothstep(margins[2] - 2. * sw.x, margins[2], 1.0 - uvMask.x) *\n smoothstep(margins[1] - 2. * sw.y, margins[1], uvMask.y) *\n smoothstep(margins[3] - 2. * sw.y, margins[3], 1.0 - uvMask.y);\n float maskStrokeInner = maskInner - mask;\n\n uv -= .5;\n uv *= patternSize;\n uv = rotateAspect(uv, patternRotation, u_imageAspectRatio);\n\n float curve = 0.;\n float patternY = uv.y / u_imageAspectRatio;\n if (u_shape > 4.5) {\n // pattern\n curve = .5 + .5 * sin(.5 * PI * uv.x) * cos(.5 * PI * patternY);\n } else if (u_shape > 3.5) {\n // zigzag\n curve = 10. * abs(fract(.1 * patternY) - .5);\n } else if (u_shape > 2.5) {\n // wave\n curve = 4. * sin(.23 * patternY);\n } else if (u_shape > 1.5) {\n // lines irregular\n curve = .5 + .5 * sin(.5 * uv.x) * sin(1.7 * uv.x);\n } else {\n // lines\n }\n\n vec2 UvToFract = uv + curve;\n vec2 fractOrigUV = fract(uv);\n vec2 floorOrigUV = floor(uv);\n\n float x = smoothFract(UvToFract.x);\n float xNonSmooth = fract(UvToFract.x) + .0001;\n\n float highlightsWidth = 2. * max(.001, fwidth(UvToFract.x));\n highlightsWidth += 2. * maskStrokeInner;\n float highlights = smoothstep(0., highlightsWidth, xNonSmooth);\n highlights *= smoothstep(1., 1. - highlightsWidth, xNonSmooth);\n highlights = 1. - highlights;\n highlights *= u_highlights;\n highlights = clamp(highlights, 0., 1.);\n highlights *= mask;\n\n float shadows = pow(x, 1.3);\n float distortion = 0.;\n float fadeX = 1.;\n float frameFade = 0.;\n\n float aa = fwidth(xNonSmooth);\n aa = max(aa, fwidth(uv.x));\n aa = max(aa, fwidth(UvToFract.x));\n aa = max(aa, .0001);\n\n if (u_distortionShape == 1.) {\n distortion = -pow(1.5 * x, 3.);\n distortion += (.5 - u_shift);\n\n frameFade = pow(1.5 * x, 3.);\n aa = max(.2, aa);\n aa += mix(.2, 0., u_size);\n fadeX = smoothstep(0., aa, xNonSmooth) * smoothstep(1., 1. - aa, xNonSmooth);\n distortion = mix(.5, distortion, fadeX);\n } else if (u_distortionShape == 2.) {\n distortion = 2. * pow(x, 2.);\n distortion -= (.5 + u_shift);\n\n frameFade = pow(abs(x - .5), 4.);\n aa = max(.2, aa);\n aa += mix(.2, 0., u_size);\n fadeX = smoothstep(0., aa, xNonSmooth) * smoothstep(1., 1. - aa, xNonSmooth);\n distortion = mix(.5, distortion, fadeX);\n frameFade = mix(1., frameFade, .5 * fadeX);\n } else if (u_distortionShape == 3.) {\n distortion = pow(2. * (xNonSmooth - .5), 6.);\n distortion -= .25;\n distortion -= u_shift;\n\n frameFade = 1. - 2. * pow(abs(x - .4), 2.);\n aa = .15;\n aa += mix(.1, 0., u_size);\n fadeX = smoothstep(0., aa, xNonSmooth) * smoothstep(1., 1. - aa, xNonSmooth);\n frameFade = mix(1., frameFade, fadeX);\n\n } else if (u_distortionShape == 4.) {\n x = xNonSmooth;\n distortion = sin((x + .25) * TWO_PI);\n shadows = .5 + .5 * asin(distortion) / (.5 * PI);\n distortion *= .5;\n distortion -= u_shift;\n frameFade = .5 + .5 * sin(x * TWO_PI);\n } else if (u_distortionShape == 5.) {\n distortion -= pow(abs(x), .2) * x;\n distortion += .33;\n distortion -= 3. * u_shift;\n distortion *= .33;\n\n frameFade = .3 * (smoothstep(.0, 1., x));\n shadows = pow(x, 2.5);\n\n aa = max(.1, aa);\n aa += mix(.1, 0., u_size);\n fadeX = smoothstep(0., aa, xNonSmooth) * smoothstep(1., 1. - aa, xNonSmooth);\n distortion *= fadeX;\n }\n\n vec2 dudx = dFdx(v_imageUV);\n vec2 dudy = dFdy(v_imageUV);\n vec2 grainUV = v_imageUV - .5;\n grainUV *= (.8 / vec2(length(dudx), length(dudy)));\n grainUV += .5;\n float grain = valueNoise(grainUV);\n grain = smoothstep(.4, .7, grain);\n grain *= u_grainMixer;\n distortion = mix(distortion, 0., grain);\n\n shadows = min(shadows, 1.);\n shadows += maskStrokeInner;\n shadows *= mask;\n shadows = min(shadows, 1.);\n shadows *= pow(u_shadows, 2.);\n shadows = clamp(shadows, 0., 1.);\n\n distortion *= 3. * u_distortion;\n frameFade *= u_distortion;\n\n fractOrigUV.x += distortion;\n floorOrigUV = rotateAspect(floorOrigUV, -patternRotation, u_imageAspectRatio);\n fractOrigUV = rotateAspect(fractOrigUV, -patternRotation, u_imageAspectRatio);\n\n uv = (floorOrigUV + fractOrigUV) / patternSize;\n uv += pow(maskStroke, 4.);\n\n uv += vec2(.5);\n\n uv = mix(v_imageUV, uv, smoothstep(0., .7, mask));\n float blur = mix(0., 50., u_blur);\n blur = mix(0., blur, smoothstep(.5, 1., mask));\n\n float edgeDistortion = mix(.0, .04, u_edges);\n edgeDistortion += .06 * frameFade * u_edges;\n edgeDistortion *= mask;\n float frame = getUvFrame(uv, edgeDistortion);\n\n float stretch = 1. - smoothstep(0., .5, xNonSmooth) * smoothstep(1., 1. - .5, xNonSmooth);\n stretch = pow(stretch, 2.);\n stretch *= mask;\n stretch *= getUvFrame(uv, .1 + .05 * mask * frameFade);\n uv.y = mix(uv.y, .5, u_stretch * stretch);\n\n vec4 image = getBlur(u_image, uv, 1. / u_resolution / u_pixelRatio, vec2(0., 1.), blur);\n image.rgb *= image.a;\n vec4 backColor = u_colorBack;\n backColor.rgb *= backColor.a;\n vec4 highlightColor = u_colorHighlight;\n highlightColor.rgb *= highlightColor.a;\n vec4 shadowColor = u_colorShadow;\n\n vec3 color = highlightColor.rgb * highlights;\n float opacity = highlightColor.a * highlights;\n\n shadows = mix(shadows * shadowColor.a, 0., highlights);\n color = mix(color, shadowColor.rgb * shadowColor.a, .5 * shadows);\n color += .5 * pow(shadows, .5) * shadowColor.rgb;\n opacity += shadows;\n color = clamp(color, vec3(0.), vec3(1.));\n opacity = clamp(opacity, 0., 1.);\n\n color += image.rgb * (1. - opacity) * frame;\n opacity += image.a * (1. - opacity) * frame;\n\n color += backColor.rgb * (1. - opacity);\n opacity += backColor.a * (1. - opacity);\n\n float grainOverlay = valueNoise(rotate(grainUV, 1.) + vec2(3.));\n grainOverlay = mix(grainOverlay, valueNoise(rotate(grainUV, 2.) + vec2(-1.)), .5);\n grainOverlay = pow(grainOverlay, 1.3);\n\n float grainOverlayV = grainOverlay * 2. - 1.;\n vec3 grainOverlayColor = vec3(step(0., grainOverlayV));\n float grainOverlayStrength = u_grainOverlay * abs(grainOverlayV);\n grainOverlayStrength = pow(grainOverlayStrength, .8);\n grainOverlayStrength *= mask;\n color = mix(color, grainOverlayColor, .35 * grainOverlayStrength);\n\n opacity += .5 * grainOverlayStrength;\n opacity = clamp(opacity, 0., 1.);\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface FlutedGlassUniforms extends ShaderSizingUniforms {\n u_image: HTMLImageElement | string | undefined;\n u_colorBack: [number, number, number, number];\n u_colorShadow: [number, number, number, number];\n u_colorHighlight: [number, number, number, number];\n u_shadows: number;\n u_size: number;\n u_angle: number;\n u_distortion: number;\n u_shift: number;\n u_blur: number;\n u_edges: number;\n u_marginLeft: number;\n u_marginRight: number;\n u_marginTop: number;\n u_marginBottom: number;\n u_stretch: number;\n u_distortionShape: (typeof GlassDistortionShapes)[GlassDistortionShape];\n u_highlights: number;\n u_shape: (typeof GlassGridShapes)[GlassGridShape];\n u_grainMixer: number;\n u_grainOverlay: number;\n u_noiseTexture?: HTMLImageElement;\n}\n\nexport interface FlutedGlassParams extends ShaderSizingParams, ShaderMotionParams {\n image?: HTMLImageElement | string;\n colorBack?: string;\n colorShadow?: string;\n colorHighlight?: string;\n shadows?: number;\n size?: number;\n angle?: number;\n distortion?: number;\n shift?: number;\n blur?: number;\n edges?: number;\n margin?: number;\n marginLeft?: number;\n marginRight?: number;\n marginTop?: number;\n marginBottom?: number;\n stretch?: number;\n distortionShape?: GlassDistortionShape;\n highlights?: number;\n shape?: GlassGridShape;\n grainMixer?: number;\n grainOverlay?: number;\n}\n\nexport const GlassGridShapes = {\n lines: 1,\n linesIrregular: 2,\n wave: 3,\n zigzag: 4,\n pattern: 5,\n} as const;\n\nexport const GlassDistortionShapes = {\n prism: 1,\n lens: 2,\n contour: 3,\n cascade: 4,\n flat: 5,\n} as const;\n\nexport type GlassDistortionShape = keyof typeof GlassDistortionShapes;\nexport type GlassGridShape = keyof typeof GlassGridShapes;\n"], + "mappings": ";;;;;AACA,eAAmE;AACnE,SAAS,WAAW,WAAW,wBAAwB;AAmDhD,MAAM,4BAAoC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAoC9C,SAAU;AAAA,EACV,SAAU;AAAA,EACV,gBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAwVb,MAAM,kBAAkB;AAAA,EAC7B,OAAO;AAAA,EACP,gBAAgB;AAAA,EAChB,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,SAAS;AACX;AAEO,MAAM,wBAAwB;AAAA,EACnC,OAAO;AAAA,EACP,MAAM;AAAA,EACN,SAAS;AAAA,EACT,SAAS;AAAA,EACT,MAAM;AACR;", + "names": [] +} diff --git a/public/vendor/paper-shaders/shaders/gem-smoke.d.ts b/public/vendor/paper-shaders/shaders/gem-smoke.d.ts new file mode 100644 index 0000000..eaca83e --- /dev/null +++ b/public/vendor/paper-shaders/shaders/gem-smoke.d.ts @@ -0,0 +1,94 @@ +import type { vec4 } from '../types.js'; +import type { ShaderMotionParams } from '../shader-mount.js'; +import type { ShaderSizingParams, ShaderSizingUniforms } from '../shader-sizing.js'; +export declare const gemSmokeMeta: { + readonly maxColorCount: 6; +}; +/** + * Animated color fields placed over uploaded logo shape; gives the illusion of smoky noise + * behind the glassy shape. + * + * Fragment shader uniforms: + * - u_time (float): Animation time + * - u_resolution (vec2): Canvas resolution in pixels + * - u_image (sampler2D): Pre-processed source image texture (R = edge gradient, G = alpha) + * - u_imageAspectRatio (float): Aspect ratio of the source image + * - u_colors (vec4[]): Up to 6 smoke colors in RGBA + * - u_colorsCount (float): Number of active colors + * - u_colorBack (vec4): Background color in RGBA + * - u_innerDistortion (float): Power of smoke distortion inside the input shape (0 to 1) + * - u_outerDistortion (float): Power of smoke distortion outside the input shape (0 to 1) + * - u_outerGlow (float): Visibility of smoke shape outside the input shape (0 to 1) + * - u_innerGlow (float): Visibility of smoke shape inside the input shape (0 to 1) + * - u_colorInner (vec4): Additional color inside the input shape, mixing with smoke (RGBA) + * - u_offset (float): Vertical offset of smoke inside the shape (-1 to 1) + * - u_angle (float): Smoke direction in degrees (0 to 360) + * - u_size (float): Size of smoke shape relative to the image box (0 to 1) + * + * Vertex shader outputs (used in fragment shader): + * - v_imageUV (vec2): UV coordinates for sampling the source image, with fit, scale, rotation, and offset applied + * - v_objectUV (vec2): Normalized UV coordinates with scale, rotation, and offset applied + * + * Vertex shader uniforms: + * - u_resolution (vec2): Canvas resolution in pixels + * - u_pixelRatio (float): Device pixel ratio + * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1) + * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1) + * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas + * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas + * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover) + * - u_scale (float): Overall zoom level of the graphics (0.01 to 4) + * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360) + * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1) + * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1) + * - u_imageAspectRatio (float): Aspect ratio of the source image + * + */ +export declare const gemSmokeFragmentShader: string; +export declare const POISSON_CONFIG_OPTIMIZED: { + measurePerformance: boolean; + workingSize: number; + iterations: number; +}; +export declare function toProcessedGemSmoke(file: File | string): Promise<{ + imageData: ImageData; + pngBlob: Blob; +}>; +export interface GemSmokeUniforms extends ShaderSizingUniforms { + u_colorBack: [number, number, number, number]; + u_colors: vec4[]; + u_colorsCount: number; + u_image: HTMLImageElement | string | undefined; + u_innerDistortion: number; + u_outerDistortion: number; + u_outerGlow: number; + u_innerGlow: number; + u_colorInner: [number, number, number, number]; + u_offset: number; + u_angle: number; + u_size: number; + u_shape: (typeof GemSmokeShapes)[GemSmokeShape]; + u_isImage: boolean; +} +export interface GemSmokeParams extends ShaderSizingParams, ShaderMotionParams { + colors?: string[]; + colorBack?: string; + image?: HTMLImageElement | string | undefined; + innerDistortion?: number; + outerDistortion?: number; + outerGlow?: number; + innerGlow?: number; + colorInner?: string; + offset?: number; + angle?: number; + size?: number; + shape?: GemSmokeShape; +} +export declare const GemSmokeShapes: { + readonly none: 0; + readonly circle: 1; + readonly daisy: 2; + readonly diamond: 3; + readonly metaballs: 4; +}; +export type GemSmokeShape = keyof typeof GemSmokeShapes; diff --git a/public/vendor/paper-shaders/shaders/gem-smoke.js b/public/vendor/paper-shaders/shaders/gem-smoke.js new file mode 100644 index 0000000..327958c --- /dev/null +++ b/public/vendor/paper-shaders/shaders/gem-smoke.js @@ -0,0 +1,585 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Paper Shaders * + * https://github.com/paper-design/shaders * + * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +import { rotation2, declarePI } from "../shader-utils.js"; +const gemSmokeMeta = { + maxColorCount: 6 +}; +const gemSmokeFragmentShader = `#version 300 es +precision mediump float; + +in mediump vec2 v_imageUV; +in mediump vec2 v_objectUV; +in mediump vec2 v_responsiveUV; +in mediump vec2 v_responsiveBoxGivenSize; +out vec4 fragColor; + +// Image +uniform sampler2D u_image; +uniform float u_imageAspectRatio; + +// Canvas +uniform vec2 u_resolution; +uniform float u_time; + +// Colors +uniform vec4 u_colors[${gemSmokeMeta.maxColorCount}]; +uniform float u_colorsCount; +uniform vec4 u_colorBack; +uniform vec4 u_colorInner; + +// Effect controls +uniform float u_innerDistortion; +uniform float u_outerDistortion; +uniform float u_outerGlow; +uniform float u_innerGlow; +uniform float u_offset; +uniform float u_angle; +uniform float u_size; + +// Shape controls +uniform float u_shape; +uniform bool u_isImage; + +${declarePI} +${rotation2} + +// 9x9 Gaussian blur on R and G channels +vec2 gaussBlur9x9RG(sampler2D tex, vec2 uv, vec2 dudx, vec2 dudy, float radius) { + vec2 texel = 1.0 / vec2(textureSize(tex, 0)); + vec2 r = max(radius, 0.0) * texel; + // Pascal's row 8: sum = 256, 2D norm = 65536 + const float k[9] = float[9](1.0, 8.0, 28.0, 56.0, 70.0, 56.0, 28.0, 8.0, 1.0); + vec2 sum = vec2(0.0); + + for (int j = -4; j <= 4; ++j) { + float wy = k[j + 4]; + for (int i = -4; i <= 4; ++i) { + float w = k[i + 4] * wy; + vec2 off = vec2(float(i) * r.x, float(j) * r.y); + sum += w * texture(tex, uv + off).rg; + } + } + + return sum / 65536.0; +} + +float sst(float a, float b, float x) { + return smoothstep(a, b, x); +} + +void main() { + float time = u_time; + + float roundness = 0.; + float imgAlpha = 0.; + + if (u_isImage == true) { + // Image sampling (UV scaled inward to account for padding) + vec2 imageUV = v_imageUV; + imageUV -= .5; + imageUV *= .95; + imageUV += .5; + + vec2 dudx = dFdx(v_imageUV); + vec2 dudy = dFdy(v_imageUV); + + // Blurred image: x = roundness, y = alpha + vec2 blurred = gaussBlur9x9RG(u_image, imageUV, dudx, dudy, 10.); + roundness = 1. - blurred.x; + vec2 texelA = 1.0 / vec2(textureSize(u_image, 0)); + const float k3[3] = float[3](1.0, 2.0, 1.0); + for (int j = -1; j <= 1; ++j) { + for (int i = -1; i <= 1; ++i) { + imgAlpha += k3[i + 1] * k3[j + 1] * texture(u_image, imageUV + vec2(float(i) * texelA.x, float(j) * texelA.y)).g; + } + } + imgAlpha /= 16.0; + } else { + vec2 uv = v_objectUV + .5; + uv.y = 1. - uv.y; + float edge = 0.; + + if (u_shape < 1.) { + // full-fill on canvas + vec2 borderUV = v_responsiveUV + .5; + vec2 mask = min(borderUV, 1. - borderUV); + vec2 pixel_thickness = min(250. / v_responsiveBoxGivenSize, vec2(.5)); + float maskX = smoothstep(0.0, pixel_thickness.x, mask.x); + float maskY = smoothstep(0.0, pixel_thickness.y, mask.y); + maskX = pow(maskX, .25); + maskY = pow(maskY, .25); + edge = clamp(1. - maskX * maskY, 0., 1.); + } else if (u_shape < 2.) { + // circle + vec2 shapeUV = uv - .5; + shapeUV *= .67; + edge = pow(clamp(3. * length(shapeUV), 0., 1.), 18.); + } else if (u_shape < 3.) { + // daisy + vec2 shapeUV = uv - .5; + shapeUV *= 1.68; + + float r = length(shapeUV) * 2.; + float a = atan(shapeUV.y, shapeUV.x) + .2; + r *= (1. + .05 * sin(3. * a + 2. * time)); + float f = abs(cos(a * 3.)); + edge = smoothstep(f, f + .7, r); + edge *= edge; + } else if (u_shape < 4.) { + // diamond + vec2 shapeUV = uv - .5; + shapeUV = rotate(shapeUV, .25 * PI); + shapeUV *= 1.42; + shapeUV += .5; + vec2 mask = min(shapeUV, 1. - shapeUV); + vec2 pixel_thickness = vec2(.15); + float maskX = smoothstep(0.0, pixel_thickness.x, mask.x); + float maskY = smoothstep(0.0, pixel_thickness.y, mask.y); + maskX = pow(maskX, .25); + maskY = pow(maskY, .25); + edge = clamp(1. - maskX * maskY, 0., 1.); + } else if (u_shape < 5.) { + // metaballs + vec2 shapeUV = uv - .5; + shapeUV *= 1.3; + edge = 0.; + for (int i = 0; i < 5; i++) { + float fi = float(i); + float speed = 1.5 + 2./3. * sin(fi * 12.345); + float angle = -fi * 1.5; + vec2 dir1 = vec2(cos(angle), sin(angle)); + vec2 dir2 = vec2(cos(angle + 1.57), sin(angle + 1.)); + vec2 traj = .4 * (dir1 * sin(time * speed + fi * 1.23) + dir2 * cos(time * (speed * 0.7) + fi * 2.17)); + float d = length(shapeUV + traj); + edge += pow(1.0 - clamp(d, 0.0, 1.0), 4.0); + } + edge = 1. - smoothstep(.65, .9, edge); + edge = pow(edge, 4.); + } + + imgAlpha = 1. - smoothstep(.9 - 2. * fwidth(edge), .9, edge); + roundness = 1. - edge; + } + +// Smoke UV setup + vec2 smokeUV = v_objectUV; + smokeUV = rotate(smokeUV, u_angle * PI / 180.); + smokeUV *= mix(4., 1., u_size); + + // Two swirl paths: inner (shape-masked) and outer (free), each with independent distortion + vec2 innerUV = smokeUV; + vec2 outerUV = smokeUV; + + // Vertical displacement \u2014 applied independently to inner and outer + innerUV.y += u_innerDistortion * (1. - sst(0., 1., length(.4 * innerUV))); + innerUV.y -= .4 * u_innerDistortion; + innerUV.y += .7 * u_offset * roundness; + + outerUV.y += u_outerDistortion * (1. - sst(0., 1., length(.4 * outerUV))); + outerUV.y -= .4 * u_outerDistortion; + + float innerSwirl = u_innerDistortion * roundness; + float outerSwirl = u_outerDistortion; + + for (int i = 1; i < 5; i++) { + float fi = float(i); + + float stretchIn = max(length(dFdx(innerUV)), length(dFdy(innerUV))); + float dampenIn = 1. / (1. + stretchIn * 8.); + float sIn = innerSwirl * dampenIn; + innerUV.x += sIn / fi * cos(time + fi * 2.9 * innerUV.y); + innerUV.y += sIn / fi * cos(time + fi * 1.5 * innerUV.x); + + float stretchOut = max(length(dFdx(outerUV)), length(dFdy(outerUV))); + float dampenOut = 1. / (1. + stretchOut * 8.); + float sOut = outerSwirl * dampenOut; + outerUV.x += sOut / fi * cos(time + fi * 2.9 * outerUV.y); + outerUV.y += sOut / fi * cos(time + fi * 1.5 * outerUV.x); + } + + // Smoke shapes from swirl fields + float innerShape = exp(-1.5 * dot(innerUV, innerUV)); + float outerShape = exp(-1.5 * dot(outerUV, outerUV)); + + // Visibility masks + float outerMask = pow(u_outerGlow, 2.) * (1. - imgAlpha); + float innerMask = (.01 + .99 * u_innerGlow) * imgAlpha; + + innerShape *= innerMask; + outerShape *= outerMask; + + // Color gradient + float mixer = (innerShape + outerShape) * u_colorsCount; + vec4 gradient = u_colors[0]; + gradient.rgb *= gradient.a; + + float smokeMask = 0.; + for (int i = 1; i < ${gemSmokeMeta.maxColorCount + 1}; i++) { + if (i > int(u_colorsCount)) break; + + float m = sst(0., 1., clamp(mixer - float(i - 1), 0., 1.)); + if (i == 1) smokeMask = m; + + vec4 c = u_colors[i - 1]; + c.rgb *= c.a; + gradient = mix(gradient, c, m); + } + + // Compositing (premultiplied alpha, front-to-back) + vec3 color = gradient.rgb * smokeMask; + float opacity = gradient.a * smokeMask; + + float innerOpacity = u_colorInner.a * imgAlpha; + vec3 innerColor = u_colorInner.rgb * innerOpacity; + color += innerColor * (1.0 - opacity); + opacity += innerOpacity * (1.0 - opacity); + + vec3 backColor = u_colorBack.rgb * u_colorBack.a; + color += backColor * (1.0 - opacity); + opacity += u_colorBack.a * (1.0 - opacity); + + fragColor = vec4(color, opacity); +} +`; +const POISSON_CONFIG_OPTIMIZED = { + measurePerformance: false, + // Set to true to see performance metrics + workingSize: 512, + // Size to solve Poisson at (will upscale to original size) + iterations: 32 + // SOR converges ~2-20x faster than standard Gauss-Seidel +}; +function toProcessedGemSmoke(file) { + const canvas = document.createElement("canvas"); + const ctx = canvas.getContext("2d"); + const isBlob = typeof file === "string" && file.startsWith("blob:"); + return new Promise((resolve, reject) => { + if (!file || !ctx) { + reject(new Error("Invalid file or canvas context")); + return; + } + const blobContentTypePromise = isBlob && fetch(file).then((res) => res.headers.get("Content-Type")); + const img = new Image(); + img.crossOrigin = "anonymous"; + const totalStartTime = performance.now(); + img.onload = async () => { + let isSVG; + const blobContentType = await blobContentTypePromise; + if (blobContentType) { + isSVG = blobContentType === "image/svg+xml"; + } else if (typeof file === "string") { + isSVG = file.endsWith(".svg") || file.startsWith("data:image/svg+xml"); + } else { + isSVG = file.type === "image/svg+xml"; + } + let originalWidth = img.width || img.naturalWidth; + let originalHeight = img.height || img.naturalHeight; + if (isSVG) { + const svgMaxSize = 4096; + const aspectRatio = originalWidth / originalHeight; + if (originalWidth > originalHeight) { + originalWidth = svgMaxSize; + originalHeight = svgMaxSize / aspectRatio; + } else { + originalHeight = svgMaxSize; + originalWidth = svgMaxSize * aspectRatio; + } + img.width = originalWidth; + img.height = originalHeight; + } + const minDimension = Math.min(originalWidth, originalHeight); + const targetSize = POISSON_CONFIG_OPTIMIZED.workingSize; + const scaleFactor = targetSize / minDimension; + const width = Math.round(originalWidth * scaleFactor); + const height = Math.round(originalHeight * scaleFactor); + if (POISSON_CONFIG_OPTIMIZED.measurePerformance) { + console.log(`[Processing Mode]`); + console.log(` Original: ${originalWidth}\xD7${originalHeight}`); + console.log(` Working: ${width}\xD7${height} (${(scaleFactor * 100).toFixed(1)}% scale)`); + if (scaleFactor < 1) { + console.log(` Speedup: ~${Math.round(1 / (scaleFactor * scaleFactor))}\xD7`); + } + } + canvas.width = originalWidth; + canvas.height = originalHeight; + const paddingSize = 0.025; + const padX = Math.ceil(width * paddingSize); + const padY = Math.ceil(height * paddingSize); + const imgW = width - 2 * padX; + const imgH = height - 2 * padY; + const shapeCanvas = document.createElement("canvas"); + shapeCanvas.width = width; + shapeCanvas.height = height; + const shapeCtx = shapeCanvas.getContext("2d"); + shapeCtx.drawImage(img, padX, padY, imgW, imgH); + const startMask = performance.now(); + const shapeImageData = shapeCtx.getImageData(0, 0, width, height); + const data = shapeImageData.data; + const shapeMask = new Uint8Array(width * height); + const boundaryMask = new Uint8Array(width * height); + let shapePixelCount = 0; + for (let i = 0, idx = 0; i < data.length; i += 4, idx++) { + const a = data[i + 3]; + const isShape = a === 0 ? 0 : 1; + shapeMask[idx] = isShape; + shapePixelCount += isShape; + } + const boundaryIndices = []; + const interiorIndices = []; + for (let y = 0; y < height; y++) { + for (let x = 0; x < width; x++) { + const idx = y * width + x; + if (!shapeMask[idx]) continue; + let isBoundary = false; + if (x === 0 || x === width - 1 || y === 0 || y === height - 1) { + isBoundary = true; + } else { + isBoundary = !shapeMask[idx - 1] || // left + !shapeMask[idx + 1] || // right + !shapeMask[idx - width] || // top + !shapeMask[idx + width] || // bottom + !shapeMask[idx - width - 1] || // top-left + !shapeMask[idx - width + 1] || // top-right + !shapeMask[idx + width - 1] || // bottom-left + !shapeMask[idx + width + 1]; + } + if (isBoundary) { + boundaryMask[idx] = 1; + boundaryIndices.push(idx); + } else { + interiorIndices.push(idx); + } + } + } + if (POISSON_CONFIG_OPTIMIZED.measurePerformance) { + console.log(`[Mask Building] Time: ${(performance.now() - startMask).toFixed(2)}ms`); + console.log( + ` Shape pixels: ${shapePixelCount} / ${width * height} (${(shapePixelCount / (width * height) * 100).toFixed(1)}%)` + ); + console.log(` Interior pixels: ${interiorIndices.length}`); + console.log(` Boundary pixels: ${boundaryIndices.length}`); + } + const sparseData = buildSparseData( + shapeMask, + boundaryMask, + new Uint32Array(interiorIndices), + new Uint32Array(boundaryIndices), + width, + height + ); + const startSolve = performance.now(); + const u = solvePoissonSparse(sparseData, shapeMask, boundaryMask, width, height); + if (POISSON_CONFIG_OPTIMIZED.measurePerformance) { + console.log(`[Poisson Solve] Time: ${(performance.now() - startSolve).toFixed(2)}ms`); + } + let maxVal = 0; + let finalImageData; + for (let i = 0; i < interiorIndices.length; i++) { + const idx = interiorIndices[i]; + if (u[idx] > maxVal) maxVal = u[idx]; + } + const tempCanvas = document.createElement("canvas"); + tempCanvas.width = width; + tempCanvas.height = height; + const tempCtx = tempCanvas.getContext("2d"); + const tempImg = tempCtx.createImageData(width, height); + for (let y = 0; y < height; y++) { + for (let x = 0; x < width; x++) { + const idx = y * width + x; + const px = idx * 4; + if (!shapeMask[idx]) { + tempImg.data[px] = 255; + tempImg.data[px + 1] = 255; + tempImg.data[px + 2] = 255; + tempImg.data[px + 3] = 0; + } else { + const poissonRatio = u[idx] / maxVal; + let gray = 255 * (1 - poissonRatio); + tempImg.data[px] = gray; + tempImg.data[px + 1] = gray; + tempImg.data[px + 2] = gray; + tempImg.data[px + 3] = 255; + } + } + } + tempCtx.putImageData(tempImg, 0, 0); + ctx.imageSmoothingEnabled = true; + ctx.imageSmoothingQuality = "high"; + ctx.drawImage(tempCanvas, 0, 0, width, height, 0, 0, originalWidth, originalHeight); + const outImg = ctx.getImageData(0, 0, originalWidth, originalHeight); + const origPadX = Math.ceil(originalWidth * paddingSize); + const origPadY = Math.ceil(originalHeight * paddingSize); + const originalCanvas = document.createElement("canvas"); + originalCanvas.width = originalWidth; + originalCanvas.height = originalHeight; + const originalCtx = originalCanvas.getContext("2d"); + originalCtx.drawImage(img, origPadX, origPadY, originalWidth - 2 * origPadX, originalHeight - 2 * origPadY); + const originalData = originalCtx.getImageData(0, 0, originalWidth, originalHeight); + for (let i = 0; i < outImg.data.length; i += 4) { + const a = originalData.data[i + 3]; + const upscaledAlpha = outImg.data[i + 3]; + if (a === 0) { + outImg.data[i] = 255; + outImg.data[i + 1] = 0; + } else { + outImg.data[i] = upscaledAlpha === 0 ? 0 : outImg.data[i]; + outImg.data[i + 1] = a; + } + outImg.data[i + 2] = 255; + outImg.data[i + 3] = 255; + } + ctx.putImageData(outImg, 0, 0); + finalImageData = outImg; + canvas.toBlob((blob) => { + if (!blob) { + reject(new Error("Failed to create PNG blob")); + return; + } + if (POISSON_CONFIG_OPTIMIZED.measurePerformance) { + const totalTime = performance.now() - totalStartTime; + console.log(`[Total Processing Time] ${totalTime.toFixed(2)}ms`); + if (scaleFactor < 1) { + const estimatedFullResTime = totalTime * Math.pow(originalWidth * originalHeight / (width * height), 1.5); + console.log(`[Estimated time at full resolution] ~${estimatedFullResTime.toFixed(0)}ms`); + console.log( + `[Time saved] ~${(estimatedFullResTime - totalTime).toFixed(0)}ms (${Math.round(estimatedFullResTime / totalTime)}\xD7 faster)` + ); + } + } + resolve({ + imageData: finalImageData, + pngBlob: blob + }); + }, "image/png"); + }; + img.onerror = () => reject(new Error("Failed to load image")); + img.src = typeof file === "string" ? file : URL.createObjectURL(file); + }); +} +function buildSparseData(shapeMask, boundaryMask, interiorPixels, boundaryPixels, width, height) { + const pixelCount = interiorPixels.length; + const neighborIndices = new Int32Array(pixelCount * 4); + for (let i = 0; i < pixelCount; i++) { + const idx = interiorPixels[i]; + const x = idx % width; + const y = Math.floor(idx / width); + neighborIndices[i * 4 + 0] = x < width - 1 && shapeMask[idx + 1] ? idx + 1 : -1; + neighborIndices[i * 4 + 1] = x > 0 && shapeMask[idx - 1] ? idx - 1 : -1; + neighborIndices[i * 4 + 2] = y > 0 && shapeMask[idx - width] ? idx - width : -1; + neighborIndices[i * 4 + 3] = y < height - 1 && shapeMask[idx + width] ? idx + width : -1; + } + return { + interiorPixels, + boundaryPixels, + pixelCount, + neighborIndices + }; +} +function solvePoissonSparse(sparseData, shapeMask, boundaryMask, width, height) { + const ITERATIONS = POISSON_CONFIG_OPTIMIZED.iterations; + const C = 0.01; + const u = new Float32Array(width * height); + const { interiorPixels, neighborIndices, pixelCount } = sparseData; + const startTime = performance.now(); + const omega = 1.9; + const redPixels = []; + const blackPixels = []; + for (let i = 0; i < pixelCount; i++) { + const idx = interiorPixels[i]; + const x = idx % width; + const y = Math.floor(idx / width); + if ((x + y) % 2 === 0) { + redPixels.push(i); + } else { + blackPixels.push(i); + } + } + for (let iter = 0; iter < ITERATIONS; iter++) { + for (const i of redPixels) { + const idx = interiorPixels[i]; + const eastIdx = neighborIndices[i * 4 + 0]; + const westIdx = neighborIndices[i * 4 + 1]; + const northIdx = neighborIndices[i * 4 + 2]; + const southIdx = neighborIndices[i * 4 + 3]; + let sumN = 0; + if (eastIdx >= 0) sumN += u[eastIdx]; + if (westIdx >= 0) sumN += u[westIdx]; + if (northIdx >= 0) sumN += u[northIdx]; + if (southIdx >= 0) sumN += u[southIdx]; + const newValue = (C + sumN) / 4; + u[idx] = omega * newValue + (1 - omega) * u[idx]; + } + for (const i of blackPixels) { + const idx = interiorPixels[i]; + const eastIdx = neighborIndices[i * 4 + 0]; + const westIdx = neighborIndices[i * 4 + 1]; + const northIdx = neighborIndices[i * 4 + 2]; + const southIdx = neighborIndices[i * 4 + 3]; + let sumN = 0; + if (eastIdx >= 0) sumN += u[eastIdx]; + if (westIdx >= 0) sumN += u[westIdx]; + if (northIdx >= 0) sumN += u[northIdx]; + if (southIdx >= 0) sumN += u[southIdx]; + const newValue = (C + sumN) / 4; + u[idx] = omega * newValue + (1 - omega) * u[idx]; + } + } + const tmp = new Float32Array(width * height); + for (let smooth = 0; smooth < 3; smooth++) { + tmp.set(u); + for (let i = 0; i < pixelCount; i++) { + const idx = interiorPixels[i]; + const eastIdx = neighborIndices[i * 4 + 0]; + const westIdx = neighborIndices[i * 4 + 1]; + const northIdx = neighborIndices[i * 4 + 2]; + const southIdx = neighborIndices[i * 4 + 3]; + let sum = 0; + let count = 0; + if (eastIdx >= 0) { + sum += tmp[eastIdx]; + count++; + } + if (westIdx >= 0) { + sum += tmp[westIdx]; + count++; + } + if (northIdx >= 0) { + sum += tmp[northIdx]; + count++; + } + if (southIdx >= 0) { + sum += tmp[southIdx]; + count++; + } + u[idx] = count > 0 ? (tmp[idx] + sum / count) * 0.5 : tmp[idx]; + } + } + if (POISSON_CONFIG_OPTIMIZED.measurePerformance) { + const elapsed = performance.now() - startTime; + console.log(`[Optimized Poisson Solver (SOR \u03C9=${omega})]`); + console.log(` Working size: ${width}\xD7${height}`); + console.log(` Iterations: ${ITERATIONS}`); + console.log(` Time: ${elapsed.toFixed(2)}ms`); + console.log(` Interior pixels processed: ${pixelCount}`); + console.log(` Speed: ${(ITERATIONS * pixelCount / (elapsed * 1e3)).toFixed(2)} Mpixels/sec`); + } + return u; +} +const GemSmokeShapes = { + none: 0, + circle: 1, + daisy: 2, + diamond: 3, + metaballs: 4 +}; +export { + GemSmokeShapes, + POISSON_CONFIG_OPTIMIZED, + gemSmokeFragmentShader, + gemSmokeMeta, + toProcessedGemSmoke +}; +//# sourceMappingURL=gem-smoke.js.map diff --git a/public/vendor/paper-shaders/shaders/gem-smoke.js.map b/public/vendor/paper-shaders/shaders/gem-smoke.js.map new file mode 100644 index 0000000..cec8dac --- /dev/null +++ b/public/vendor/paper-shaders/shaders/gem-smoke.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../../src/shaders/gem-smoke.ts"], + "sourcesContent": ["import type { vec4 } from '../types.js';\nimport type { ShaderMotionParams } from '../shader-mount.js';\nimport type { ShaderSizingParams, ShaderSizingUniforms } from '../shader-sizing.js';\nimport { rotation2, declarePI } from '../shader-utils.js';\n\nexport const gemSmokeMeta = {\n maxColorCount: 6,\n} as const;\n\n/**\n * Animated color fields placed over uploaded logo shape; gives the illusion of smoky noise\n * behind the glassy shape.\n *\n * Fragment shader uniforms:\n * - u_time (float): Animation time\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_image (sampler2D): Pre-processed source image texture (R = edge gradient, G = alpha)\n * - u_imageAspectRatio (float): Aspect ratio of the source image\n * - u_colors (vec4[]): Up to 6 smoke colors in RGBA\n * - u_colorsCount (float): Number of active colors\n * - u_colorBack (vec4): Background color in RGBA\n * - u_innerDistortion (float): Power of smoke distortion inside the input shape (0 to 1)\n * - u_outerDistortion (float): Power of smoke distortion outside the input shape (0 to 1)\n * - u_outerGlow (float): Visibility of smoke shape outside the input shape (0 to 1)\n * - u_innerGlow (float): Visibility of smoke shape inside the input shape (0 to 1)\n * - u_colorInner (vec4): Additional color inside the input shape, mixing with smoke (RGBA)\n * - u_offset (float): Vertical offset of smoke inside the shape (-1 to 1)\n * - u_angle (float): Smoke direction in degrees (0 to 360)\n * - u_size (float): Size of smoke shape relative to the image box (0 to 1)\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_imageUV (vec2): UV coordinates for sampling the source image, with fit, scale, rotation, and offset applied\n * - v_objectUV (vec2): Normalized UV coordinates with scale, rotation, and offset applied\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n * - u_imageAspectRatio (float): Aspect ratio of the source image\n *\n */\n\n// language=GLSL\nexport const gemSmokeFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nin mediump vec2 v_imageUV;\nin mediump vec2 v_objectUV;\nin mediump vec2 v_responsiveUV;\nin mediump vec2 v_responsiveBoxGivenSize;\nout vec4 fragColor;\n\n// Image\nuniform sampler2D u_image;\nuniform float u_imageAspectRatio;\n\n// Canvas\nuniform vec2 u_resolution;\nuniform float u_time;\n\n// Colors\nuniform vec4 u_colors[${gemSmokeMeta.maxColorCount}];\nuniform float u_colorsCount;\nuniform vec4 u_colorBack;\nuniform vec4 u_colorInner;\n\n// Effect controls\nuniform float u_innerDistortion;\nuniform float u_outerDistortion;\nuniform float u_outerGlow;\nuniform float u_innerGlow;\nuniform float u_offset;\nuniform float u_angle;\nuniform float u_size;\n\n// Shape controls\nuniform float u_shape;\nuniform bool u_isImage;\n\n${ declarePI }\n${ rotation2 }\n\n// 9x9 Gaussian blur on R and G channels\nvec2 gaussBlur9x9RG(sampler2D tex, vec2 uv, vec2 dudx, vec2 dudy, float radius) {\n vec2 texel = 1.0 / vec2(textureSize(tex, 0));\n vec2 r = max(radius, 0.0) * texel;\n // Pascal's row 8: sum = 256, 2D norm = 65536\n const float k[9] = float[9](1.0, 8.0, 28.0, 56.0, 70.0, 56.0, 28.0, 8.0, 1.0);\n vec2 sum = vec2(0.0);\n\n for (int j = -4; j <= 4; ++j) {\n float wy = k[j + 4];\n for (int i = -4; i <= 4; ++i) {\n float w = k[i + 4] * wy;\n vec2 off = vec2(float(i) * r.x, float(j) * r.y);\n sum += w * texture(tex, uv + off).rg;\n }\n }\n\n return sum / 65536.0;\n}\n\nfloat sst(float a, float b, float x) {\n return smoothstep(a, b, x);\n}\n\nvoid main() {\n float time = u_time;\n\n float roundness = 0.;\n float imgAlpha = 0.;\n\n if (u_isImage == true) {\n // Image sampling (UV scaled inward to account for padding)\n vec2 imageUV = v_imageUV;\n imageUV -= .5;\n imageUV *= .95;\n imageUV += .5;\n\n vec2 dudx = dFdx(v_imageUV);\n vec2 dudy = dFdy(v_imageUV);\n\n // Blurred image: x = roundness, y = alpha\n vec2 blurred = gaussBlur9x9RG(u_image, imageUV, dudx, dudy, 10.);\n roundness = 1. - blurred.x;\n vec2 texelA = 1.0 / vec2(textureSize(u_image, 0));\n const float k3[3] = float[3](1.0, 2.0, 1.0);\n for (int j = -1; j <= 1; ++j) {\n for (int i = -1; i <= 1; ++i) {\n imgAlpha += k3[i + 1] * k3[j + 1] * texture(u_image, imageUV + vec2(float(i) * texelA.x, float(j) * texelA.y)).g;\n }\n }\n imgAlpha /= 16.0;\n } else {\n vec2 uv = v_objectUV + .5;\n uv.y = 1. - uv.y;\n float edge = 0.;\n\n if (u_shape < 1.) {\n // full-fill on canvas\n vec2 borderUV = v_responsiveUV + .5;\n vec2 mask = min(borderUV, 1. - borderUV);\n vec2 pixel_thickness = min(250. / v_responsiveBoxGivenSize, vec2(.5));\n float maskX = smoothstep(0.0, pixel_thickness.x, mask.x);\n float maskY = smoothstep(0.0, pixel_thickness.y, mask.y);\n maskX = pow(maskX, .25);\n maskY = pow(maskY, .25);\n edge = clamp(1. - maskX * maskY, 0., 1.);\n } else if (u_shape < 2.) {\n // circle\n vec2 shapeUV = uv - .5;\n shapeUV *= .67;\n edge = pow(clamp(3. * length(shapeUV), 0., 1.), 18.);\n } else if (u_shape < 3.) {\n // daisy\n vec2 shapeUV = uv - .5;\n shapeUV *= 1.68;\n\n float r = length(shapeUV) * 2.;\n float a = atan(shapeUV.y, shapeUV.x) + .2;\n r *= (1. + .05 * sin(3. * a + 2. * time));\n float f = abs(cos(a * 3.));\n edge = smoothstep(f, f + .7, r);\n edge *= edge;\n } else if (u_shape < 4.) {\n // diamond\n vec2 shapeUV = uv - .5;\n shapeUV = rotate(shapeUV, .25 * PI);\n shapeUV *= 1.42;\n shapeUV += .5;\n vec2 mask = min(shapeUV, 1. - shapeUV);\n vec2 pixel_thickness = vec2(.15);\n float maskX = smoothstep(0.0, pixel_thickness.x, mask.x);\n float maskY = smoothstep(0.0, pixel_thickness.y, mask.y);\n maskX = pow(maskX, .25);\n maskY = pow(maskY, .25);\n edge = clamp(1. - maskX * maskY, 0., 1.);\n } else if (u_shape < 5.) {\n // metaballs\n vec2 shapeUV = uv - .5;\n shapeUV *= 1.3;\n edge = 0.;\n for (int i = 0; i < 5; i++) {\n float fi = float(i);\n float speed = 1.5 + 2./3. * sin(fi * 12.345);\n float angle = -fi * 1.5;\n vec2 dir1 = vec2(cos(angle), sin(angle));\n vec2 dir2 = vec2(cos(angle + 1.57), sin(angle + 1.));\n vec2 traj = .4 * (dir1 * sin(time * speed + fi * 1.23) + dir2 * cos(time * (speed * 0.7) + fi * 2.17));\n float d = length(shapeUV + traj);\n edge += pow(1.0 - clamp(d, 0.0, 1.0), 4.0);\n }\n edge = 1. - smoothstep(.65, .9, edge);\n edge = pow(edge, 4.);\n }\n\n imgAlpha = 1. - smoothstep(.9 - 2. * fwidth(edge), .9, edge);\n roundness = 1. - edge;\n }\n\n// Smoke UV setup\n vec2 smokeUV = v_objectUV;\n smokeUV = rotate(smokeUV, u_angle * PI / 180.);\n smokeUV *= mix(4., 1., u_size);\n\n // Two swirl paths: inner (shape-masked) and outer (free), each with independent distortion\n vec2 innerUV = smokeUV;\n vec2 outerUV = smokeUV;\n\n // Vertical displacement \u2014 applied independently to inner and outer\n innerUV.y += u_innerDistortion * (1. - sst(0., 1., length(.4 * innerUV)));\n innerUV.y -= .4 * u_innerDistortion;\n innerUV.y += .7 * u_offset * roundness;\n\n outerUV.y += u_outerDistortion * (1. - sst(0., 1., length(.4 * outerUV)));\n outerUV.y -= .4 * u_outerDistortion;\n\n float innerSwirl = u_innerDistortion * roundness;\n float outerSwirl = u_outerDistortion;\n\n for (int i = 1; i < 5; i++) {\n float fi = float(i);\n\n float stretchIn = max(length(dFdx(innerUV)), length(dFdy(innerUV)));\n float dampenIn = 1. / (1. + stretchIn * 8.);\n float sIn = innerSwirl * dampenIn;\n innerUV.x += sIn / fi * cos(time + fi * 2.9 * innerUV.y);\n innerUV.y += sIn / fi * cos(time + fi * 1.5 * innerUV.x);\n\n float stretchOut = max(length(dFdx(outerUV)), length(dFdy(outerUV)));\n float dampenOut = 1. / (1. + stretchOut * 8.);\n float sOut = outerSwirl * dampenOut;\n outerUV.x += sOut / fi * cos(time + fi * 2.9 * outerUV.y);\n outerUV.y += sOut / fi * cos(time + fi * 1.5 * outerUV.x);\n }\n\n // Smoke shapes from swirl fields\n float innerShape = exp(-1.5 * dot(innerUV, innerUV));\n float outerShape = exp(-1.5 * dot(outerUV, outerUV));\n\n // Visibility masks\n float outerMask = pow(u_outerGlow, 2.) * (1. - imgAlpha);\n float innerMask = (.01 + .99 * u_innerGlow) * imgAlpha;\n\n innerShape *= innerMask;\n outerShape *= outerMask;\n\n // Color gradient\n float mixer = (innerShape + outerShape) * u_colorsCount;\n vec4 gradient = u_colors[0];\n gradient.rgb *= gradient.a;\n\n float smokeMask = 0.;\n for (int i = 1; i < ${gemSmokeMeta.maxColorCount + 1}; i++) {\n if (i > int(u_colorsCount)) break;\n\n float m = sst(0., 1., clamp(mixer - float(i - 1), 0., 1.));\n if (i == 1) smokeMask = m;\n\n vec4 c = u_colors[i - 1];\n c.rgb *= c.a;\n gradient = mix(gradient, c, m);\n }\n\n // Compositing (premultiplied alpha, front-to-back)\n vec3 color = gradient.rgb * smokeMask;\n float opacity = gradient.a * smokeMask;\n\n float innerOpacity = u_colorInner.a * imgAlpha;\n vec3 innerColor = u_colorInner.rgb * innerOpacity;\n color += innerColor * (1.0 - opacity);\n opacity += innerOpacity * (1.0 - opacity);\n\n vec3 backColor = u_colorBack.rgb * u_colorBack.a;\n color += backColor * (1.0 - opacity);\n opacity += u_colorBack.a * (1.0 - opacity);\n\n fragColor = vec4(color, opacity);\n}\n`;\n\n// Configuration for Poisson solver\nexport const POISSON_CONFIG_OPTIMIZED = {\n measurePerformance: false, // Set to true to see performance metrics\n workingSize: 512, // Size to solve Poisson at (will upscale to original size)\n iterations: 32, // SOR converges ~2-20x faster than standard Gauss-Seidel\n};\n\n// Precomputed pixel data for sparse processing\ninterface SparsePixelData {\n interiorPixels: Uint32Array; // Indices of interior pixels\n boundaryPixels: Uint32Array; // Indices of boundary pixels\n pixelCount: number;\n // Neighbor indices for each interior pixel (4 neighbors per pixel)\n // Layout: [east, west, north, south] for each pixel\n neighborIndices: Int32Array;\n}\n\nexport function toProcessedGemSmoke(file: File | string): Promise<{ imageData: ImageData; pngBlob: Blob }> {\n const canvas = document.createElement('canvas');\n const ctx = canvas.getContext('2d');\n const isBlob = typeof file === 'string' && file.startsWith('blob:');\n\n return new Promise((resolve, reject) => {\n if (!file || !ctx) {\n reject(new Error('Invalid file or canvas context'));\n return;\n }\n\n const blobContentTypePromise = isBlob && fetch(file).then((res) => res.headers.get('Content-Type'));\n const img = new Image();\n img.crossOrigin = 'anonymous';\n const totalStartTime = performance.now();\n\n img.onload = async () => {\n // Force SVG to load at a high fidelity size if it's an SVG\n let isSVG;\n\n const blobContentType = await blobContentTypePromise;\n\n if (blobContentType) {\n isSVG = blobContentType === 'image/svg+xml';\n } else if (typeof file === 'string') {\n isSVG = file.endsWith('.svg') || file.startsWith('data:image/svg+xml');\n } else {\n isSVG = file.type === 'image/svg+xml';\n }\n\n let originalWidth = img.width || img.naturalWidth;\n let originalHeight = img.height || img.naturalHeight;\n\n if (isSVG) {\n // Scale SVG to max dimension while preserving aspect ratio\n const svgMaxSize = 4096;\n const aspectRatio = originalWidth / originalHeight;\n\n if (originalWidth > originalHeight) {\n originalWidth = svgMaxSize;\n originalHeight = svgMaxSize / aspectRatio;\n } else {\n originalHeight = svgMaxSize;\n originalWidth = svgMaxSize * aspectRatio;\n }\n\n img.width = originalWidth;\n img.height = originalHeight;\n }\n\n // Always scale to working resolution for consistency\n const minDimension = Math.min(originalWidth, originalHeight);\n const targetSize = POISSON_CONFIG_OPTIMIZED.workingSize;\n\n // Calculate scale to fit within workingSize\n const scaleFactor = targetSize / minDimension;\n const width = Math.round(originalWidth * scaleFactor);\n const height = Math.round(originalHeight * scaleFactor);\n\n if (POISSON_CONFIG_OPTIMIZED.measurePerformance) {\n console.log(`[Processing Mode]`);\n console.log(` Original: ${originalWidth}\u00D7${originalHeight}`);\n console.log(` Working: ${width}\u00D7${height} (${(scaleFactor * 100).toFixed(1)}% scale)`);\n if (scaleFactor < 1) {\n console.log(` Speedup: ~${Math.round(1 / (scaleFactor * scaleFactor))}\u00D7`);\n }\n }\n\n canvas.width = originalWidth;\n canvas.height = originalHeight;\n\n const paddingSize = 0.025;\n const padX = Math.ceil(width * paddingSize);\n const padY = Math.ceil(height * paddingSize);\n const imgW = width - 2 * padX;\n const imgH = height - 2 * padY;\n\n // \u2500\u2500 1. Shape canvas (working res): image centered with padding \u2500\u2500\n const shapeCanvas = document.createElement('canvas');\n shapeCanvas.width = width;\n shapeCanvas.height = height;\n\n const shapeCtx = shapeCanvas.getContext('2d')!;\n shapeCtx.drawImage(img, padX, padY, imgW, imgH);\n\n // 1) Build optimized masks using TypedArrays\n const startMask = performance.now();\n\n const shapeImageData = shapeCtx.getImageData(0, 0, width, height);\n const data = shapeImageData.data;\n\n // Use Uint8Array for masks (1 byte per pixel vs 8+ bytes for boolean array)\n const shapeMask = new Uint8Array(width * height);\n const boundaryMask = new Uint8Array(width * height);\n\n // First pass: identify shape pixels\n let shapePixelCount = 0;\n for (let i = 0, idx = 0; i < data.length; i += 4, idx++) {\n const a = data[i + 3];\n const isShape = a === 0 ? 0 : 1;\n shapeMask[idx] = isShape;\n shapePixelCount += isShape;\n }\n\n // 2) Optimized boundary detection using sparse approach\n // Only check shape pixels, not all pixels\n const boundaryIndices: number[] = [];\n const interiorIndices: number[] = [];\n\n for (let y = 0; y < height; y++) {\n for (let x = 0; x < width; x++) {\n const idx = y * width + x;\n if (!shapeMask[idx]) continue;\n\n // Check if pixel is on boundary (optimized: early exit)\n let isBoundary = false;\n\n // Check 4-connected neighbors first (most common case)\n if (x === 0 || x === width - 1 || y === 0 || y === height - 1) {\n isBoundary = true;\n } else {\n // Check all 8 neighbors (including diagonals) for comprehensive boundary detection\n isBoundary =\n !shapeMask[idx - 1] || // left\n !shapeMask[idx + 1] || // right\n !shapeMask[idx - width] || // top\n !shapeMask[idx + width] || // bottom\n !shapeMask[idx - width - 1] || // top-left\n !shapeMask[idx - width + 1] || // top-right\n !shapeMask[idx + width - 1] || // bottom-left\n !shapeMask[idx + width + 1]; // bottom-right\n }\n\n if (isBoundary) {\n boundaryMask[idx] = 1;\n boundaryIndices.push(idx);\n } else {\n interiorIndices.push(idx);\n }\n }\n }\n\n if (POISSON_CONFIG_OPTIMIZED.measurePerformance) {\n console.log(`[Mask Building] Time: ${(performance.now() - startMask).toFixed(2)}ms`);\n console.log(\n ` Shape pixels: ${shapePixelCount} / ${width * height} (${((shapePixelCount / (width * height)) * 100).toFixed(1)}%)`\n );\n console.log(` Interior pixels: ${interiorIndices.length}`);\n console.log(` Boundary pixels: ${boundaryIndices.length}`);\n }\n\n // 3) Precompute sparse data structure for solver\n const sparseData = buildSparseData(\n shapeMask,\n boundaryMask,\n new Uint32Array(interiorIndices),\n new Uint32Array(boundaryIndices),\n width,\n height\n );\n\n // 4) Solve Poisson equation with optimized sparse solver\n const startSolve = performance.now();\n const u = solvePoissonSparse(sparseData, shapeMask, boundaryMask, width, height);\n\n if (POISSON_CONFIG_OPTIMIZED.measurePerformance) {\n console.log(`[Poisson Solve] Time: ${(performance.now() - startSolve).toFixed(2)}ms`);\n }\n\n // 5) Generate output image\n let maxVal = 0;\n let finalImageData: ImageData;\n\n // Only check shape pixels for max value\n for (let i = 0; i < interiorIndices.length; i++) {\n const idx = interiorIndices[i]!;\n if (u[idx]! > maxVal) maxVal = u[idx]!;\n }\n\n // Create roundness image at working resolution\n const tempCanvas = document.createElement('canvas');\n tempCanvas.width = width;\n tempCanvas.height = height;\n const tempCtx = tempCanvas.getContext('2d')!;\n\n const tempImg = tempCtx.createImageData(width, height);\n for (let y = 0; y < height; y++) {\n for (let x = 0; x < width; x++) {\n const idx = y * width + x;\n const px = idx * 4;\n\n if (!shapeMask[idx]) {\n tempImg.data[px] = 255;\n tempImg.data[px + 1] = 255;\n tempImg.data[px + 2] = 255;\n tempImg.data[px + 3] = 0; // Alpha = 0 for background\n } else {\n const poissonRatio = u[idx]! / maxVal;\n let gray = 255 * (1 - poissonRatio);\n tempImg.data[px] = gray;\n tempImg.data[px + 1] = gray;\n tempImg.data[px + 2] = gray;\n tempImg.data[px + 3] = 255; // Alpha = 255 for shape\n }\n }\n }\n tempCtx.putImageData(tempImg, 0, 0);\n\n // Upscale to original resolution with smooth interpolation\n ctx.imageSmoothingEnabled = true;\n ctx.imageSmoothingQuality = 'high';\n ctx.drawImage(tempCanvas, 0, 0, width, height, 0, 0, originalWidth, originalHeight);\n\n // Now get the upscaled image data for final output\n const outImg = ctx.getImageData(0, 0, originalWidth, originalHeight);\n\n // Re-apply edges from original resolution with anti-aliasing\n // This ensures edges are pixel-perfect while roundness is smooth\n const origPadX = Math.ceil(originalWidth * paddingSize);\n const origPadY = Math.ceil(originalHeight * paddingSize);\n const originalCanvas = document.createElement('canvas');\n originalCanvas.width = originalWidth;\n originalCanvas.height = originalHeight;\n const originalCtx = originalCanvas.getContext('2d')!;\n originalCtx.drawImage(img, origPadX, origPadY, originalWidth - 2 * origPadX, originalHeight - 2 * origPadY);\n const originalData = originalCtx.getImageData(0, 0, originalWidth, originalHeight);\n\n // Process each pixel: Red channel = roundness, Alpha channel = original alpha\n for (let i = 0; i < outImg.data.length; i += 4) {\n const a = originalData.data[i + 3]!;\n // Use only alpha to determine background vs shape\n const upscaledAlpha = outImg.data[i + 3]!;\n if (a === 0) {\n // Background pixel\n outImg.data[i] = 255;\n outImg.data[i + 1] = 0;\n } else {\n // Red channel carries the roundness\n // Check if upscale missed this pixel by looking at alpha channel\n // If upscaled alpha is 0, the low-res version thought this was background\n outImg.data[i] = upscaledAlpha === 0 ? 0 : outImg.data[i]!; // roundness or 0\n outImg.data[i + 1] = a; // original alpha\n }\n\n // Unused channels fixed\n outImg.data[i + 2] = 255;\n outImg.data[i + 3] = 255;\n }\n\n ctx.putImageData(outImg, 0, 0);\n finalImageData = outImg;\n canvas.toBlob((blob) => {\n if (!blob) {\n reject(new Error('Failed to create PNG blob'));\n return;\n }\n\n if (POISSON_CONFIG_OPTIMIZED.measurePerformance) {\n const totalTime = performance.now() - totalStartTime;\n console.log(`[Total Processing Time] ${totalTime.toFixed(2)}ms`);\n if (scaleFactor < 1) {\n const estimatedFullResTime = totalTime * Math.pow((originalWidth * originalHeight) / (width * height), 1.5);\n console.log(`[Estimated time at full resolution] ~${estimatedFullResTime.toFixed(0)}ms`);\n console.log(\n `[Time saved] ~${(estimatedFullResTime - totalTime).toFixed(0)}ms (${Math.round(estimatedFullResTime / totalTime)}\u00D7 faster)`\n );\n }\n }\n\n resolve({\n imageData: finalImageData,\n pngBlob: blob,\n });\n }, 'image/png');\n };\n\n img.onerror = () => reject(new Error('Failed to load image'));\n img.src = typeof file === 'string' ? file : URL.createObjectURL(file);\n });\n}\n\nfunction buildSparseData(\n shapeMask: Uint8Array,\n boundaryMask: Uint8Array,\n interiorPixels: Uint32Array,\n boundaryPixels: Uint32Array,\n width: number,\n height: number\n): SparsePixelData {\n const pixelCount = interiorPixels.length;\n\n // Build neighbor indices for sparse processing\n // For each interior pixel, store indices of its 4 neighbors\n // Use -1 for out-of-bounds or non-shape neighbors\n const neighborIndices = new Int32Array(pixelCount * 4);\n\n for (let i = 0; i < pixelCount; i++) {\n const idx = interiorPixels[i]!;\n const x = idx % width;\n const y = Math.floor(idx / width);\n\n // East neighbor\n neighborIndices[i * 4 + 0] = x < width - 1 && shapeMask[idx + 1] ? idx + 1 : -1;\n // West neighbor\n neighborIndices[i * 4 + 1] = x > 0 && shapeMask[idx - 1] ? idx - 1 : -1;\n // North neighbor\n neighborIndices[i * 4 + 2] = y > 0 && shapeMask[idx - width] ? idx - width : -1;\n // South neighbor\n neighborIndices[i * 4 + 3] = y < height - 1 && shapeMask[idx + width] ? idx + width : -1;\n }\n\n return {\n interiorPixels,\n boundaryPixels,\n pixelCount,\n neighborIndices,\n };\n}\n\nfunction solvePoissonSparse(\n sparseData: SparsePixelData,\n shapeMask: Uint8Array,\n boundaryMask: Uint8Array,\n width: number,\n height: number\n): Float32Array {\n // This controls how smooth the falloff roundness will be and extend into the shape\n const ITERATIONS = POISSON_CONFIG_OPTIMIZED.iterations;\n\n // Keep C constant - only iterations control roundness spread\n const C = 0.01;\n\n const u = new Float32Array(width * height);\n const { interiorPixels, neighborIndices, pixelCount } = sparseData;\n\n // Performance tracking\n const startTime = performance.now();\n\n // Red-Black SOR for better symmetry with fewer iterations\n // omega between 1.8-1.95 typically gives best convergence for Poisson\n const omega = 1.9;\n\n // Pre-classify pixels as red or black for efficient processing\n const redPixels: number[] = [];\n const blackPixels: number[] = [];\n\n for (let i = 0; i < pixelCount; i++) {\n const idx = interiorPixels[i]!;\n const x = idx % width;\n const y = Math.floor(idx / width);\n\n if ((x + y) % 2 === 0) {\n redPixels.push(i);\n } else {\n blackPixels.push(i);\n }\n }\n\n for (let iter = 0; iter < ITERATIONS; iter++) {\n // Red pass: update red pixels\n for (const i of redPixels) {\n const idx = interiorPixels[i]!;\n\n // Get precomputed neighbor indices\n const eastIdx = neighborIndices[i * 4 + 0]!;\n const westIdx = neighborIndices[i * 4 + 1]!;\n const northIdx = neighborIndices[i * 4 + 2]!;\n const southIdx = neighborIndices[i * 4 + 3]!;\n\n // Sum neighbors (use 0 for out-of-bounds)\n let sumN = 0;\n if (eastIdx >= 0) sumN += u[eastIdx]!;\n if (westIdx >= 0) sumN += u[westIdx]!;\n if (northIdx >= 0) sumN += u[northIdx]!;\n if (southIdx >= 0) sumN += u[southIdx]!;\n\n // SOR update: blend new value with old value\n const newValue = (C + sumN) / 4;\n u[idx] = omega * newValue + (1 - omega) * u[idx]!;\n }\n\n // Black pass: update black pixels\n for (const i of blackPixels) {\n const idx = interiorPixels[i]!;\n\n // Get precomputed neighbor indices\n const eastIdx = neighborIndices[i * 4 + 0]!;\n const westIdx = neighborIndices[i * 4 + 1]!;\n const northIdx = neighborIndices[i * 4 + 2]!;\n const southIdx = neighborIndices[i * 4 + 3]!;\n\n // Sum neighbors (use 0 for out-of-bounds)\n let sumN = 0;\n if (eastIdx >= 0) sumN += u[eastIdx]!;\n if (westIdx >= 0) sumN += u[westIdx]!;\n if (northIdx >= 0) sumN += u[northIdx]!;\n if (southIdx >= 0) sumN += u[southIdx]!;\n\n // SOR update: blend new value with old value\n const newValue = (C + sumN) / 4;\n u[idx] = omega * newValue + (1 - omega) * u[idx]!;\n }\n }\n\n // Jacobi smoothing passes to remove Red-Black checkerboard artifacts\n const tmp = new Float32Array(width * height);\n for (let smooth = 0; smooth < 3; smooth++) {\n tmp.set(u);\n for (let i = 0; i < pixelCount; i++) {\n const idx = interiorPixels[i]!;\n const eastIdx = neighborIndices[i * 4 + 0]!;\n const westIdx = neighborIndices[i * 4 + 1]!;\n const northIdx = neighborIndices[i * 4 + 2]!;\n const southIdx = neighborIndices[i * 4 + 3]!;\n\n let sum = 0;\n let count = 0;\n if (eastIdx >= 0) { sum += tmp[eastIdx]!; count++; }\n if (westIdx >= 0) { sum += tmp[westIdx]!; count++; }\n if (northIdx >= 0) { sum += tmp[northIdx]!; count++; }\n if (southIdx >= 0) { sum += tmp[southIdx]!; count++; }\n\n u[idx] = count > 0 ? (tmp[idx]! + sum / count) * 0.5 : tmp[idx]!;\n }\n }\n\n if (POISSON_CONFIG_OPTIMIZED.measurePerformance) {\n const elapsed = performance.now() - startTime;\n\n console.log(`[Optimized Poisson Solver (SOR \u03C9=${omega})]`);\n console.log(` Working size: ${width}\u00D7${height}`);\n console.log(` Iterations: ${ITERATIONS}`);\n console.log(` Time: ${elapsed.toFixed(2)}ms`);\n console.log(` Interior pixels processed: ${pixelCount}`);\n console.log(` Speed: ${((ITERATIONS * pixelCount) / (elapsed * 1000)).toFixed(2)} Mpixels/sec`);\n }\n\n return u;\n}\n\nexport interface GemSmokeUniforms extends ShaderSizingUniforms {\n u_colorBack: [number, number, number, number];\n u_colors: vec4[];\n u_colorsCount: number;\n u_image: HTMLImageElement | string | undefined;\n u_innerDistortion: number;\n u_outerDistortion: number;\n u_outerGlow: number;\n u_innerGlow: number;\n u_colorInner: [number, number, number, number];\n u_offset: number;\n u_angle: number;\n u_size: number;\n u_shape: (typeof GemSmokeShapes)[GemSmokeShape];\n u_isImage: boolean;\n}\n\nexport interface GemSmokeParams extends ShaderSizingParams, ShaderMotionParams {\n colors?: string[];\n colorBack?: string;\n image?: HTMLImageElement | string | undefined;\n innerDistortion?: number;\n outerDistortion?: number;\n outerGlow?: number;\n innerGlow?: number;\n colorInner?: string;\n offset?: number;\n angle?: number;\n size?: number;\n shape?: GemSmokeShape;\n}\n\nexport const GemSmokeShapes = {\n none: 0,\n circle: 1,\n daisy: 2,\n diamond: 3,\n metaballs: 4,\n} as const;\n\nexport type GemSmokeShape = keyof typeof GemSmokeShapes;\n"], + "mappings": "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", + "names": [] +} diff --git a/public/vendor/paper-shaders/shaders/god-rays.d.ts b/public/vendor/paper-shaders/shaders/god-rays.d.ts new file mode 100644 index 0000000..860ffd5 --- /dev/null +++ b/public/vendor/paper-shaders/shaders/god-rays.d.ts @@ -0,0 +1,67 @@ +import type { vec4 } from '../types.js'; +import type { ShaderMotionParams } from '../shader-mount.js'; +import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js'; +export declare const godRaysMeta: { + readonly maxColorCount: 5; +}; +/** + * Animated rays of light radiating from the center, blended with up to 5 colors. + * + * Fragment shader uniforms: + * - u_time (float): Animation time + * - u_colorBack (vec4): Background color in RGBA + * - u_colorBloom (vec4): Color overlay blended with the rays in RGBA + * - u_colors (vec4[]): Up to 5 ray colors in RGBA + * - u_colorsCount (float): Number of active colors + * - u_bloom (float): Strength of the bloom/overlay effect, 0 = alpha blend, 1 = additive blend (0 to 1) + * - u_intensity (float): Visibility/strength of the rays (0 to 1) + * - u_density (float): The number of rays (0 to 1) + * - u_spotty (float): The length of the rays, higher = more spots/shorter rays (0 to 1) + * - u_midSize (float): Size of the circular glow shape in the center (0 to 1) + * - u_midIntensity (float): Brightness/intensity of the central glow (0 to 1) + * - u_noiseTexture (sampler2D): Pre-computed randomizer source texture + * + * Vertex shader outputs (used in fragment shader): + * - v_objectUV (vec2): Object box UV coordinates with global sizing (scale, rotation, offsets, etc) applied + * + * The rays are adjustable by size, density, brightness and center glow. + * + * Vertex shader uniforms: + * - u_resolution (vec2): Canvas resolution in pixels + * - u_pixelRatio (float): Device pixel ratio + * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1) + * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1) + * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas + * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas + * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover) + * - u_scale (float): Overall zoom level of the graphics (0.01 to 4) + * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360) + * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1) + * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1) + * + */ +export declare const godRaysFragmentShader: string; +export interface GodRaysUniforms extends ShaderSizingUniforms { + u_colorBack: [number, number, number, number]; + u_colorBloom: [number, number, number, number]; + u_colors: vec4[]; + u_colorsCount: number; + u_spotty: number; + u_midSize: number; + u_midIntensity: number; + u_density: number; + u_intensity: number; + u_bloom: number; + u_noiseTexture?: HTMLImageElement; +} +export interface GodRaysParams extends ShaderSizingParams, ShaderMotionParams { + colorBack?: string; + colorBloom?: string; + colors?: string[]; + spotty?: number; + midSize?: number; + midIntensity?: number; + density?: number; + intensity?: number; + bloom?: number; +} diff --git a/public/vendor/paper-shaders/shaders/god-rays.js b/public/vendor/paper-shaders/shaders/god-rays.js new file mode 100644 index 0000000..a4c3891 --- /dev/null +++ b/public/vendor/paper-shaders/shaders/god-rays.js @@ -0,0 +1,133 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Paper Shaders * + * https://github.com/paper-design/shaders * + * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +import {} from "../shader-sizing.js"; +import { declarePI, rotation2, textureRandomizerR, colorBandingFix, proceduralHash11 } from "../shader-utils.js"; +const godRaysMeta = { + maxColorCount: 5 +}; +const godRaysFragmentShader = `#version 300 es +precision mediump float; + +uniform float u_time; + +uniform sampler2D u_noiseTexture; + +uniform vec4 u_colorBack; +uniform vec4 u_colorBloom; +uniform vec4 u_colors[${godRaysMeta.maxColorCount}]; +uniform float u_colorsCount; + +uniform float u_density; +uniform float u_spotty; +uniform float u_midSize; +uniform float u_midIntensity; +uniform float u_intensity; +uniform float u_bloom; + +in vec2 v_objectUV; + +out vec4 fragColor; + +${declarePI} +${rotation2} +${textureRandomizerR} +float valueNoise(vec2 st) { + vec2 i = floor(st); + vec2 f = fract(st); + float a = randomR(i); + float b = randomR(i + vec2(1.0, 0.0)); + float c = randomR(i + vec2(0.0, 1.0)); + float d = randomR(i + vec2(1.0, 1.0)); + vec2 u = f * f * (3.0 - 2.0 * f); + float x1 = mix(a, b, u.x); + float x2 = mix(c, d, u.x); + return mix(x1, x2, u.y); +} + +${proceduralHash11} + +float raysShape(vec2 uv, float r, float freq, float intensity, float radius) { + float a = atan(uv.y, uv.x); + vec2 left = vec2(a * freq, r); + vec2 right = vec2(fract(a / TWO_PI) * TWO_PI * freq, r); + float n_left = pow(valueNoise(left), intensity); + float n_right = pow(valueNoise(right), intensity); + float shape = mix(n_right, n_left, smoothstep(-.15, .15, uv.x)); + return shape; +} + +void main() { + vec2 shape_uv = v_objectUV; + + float t = .2 * u_time; + + float radius = length(shape_uv); + float spots = 6.5 * abs(u_spotty); + + float intensity = 4. - 3. * clamp(u_intensity, 0., 1.); + + float delta = 1. - smoothstep(0., 1., radius); + + float midSize = 10. * abs(u_midSize); + float ms_lo = 0.02 * midSize; + float ms_hi = max(midSize, 1e-6); + float middleShape = pow(u_midIntensity, 0.3) * (1. - smoothstep(ms_lo, ms_hi, 3.0 * radius)); + middleShape = pow(middleShape, 5.0); + + vec3 accumColor = vec3(0.0); + float accumAlpha = 0.0; + + for (int i = 0; i < ${godRaysMeta.maxColorCount}; i++) { + if (i >= int(u_colorsCount)) break; + + vec2 rotatedUV = rotate(shape_uv, float(i) + 1.0); + + float r1 = radius * (1.0 + 0.4 * float(i)) - 3.0 * t; + float r2 = 0.5 * radius * (1.0 + spots) - 2.0 * t; + float density = 6. * u_density + step(.5, u_density) * pow(4.5 * (u_density - .5), 4.); + float f = mix(1.0, 3.0 + 0.5 * float(i), hash11(float(i) * 15.)) * density; + + float ray = raysShape(rotatedUV, r1, 5.0 * f, intensity, radius); + ray *= raysShape(rotatedUV, r2, 4.0 * f, intensity, radius); + ray += (1. + 4. * ray) * middleShape; + ray = clamp(ray, 0.0, 1.0); + + float srcAlpha = u_colors[i].a * ray; + vec3 srcColor = u_colors[i].rgb * srcAlpha; + + vec3 alphaBlendColor = accumColor + (1.0 - accumAlpha) * srcColor; + float alphaBlendAlpha = accumAlpha + (1.0 - accumAlpha) * srcAlpha; + + vec3 addBlendColor = accumColor + srcColor; + float addBlendAlpha = accumAlpha + srcAlpha; + + accumColor = mix(alphaBlendColor, addBlendColor, u_bloom); + accumAlpha = mix(alphaBlendAlpha, addBlendAlpha, u_bloom); + } + + float overlayAlpha = u_colorBloom.a; + vec3 overlayColor = u_colorBloom.rgb * overlayAlpha; + + vec3 colorWithOverlay = accumColor + accumAlpha * overlayColor; + accumColor = mix(accumColor, colorWithOverlay, u_bloom); + + vec3 bgColor = u_colorBack.rgb * u_colorBack.a; + + vec3 color = accumColor + (1. - accumAlpha) * bgColor; + float opacity = accumAlpha + (1. - accumAlpha) * u_colorBack.a; + color = clamp(color, 0., 1.); + opacity = clamp(opacity, 0., 1.); + + ${colorBandingFix} + + fragColor = vec4(color, opacity); +} +`; +export { + godRaysFragmentShader, + godRaysMeta +}; +//# sourceMappingURL=god-rays.js.map diff --git a/public/vendor/paper-shaders/shaders/god-rays.js.map b/public/vendor/paper-shaders/shaders/god-rays.js.map new file mode 100644 index 0000000..a6a5bea --- /dev/null +++ b/public/vendor/paper-shaders/shaders/god-rays.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../../src/shaders/god-rays.ts"], + "sourcesContent": ["import type { vec4 } from '../types.js';\nimport type { ShaderMotionParams } from '../shader-mount.js';\nimport { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { declarePI, rotation2, textureRandomizerR, colorBandingFix, proceduralHash11 } from '../shader-utils.js';\n\nexport const godRaysMeta = {\n maxColorCount: 5,\n} as const;\n\n/**\n * Animated rays of light radiating from the center, blended with up to 5 colors.\n *\n * Fragment shader uniforms:\n * - u_time (float): Animation time\n * - u_colorBack (vec4): Background color in RGBA\n * - u_colorBloom (vec4): Color overlay blended with the rays in RGBA\n * - u_colors (vec4[]): Up to 5 ray colors in RGBA\n * - u_colorsCount (float): Number of active colors\n * - u_bloom (float): Strength of the bloom/overlay effect, 0 = alpha blend, 1 = additive blend (0 to 1)\n * - u_intensity (float): Visibility/strength of the rays (0 to 1)\n * - u_density (float): The number of rays (0 to 1)\n * - u_spotty (float): The length of the rays, higher = more spots/shorter rays (0 to 1)\n * - u_midSize (float): Size of the circular glow shape in the center (0 to 1)\n * - u_midIntensity (float): Brightness/intensity of the central glow (0 to 1)\n * - u_noiseTexture (sampler2D): Pre-computed randomizer source texture\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_objectUV (vec2): Object box UV coordinates with global sizing (scale, rotation, offsets, etc) applied\n *\n * The rays are adjustable by size, density, brightness and center glow.\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n *\n */\n\n// language=GLSL\nexport const godRaysFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform float u_time;\n\nuniform sampler2D u_noiseTexture;\n\nuniform vec4 u_colorBack;\nuniform vec4 u_colorBloom;\nuniform vec4 u_colors[${ godRaysMeta.maxColorCount }];\nuniform float u_colorsCount;\n\nuniform float u_density;\nuniform float u_spotty;\nuniform float u_midSize;\nuniform float u_midIntensity;\nuniform float u_intensity;\nuniform float u_bloom;\n\nin vec2 v_objectUV;\n\nout vec4 fragColor;\n\n${ declarePI }\n${ rotation2 }\n${ textureRandomizerR }\nfloat valueNoise(vec2 st) {\n vec2 i = floor(st);\n vec2 f = fract(st);\n float a = randomR(i);\n float b = randomR(i + vec2(1.0, 0.0));\n float c = randomR(i + vec2(0.0, 1.0));\n float d = randomR(i + vec2(1.0, 1.0));\n vec2 u = f * f * (3.0 - 2.0 * f);\n float x1 = mix(a, b, u.x);\n float x2 = mix(c, d, u.x);\n return mix(x1, x2, u.y);\n}\n\n${ proceduralHash11 }\n\nfloat raysShape(vec2 uv, float r, float freq, float intensity, float radius) {\n float a = atan(uv.y, uv.x);\n vec2 left = vec2(a * freq, r);\n vec2 right = vec2(fract(a / TWO_PI) * TWO_PI * freq, r);\n float n_left = pow(valueNoise(left), intensity);\n float n_right = pow(valueNoise(right), intensity);\n float shape = mix(n_right, n_left, smoothstep(-.15, .15, uv.x));\n return shape;\n}\n\nvoid main() {\n vec2 shape_uv = v_objectUV;\n\n float t = .2 * u_time;\n\n float radius = length(shape_uv);\n float spots = 6.5 * abs(u_spotty);\n\n float intensity = 4. - 3. * clamp(u_intensity, 0., 1.);\n\n float delta = 1. - smoothstep(0., 1., radius);\n\n float midSize = 10. * abs(u_midSize);\n float ms_lo = 0.02 * midSize;\n float ms_hi = max(midSize, 1e-6);\n float middleShape = pow(u_midIntensity, 0.3) * (1. - smoothstep(ms_lo, ms_hi, 3.0 * radius));\n middleShape = pow(middleShape, 5.0);\n\n vec3 accumColor = vec3(0.0);\n float accumAlpha = 0.0;\n\n for (int i = 0; i < ${ godRaysMeta.maxColorCount }; i++) {\n if (i >= int(u_colorsCount)) break;\n\n vec2 rotatedUV = rotate(shape_uv, float(i) + 1.0);\n\n float r1 = radius * (1.0 + 0.4 * float(i)) - 3.0 * t;\n float r2 = 0.5 * radius * (1.0 + spots) - 2.0 * t;\n float density = 6. * u_density + step(.5, u_density) * pow(4.5 * (u_density - .5), 4.);\n float f = mix(1.0, 3.0 + 0.5 * float(i), hash11(float(i) * 15.)) * density;\n\n float ray = raysShape(rotatedUV, r1, 5.0 * f, intensity, radius);\n ray *= raysShape(rotatedUV, r2, 4.0 * f, intensity, radius);\n ray += (1. + 4. * ray) * middleShape;\n ray = clamp(ray, 0.0, 1.0);\n\n float srcAlpha = u_colors[i].a * ray;\n vec3 srcColor = u_colors[i].rgb * srcAlpha;\n\n vec3 alphaBlendColor = accumColor + (1.0 - accumAlpha) * srcColor;\n float alphaBlendAlpha = accumAlpha + (1.0 - accumAlpha) * srcAlpha;\n\n vec3 addBlendColor = accumColor + srcColor;\n float addBlendAlpha = accumAlpha + srcAlpha;\n\n accumColor = mix(alphaBlendColor, addBlendColor, u_bloom);\n accumAlpha = mix(alphaBlendAlpha, addBlendAlpha, u_bloom);\n }\n\n float overlayAlpha = u_colorBloom.a;\n vec3 overlayColor = u_colorBloom.rgb * overlayAlpha;\n\n vec3 colorWithOverlay = accumColor + accumAlpha * overlayColor;\n accumColor = mix(accumColor, colorWithOverlay, u_bloom);\n\n vec3 bgColor = u_colorBack.rgb * u_colorBack.a;\n\n vec3 color = accumColor + (1. - accumAlpha) * bgColor;\n float opacity = accumAlpha + (1. - accumAlpha) * u_colorBack.a;\n color = clamp(color, 0., 1.);\n opacity = clamp(opacity, 0., 1.);\n\n ${ colorBandingFix }\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface GodRaysUniforms extends ShaderSizingUniforms {\n u_colorBack: [number, number, number, number];\n u_colorBloom: [number, number, number, number];\n u_colors: vec4[];\n u_colorsCount: number;\n u_spotty: number;\n u_midSize: number;\n u_midIntensity: number;\n u_density: number;\n u_intensity: number;\n u_bloom: number;\n u_noiseTexture?: HTMLImageElement;\n}\n\nexport interface GodRaysParams extends ShaderSizingParams, ShaderMotionParams {\n colorBack?: string;\n colorBloom?: string;\n colors?: string[];\n spotty?: number;\n midSize?: number;\n midIntensity?: number;\n density?: number;\n intensity?: number;\n bloom?: number;\n}\n"], + "mappings": ";;;;;AAEA,eAAmE;AACnE,SAAS,WAAW,WAAW,oBAAoB,iBAAiB,wBAAwB;AAErF,MAAM,cAAc;AAAA,EACzB,eAAe;AACjB;AAwCO,MAAM,wBAAgC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBASpB,YAAY,aAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAchD,SAAU;AAAA,EACV,SAAU;AAAA,EACV,kBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcnB,gBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAiCK,YAAY,aAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAyC9C,eAAgB;AAAA;AAAA;AAAA;AAAA;", + "names": [] +} diff --git a/public/vendor/paper-shaders/shaders/grain-gradient.d.ts b/public/vendor/paper-shaders/shaders/grain-gradient.d.ts new file mode 100644 index 0000000..73f1b9f --- /dev/null +++ b/public/vendor/paper-shaders/shaders/grain-gradient.d.ts @@ -0,0 +1,82 @@ +import type { vec4 } from '../types.js'; +import type { ShaderMotionParams } from '../shader-mount.js'; +import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js'; +export declare const grainGradientMeta: { + readonly maxColorCount: 7; +}; +/** + * Multi-color gradients with grainy, noise-textured distortion available in 7 animated abstract forms. + * + * Note: grains are calculated using gl_FragCoord & u_resolution, meaning grains don't react to scaling and fit + * + * Fragment shader uniforms: + * - u_time (float): Animation time + * - u_resolution (vec2): Canvas resolution in pixels + * - u_pixelRatio (float): Device pixel ratio + * - u_originX (float): Reference point for positioning (0 to 1) + * - u_originY (float): Reference point for positioning (0 to 1) + * - u_worldWidth (float): Virtual width of the graphic + * - u_worldHeight (float): Virtual height of the graphic + * - u_fit (float): Fit mode (0 = none, 1 = contain, 2 = cover) + * - u_scale (float): Overall zoom level (0.01 to 4) + * - u_rotation (float): Rotation angle in degrees (0 to 360) + * - u_offsetX (float): Horizontal offset (-1 to 1) + * - u_offsetY (float): Vertical offset (-1 to 1) + * - u_colorBack (vec4): Background color in RGBA + * - u_colors (vec4[]): Up to 7 gradient colors in RGBA + * - u_colorsCount (float): Number of active colors + * - u_softness (float): Color transition sharpness, 0 = hard edge, 1 = smooth gradient (0 to 1) + * - u_intensity (float): Distortion between color bands (0 to 1) + * - u_noise (float): Grainy noise overlay (0 to 1) + * - u_shape (float): Shape type (1 = wave, 2 = dots, 3 = truchet, 4 = corners, 5 = ripple, 6 = blob, 7 = sphere) + * - u_noiseTexture (sampler2D): Pre-computed randomizer source texture + * + * Vertex shader outputs (used in fragment shader): + * - v_objectUV (vec2): Object box UV coordinates with global sizing (scale, rotation, offsets, etc) applied (used for shapes 4-7) + * - v_objectBoxSize (vec2): Size of the object bounding box in pixels + * - v_patternUV (vec2): UV coordinates for pattern with global sizing (rotation, scale, offset, etc) applied (used for shapes 1-3) + * - v_patternBoxSize (vec2): Size of the pattern bounding box in pixels + * + * Vertex shader uniforms: + * - u_resolution (vec2): Canvas resolution in pixels + * - u_pixelRatio (float): Device pixel ratio + * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1) + * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1) + * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas + * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas + * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover) + * - u_scale (float): Overall zoom level of the graphics (0.01 to 4) + * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360) + * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1) + * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1) + * + */ +export declare const grainGradientFragmentShader: string; +export interface GrainGradientUniforms extends ShaderSizingUniforms { + u_colorBack: [number, number, number, number]; + u_colors: vec4[]; + u_colorsCount: number; + u_softness: number; + u_intensity: number; + u_noise: number; + u_shape: (typeof GrainGradientShapes)[GrainGradientShape]; + u_noiseTexture?: HTMLImageElement; +} +export interface GrainGradientParams extends ShaderSizingParams, ShaderMotionParams { + colorBack?: string; + colors?: string[]; + softness?: number; + intensity?: number; + noise?: number; + shape?: GrainGradientShape; +} +export declare const GrainGradientShapes: { + wave: number; + dots: number; + truchet: number; + corners: number; + ripple: number; + blob: number; + sphere: number; +}; +export type GrainGradientShape = keyof typeof GrainGradientShapes; diff --git a/public/vendor/paper-shaders/shaders/grain-gradient.js b/public/vendor/paper-shaders/shaders/grain-gradient.js new file mode 100644 index 0000000..ed7a3fc --- /dev/null +++ b/public/vendor/paper-shaders/shaders/grain-gradient.js @@ -0,0 +1,303 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Paper Shaders * + * https://github.com/paper-design/shaders * + * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +import { +} from "../shader-sizing.js"; +import { + simplexNoise, + declarePI, + rotation2, + textureRandomizerR, + proceduralHash11 +} from "../shader-utils.js"; +const grainGradientMeta = { + maxColorCount: 7 +}; +const grainGradientFragmentShader = `#version 300 es +precision lowp float; + +uniform mediump float u_time; +uniform mediump vec2 u_resolution; +uniform mediump float u_pixelRatio; + +uniform sampler2D u_noiseTexture; + +uniform vec4 u_colorBack; +uniform vec4 u_colors[${grainGradientMeta.maxColorCount}]; +uniform float u_colorsCount; +uniform float u_softness; +uniform float u_intensity; +uniform float u_noise; +uniform float u_shape; + +uniform mediump float u_originX; +uniform mediump float u_originY; +uniform mediump float u_worldWidth; +uniform mediump float u_worldHeight; +uniform mediump float u_fit; + +uniform mediump float u_scale; +uniform mediump float u_rotation; +uniform mediump float u_offsetX; +uniform mediump float u_offsetY; + +in vec2 v_objectUV; +in vec2 v_patternUV; +in vec2 v_objectBoxSize; +in vec2 v_patternBoxSize; + +out vec4 fragColor; + +${declarePI} +${simplexNoise} +${rotation2} +${textureRandomizerR} + +float valueNoiseR(vec2 st) { + vec2 i = floor(st); + vec2 f = fract(st); + float a = randomR(i); + float b = randomR(i + vec2(1.0, 0.0)); + float c = randomR(i + vec2(0.0, 1.0)); + float d = randomR(i + vec2(1.0, 1.0)); + vec2 u = f * f * (3.0 - 2.0 * f); + float x1 = mix(a, b, u.x); + float x2 = mix(c, d, u.x); + return mix(x1, x2, u.y); +} +vec4 fbmR(vec2 n0, vec2 n1, vec2 n2, vec2 n3) { + float amplitude = 0.2; + vec4 total = vec4(0.); + for (int i = 0; i < 3; i++) { + n0 = rotate(n0, 0.3); + n1 = rotate(n1, 0.3); + n2 = rotate(n2, 0.3); + n3 = rotate(n3, 0.3); + total.x += valueNoiseR(n0) * amplitude; + total.y += valueNoiseR(n1) * amplitude; + total.z += valueNoiseR(n2) * amplitude; + total.z += valueNoiseR(n3) * amplitude; + n0 *= 1.99; + n1 *= 1.99; + n2 *= 1.99; + n3 *= 1.99; + amplitude *= 0.6; + } + return total; +} + +${proceduralHash11} + +vec2 truchet(vec2 uv, float idx){ + idx = fract(((idx - .5) * 2.)); + if (idx > 0.75) { + uv = vec2(1.0) - uv; + } else if (idx > 0.5) { + uv = vec2(1.0 - uv.x, uv.y); + } else if (idx > 0.25) { + uv = 1.0 - vec2(1.0 - uv.x, uv.y); + } + return uv; +} + +void main() { + + const float firstFrameOffset = 7.; + float t = .1 * (u_time + firstFrameOffset); + + vec2 shape_uv = vec2(0.); + vec2 grain_uv = vec2(0.); + + float r = u_rotation * PI / 180.; + float cr = cos(r); + float sr = sin(r); + mat2 graphicRotation = mat2(cr, sr, -sr, cr); + vec2 graphicOffset = vec2(-u_offsetX, u_offsetY); + + if (u_shape > 3.5) { + shape_uv = v_objectUV; + grain_uv = shape_uv; + + // apply inverse transform to grain_uv so it respects the originXY + grain_uv = transpose(graphicRotation) * grain_uv; + grain_uv *= u_scale; + grain_uv -= graphicOffset; + grain_uv *= v_objectBoxSize; + grain_uv *= .7; + } else { + shape_uv = .5 * v_patternUV; + grain_uv = 100. * v_patternUV; + + // apply inverse transform to grain_uv so it respects the originXY + grain_uv = transpose(graphicRotation) * grain_uv; + grain_uv *= u_scale; + if (u_fit > 0.) { + vec2 givenBoxSize = vec2(u_worldWidth, u_worldHeight); + givenBoxSize = max(givenBoxSize, vec2(1.)) * u_pixelRatio; + float patternBoxRatio = givenBoxSize.x / givenBoxSize.y; + vec2 patternBoxGivenSize = vec2( + (u_worldWidth == 0.) ? u_resolution.x : givenBoxSize.x, + (u_worldHeight == 0.) ? u_resolution.y : givenBoxSize.y + ); + patternBoxRatio = patternBoxGivenSize.x / patternBoxGivenSize.y; + float patternBoxNoFitBoxWidth = patternBoxRatio * min(patternBoxGivenSize.x / patternBoxRatio, patternBoxGivenSize.y); + grain_uv /= (patternBoxNoFitBoxWidth / v_patternBoxSize.x); + } + vec2 patternBoxScale = u_resolution.xy / v_patternBoxSize; + grain_uv -= graphicOffset / patternBoxScale; + grain_uv *= 1.6; + } + + + float shape = 0.; + + if (u_shape < 1.5) { + // Sine wave + + float wave = cos(.5 * shape_uv.x - 4. * t) * sin(1.5 * shape_uv.x + 2. * t) * (.75 + .25 * cos(6. * t)); + shape = 1. - smoothstep(-1., 1., shape_uv.y + wave); + + } else if (u_shape < 2.5) { + // Grid (dots) + + float stripeIdx = floor(2. * shape_uv.x / TWO_PI); + float rand = hash11(stripeIdx * 100.); + rand = sign(rand - .5) * pow(4. * abs(rand), .3); + shape = sin(shape_uv.x) * cos(shape_uv.y - 5. * rand * t); + shape = pow(abs(shape), 4.); + + } else if (u_shape < 3.5) { + // Truchet pattern + + float n2 = valueNoiseR(shape_uv * .4 - 3.75 * t); + shape_uv.x += 10.; + shape_uv *= .6; + + vec2 tile = truchet(fract(shape_uv), randomR(floor(shape_uv))); + + float distance1 = length(tile); + float distance2 = length(tile - vec2(1.)); + + n2 -= .5; + n2 *= .1; + shape = smoothstep(.2, .55, distance1 + n2) * (1. - smoothstep(.45, .8, distance1 - n2)); + shape += smoothstep(.2, .55, distance2 + n2) * (1. - smoothstep(.45, .8, distance2 - n2)); + + shape = pow(shape, 1.5); + + } else if (u_shape < 4.5) { + // Corners + + shape_uv *= .6; + vec2 outer = vec2(.5); + + vec2 bl = smoothstep(vec2(0.), outer, shape_uv + vec2(.1 + .1 * sin(3. * t), .2 - .1 * sin(5.25 * t))); + vec2 tr = smoothstep(vec2(0.), outer, 1. - shape_uv); + shape = 1. - bl.x * bl.y * tr.x * tr.y; + + shape_uv = -shape_uv; + bl = smoothstep(vec2(0.), outer, shape_uv + vec2(.1 + .1 * sin(3. * t), .2 - .1 * cos(5.25 * t))); + tr = smoothstep(vec2(0.), outer, 1. - shape_uv); + shape -= bl.x * bl.y * tr.x * tr.y; + + shape = 1. - smoothstep(0., 1., shape); + + } else if (u_shape < 5.5) { + // Ripple + + shape_uv *= 2.; + float dist = length(.4 * shape_uv); + float waves = sin(pow(dist, 1.2) * 5. - 3. * t) * .5 + .5; + shape = waves; + + } else if (u_shape < 6.5) { + // Blob + + t *= 2.; + + vec2 f1_traj = .25 * vec2(1.3 * sin(t), .2 + 1.3 * cos(.6 * t + 4.)); + vec2 f2_traj = .2 * vec2(1.2 * sin(-t), 1.3 * sin(1.6 * t)); + vec2 f3_traj = .25 * vec2(1.7 * cos(-.6 * t), cos(-1.6 * t)); + vec2 f4_traj = .3 * vec2(1.4 * cos(.8 * t), 1.2 * sin(-.6 * t - 3.)); + + shape = .5 * pow(1. - clamp(0., 1., length(shape_uv + f1_traj)), 5.); + shape += .5 * pow(1. - clamp(0., 1., length(shape_uv + f2_traj)), 5.); + shape += .5 * pow(1. - clamp(0., 1., length(shape_uv + f3_traj)), 5.); + shape += .5 * pow(1. - clamp(0., 1., length(shape_uv + f4_traj)), 5.); + + shape = smoothstep(.0, .9, shape); + float edge = smoothstep(.25, .3, shape); + shape = mix(.0, shape, edge); + + } else { + // Sphere + + shape_uv *= 2.; + float d = 1. - pow(length(shape_uv), 2.); + vec3 pos = vec3(shape_uv, sqrt(max(d, 0.))); + vec3 lightPos = normalize(vec3(cos(1.5 * t), .8, sin(1.25 * t))); + shape = .5 + .5 * dot(lightPos, pos); + shape *= step(0., d); + } + + float baseNoise = snoise(grain_uv * .5); + vec4 fbmVals = fbmR( + .002 * grain_uv + 10., + .003 * grain_uv, + .001 * grain_uv, + rotate(.4 * grain_uv, 2.) + ); + float grainDist = baseNoise * snoise(grain_uv * .2) - fbmVals.x - fbmVals.y; + float rawNoise = .75 * baseNoise - fbmVals.w - fbmVals.z; + float noise = clamp(rawNoise, 0., 1.); + + shape += u_intensity * 2. / u_colorsCount * (grainDist + .5); + shape += u_noise * 10. / u_colorsCount * noise; + + float aa = fwidth(shape); + + shape = clamp(shape - .5 / u_colorsCount, 0., 1.); + float totalShape = smoothstep(0., u_softness + 2. * aa, clamp(shape * u_colorsCount, 0., 1.)); + float mixer = shape * (u_colorsCount - 1.); + + int cntStop = int(u_colorsCount) - 1; + vec4 gradient = u_colors[0]; + gradient.rgb *= gradient.a; + for (int i = 1; i < ${grainGradientMeta.maxColorCount}; i++) { + if (i > cntStop) break; + + float localT = clamp(mixer - float(i - 1), 0., 1.); + localT = smoothstep(.5 - .5 * u_softness - aa, .5 + .5 * u_softness + aa, localT); + + vec4 c = u_colors[i]; + c.rgb *= c.a; + gradient = mix(gradient, c, localT); + } + + vec3 color = gradient.rgb * totalShape; + float opacity = gradient.a * totalShape; + + vec3 bgColor = u_colorBack.rgb * u_colorBack.a; + color = color + bgColor * (1.0 - opacity); + opacity = opacity + u_colorBack.a * (1.0 - opacity); + + fragColor = vec4(color, opacity); +} +`; +const GrainGradientShapes = { + wave: 1, + dots: 2, + truchet: 3, + corners: 4, + ripple: 5, + blob: 6, + sphere: 7 +}; +export { + GrainGradientShapes, + grainGradientFragmentShader, + grainGradientMeta +}; +//# sourceMappingURL=grain-gradient.js.map diff --git a/public/vendor/paper-shaders/shaders/grain-gradient.js.map b/public/vendor/paper-shaders/shaders/grain-gradient.js.map new file mode 100644 index 0000000..27240ed --- /dev/null +++ b/public/vendor/paper-shaders/shaders/grain-gradient.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../../src/shaders/grain-gradient.ts"], + "sourcesContent": ["import type { vec4 } from '../types.js';\nimport type { ShaderMotionParams } from '../shader-mount.js';\nimport {\n type ShaderSizingParams,\n type ShaderSizingUniforms,\n} from '../shader-sizing.js';\nimport {\n simplexNoise,\n declarePI,\n rotation2,\n textureRandomizerR,\n proceduralHash11,\n} from '../shader-utils.js';\n\nexport const grainGradientMeta = {\n maxColorCount: 7,\n} as const;\n\n/**\n * Multi-color gradients with grainy, noise-textured distortion available in 7 animated abstract forms.\n *\n * Note: grains are calculated using gl_FragCoord & u_resolution, meaning grains don't react to scaling and fit\n *\n * Fragment shader uniforms:\n * - u_time (float): Animation time\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning (0 to 1)\n * - u_originY (float): Reference point for positioning (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic\n * - u_worldHeight (float): Virtual height of the graphic\n * - u_fit (float): Fit mode (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level (0.01 to 4)\n * - u_rotation (float): Rotation angle in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset (-1 to 1)\n * - u_offsetY (float): Vertical offset (-1 to 1)\n * - u_colorBack (vec4): Background color in RGBA\n * - u_colors (vec4[]): Up to 7 gradient colors in RGBA\n * - u_colorsCount (float): Number of active colors\n * - u_softness (float): Color transition sharpness, 0 = hard edge, 1 = smooth gradient (0 to 1)\n * - u_intensity (float): Distortion between color bands (0 to 1)\n * - u_noise (float): Grainy noise overlay (0 to 1)\n * - u_shape (float): Shape type (1 = wave, 2 = dots, 3 = truchet, 4 = corners, 5 = ripple, 6 = blob, 7 = sphere)\n * - u_noiseTexture (sampler2D): Pre-computed randomizer source texture\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_objectUV (vec2): Object box UV coordinates with global sizing (scale, rotation, offsets, etc) applied (used for shapes 4-7)\n * - v_objectBoxSize (vec2): Size of the object bounding box in pixels\n * - v_patternUV (vec2): UV coordinates for pattern with global sizing (rotation, scale, offset, etc) applied (used for shapes 1-3)\n * - v_patternBoxSize (vec2): Size of the pattern bounding box in pixels\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n *\n */\n\n// language=GLSL\nexport const grainGradientFragmentShader: string = `#version 300 es\nprecision lowp float;\n\nuniform mediump float u_time;\nuniform mediump vec2 u_resolution;\nuniform mediump float u_pixelRatio;\n\nuniform sampler2D u_noiseTexture;\n\nuniform vec4 u_colorBack;\nuniform vec4 u_colors[${ grainGradientMeta.maxColorCount }];\nuniform float u_colorsCount;\nuniform float u_softness;\nuniform float u_intensity;\nuniform float u_noise;\nuniform float u_shape;\n\nuniform mediump float u_originX;\nuniform mediump float u_originY;\nuniform mediump float u_worldWidth;\nuniform mediump float u_worldHeight;\nuniform mediump float u_fit;\n\nuniform mediump float u_scale;\nuniform mediump float u_rotation;\nuniform mediump float u_offsetX;\nuniform mediump float u_offsetY;\n\nin vec2 v_objectUV;\nin vec2 v_patternUV;\nin vec2 v_objectBoxSize;\nin vec2 v_patternBoxSize;\n\nout vec4 fragColor;\n\n${ declarePI }\n${ simplexNoise }\n${ rotation2 }\n${ textureRandomizerR }\n\nfloat valueNoiseR(vec2 st) {\n vec2 i = floor(st);\n vec2 f = fract(st);\n float a = randomR(i);\n float b = randomR(i + vec2(1.0, 0.0));\n float c = randomR(i + vec2(0.0, 1.0));\n float d = randomR(i + vec2(1.0, 1.0));\n vec2 u = f * f * (3.0 - 2.0 * f);\n float x1 = mix(a, b, u.x);\n float x2 = mix(c, d, u.x);\n return mix(x1, x2, u.y);\n}\nvec4 fbmR(vec2 n0, vec2 n1, vec2 n2, vec2 n3) {\n float amplitude = 0.2;\n vec4 total = vec4(0.);\n for (int i = 0; i < 3; i++) {\n n0 = rotate(n0, 0.3);\n n1 = rotate(n1, 0.3);\n n2 = rotate(n2, 0.3);\n n3 = rotate(n3, 0.3);\n total.x += valueNoiseR(n0) * amplitude;\n total.y += valueNoiseR(n1) * amplitude;\n total.z += valueNoiseR(n2) * amplitude;\n total.z += valueNoiseR(n3) * amplitude;\n n0 *= 1.99;\n n1 *= 1.99;\n n2 *= 1.99;\n n3 *= 1.99;\n amplitude *= 0.6;\n }\n return total;\n}\n\n${ proceduralHash11 }\n\nvec2 truchet(vec2 uv, float idx){\n idx = fract(((idx - .5) * 2.));\n if (idx > 0.75) {\n uv = vec2(1.0) - uv;\n } else if (idx > 0.5) {\n uv = vec2(1.0 - uv.x, uv.y);\n } else if (idx > 0.25) {\n uv = 1.0 - vec2(1.0 - uv.x, uv.y);\n }\n return uv;\n}\n\nvoid main() {\n\n const float firstFrameOffset = 7.;\n float t = .1 * (u_time + firstFrameOffset);\n\n vec2 shape_uv = vec2(0.);\n vec2 grain_uv = vec2(0.);\n\n float r = u_rotation * PI / 180.;\n float cr = cos(r);\n float sr = sin(r);\n mat2 graphicRotation = mat2(cr, sr, -sr, cr);\n vec2 graphicOffset = vec2(-u_offsetX, u_offsetY);\n\n if (u_shape > 3.5) {\n shape_uv = v_objectUV;\n grain_uv = shape_uv;\n\n // apply inverse transform to grain_uv so it respects the originXY\n grain_uv = transpose(graphicRotation) * grain_uv;\n grain_uv *= u_scale;\n grain_uv -= graphicOffset;\n grain_uv *= v_objectBoxSize;\n grain_uv *= .7;\n } else {\n shape_uv = .5 * v_patternUV;\n grain_uv = 100. * v_patternUV;\n\n // apply inverse transform to grain_uv so it respects the originXY\n grain_uv = transpose(graphicRotation) * grain_uv;\n grain_uv *= u_scale;\n if (u_fit > 0.) {\n vec2 givenBoxSize = vec2(u_worldWidth, u_worldHeight);\n givenBoxSize = max(givenBoxSize, vec2(1.)) * u_pixelRatio;\n float patternBoxRatio = givenBoxSize.x / givenBoxSize.y;\n vec2 patternBoxGivenSize = vec2(\n (u_worldWidth == 0.) ? u_resolution.x : givenBoxSize.x,\n (u_worldHeight == 0.) ? u_resolution.y : givenBoxSize.y\n );\n patternBoxRatio = patternBoxGivenSize.x / patternBoxGivenSize.y;\n float patternBoxNoFitBoxWidth = patternBoxRatio * min(patternBoxGivenSize.x / patternBoxRatio, patternBoxGivenSize.y);\n grain_uv /= (patternBoxNoFitBoxWidth / v_patternBoxSize.x);\n }\n vec2 patternBoxScale = u_resolution.xy / v_patternBoxSize;\n grain_uv -= graphicOffset / patternBoxScale;\n grain_uv *= 1.6;\n }\n\n\n float shape = 0.;\n\n if (u_shape < 1.5) {\n // Sine wave\n\n float wave = cos(.5 * shape_uv.x - 4. * t) * sin(1.5 * shape_uv.x + 2. * t) * (.75 + .25 * cos(6. * t));\n shape = 1. - smoothstep(-1., 1., shape_uv.y + wave);\n\n } else if (u_shape < 2.5) {\n // Grid (dots)\n\n float stripeIdx = floor(2. * shape_uv.x / TWO_PI);\n float rand = hash11(stripeIdx * 100.);\n rand = sign(rand - .5) * pow(4. * abs(rand), .3);\n shape = sin(shape_uv.x) * cos(shape_uv.y - 5. * rand * t);\n shape = pow(abs(shape), 4.);\n\n } else if (u_shape < 3.5) {\n // Truchet pattern\n\n float n2 = valueNoiseR(shape_uv * .4 - 3.75 * t);\n shape_uv.x += 10.;\n shape_uv *= .6;\n\n vec2 tile = truchet(fract(shape_uv), randomR(floor(shape_uv)));\n\n float distance1 = length(tile);\n float distance2 = length(tile - vec2(1.));\n\n n2 -= .5;\n n2 *= .1;\n shape = smoothstep(.2, .55, distance1 + n2) * (1. - smoothstep(.45, .8, distance1 - n2));\n shape += smoothstep(.2, .55, distance2 + n2) * (1. - smoothstep(.45, .8, distance2 - n2));\n\n shape = pow(shape, 1.5);\n\n } else if (u_shape < 4.5) {\n // Corners\n\n shape_uv *= .6;\n vec2 outer = vec2(.5);\n\n vec2 bl = smoothstep(vec2(0.), outer, shape_uv + vec2(.1 + .1 * sin(3. * t), .2 - .1 * sin(5.25 * t)));\n vec2 tr = smoothstep(vec2(0.), outer, 1. - shape_uv);\n shape = 1. - bl.x * bl.y * tr.x * tr.y;\n\n shape_uv = -shape_uv;\n bl = smoothstep(vec2(0.), outer, shape_uv + vec2(.1 + .1 * sin(3. * t), .2 - .1 * cos(5.25 * t)));\n tr = smoothstep(vec2(0.), outer, 1. - shape_uv);\n shape -= bl.x * bl.y * tr.x * tr.y;\n\n shape = 1. - smoothstep(0., 1., shape);\n\n } else if (u_shape < 5.5) {\n // Ripple\n\n shape_uv *= 2.;\n float dist = length(.4 * shape_uv);\n float waves = sin(pow(dist, 1.2) * 5. - 3. * t) * .5 + .5;\n shape = waves;\n\n } else if (u_shape < 6.5) {\n // Blob\n\n t *= 2.;\n\n vec2 f1_traj = .25 * vec2(1.3 * sin(t), .2 + 1.3 * cos(.6 * t + 4.));\n vec2 f2_traj = .2 * vec2(1.2 * sin(-t), 1.3 * sin(1.6 * t));\n vec2 f3_traj = .25 * vec2(1.7 * cos(-.6 * t), cos(-1.6 * t));\n vec2 f4_traj = .3 * vec2(1.4 * cos(.8 * t), 1.2 * sin(-.6 * t - 3.));\n\n shape = .5 * pow(1. - clamp(0., 1., length(shape_uv + f1_traj)), 5.);\n shape += .5 * pow(1. - clamp(0., 1., length(shape_uv + f2_traj)), 5.);\n shape += .5 * pow(1. - clamp(0., 1., length(shape_uv + f3_traj)), 5.);\n shape += .5 * pow(1. - clamp(0., 1., length(shape_uv + f4_traj)), 5.);\n\n shape = smoothstep(.0, .9, shape);\n float edge = smoothstep(.25, .3, shape);\n shape = mix(.0, shape, edge);\n\n } else {\n // Sphere\n\n shape_uv *= 2.;\n float d = 1. - pow(length(shape_uv), 2.);\n vec3 pos = vec3(shape_uv, sqrt(max(d, 0.)));\n vec3 lightPos = normalize(vec3(cos(1.5 * t), .8, sin(1.25 * t)));\n shape = .5 + .5 * dot(lightPos, pos);\n shape *= step(0., d);\n }\n\n float baseNoise = snoise(grain_uv * .5);\n vec4 fbmVals = fbmR(\n .002 * grain_uv + 10.,\n .003 * grain_uv,\n .001 * grain_uv,\n rotate(.4 * grain_uv, 2.)\n );\n float grainDist = baseNoise * snoise(grain_uv * .2) - fbmVals.x - fbmVals.y;\n float rawNoise = .75 * baseNoise - fbmVals.w - fbmVals.z;\n float noise = clamp(rawNoise, 0., 1.);\n\n shape += u_intensity * 2. / u_colorsCount * (grainDist + .5);\n shape += u_noise * 10. / u_colorsCount * noise;\n\n float aa = fwidth(shape);\n\n shape = clamp(shape - .5 / u_colorsCount, 0., 1.);\n float totalShape = smoothstep(0., u_softness + 2. * aa, clamp(shape * u_colorsCount, 0., 1.));\n float mixer = shape * (u_colorsCount - 1.);\n\n int cntStop = int(u_colorsCount) - 1;\n vec4 gradient = u_colors[0];\n gradient.rgb *= gradient.a;\n for (int i = 1; i < ${ grainGradientMeta.maxColorCount }; i++) {\n if (i > cntStop) break;\n\n float localT = clamp(mixer - float(i - 1), 0., 1.);\n localT = smoothstep(.5 - .5 * u_softness - aa, .5 + .5 * u_softness + aa, localT);\n\n vec4 c = u_colors[i];\n c.rgb *= c.a;\n gradient = mix(gradient, c, localT);\n }\n\n vec3 color = gradient.rgb * totalShape;\n float opacity = gradient.a * totalShape;\n\n vec3 bgColor = u_colorBack.rgb * u_colorBack.a;\n color = color + bgColor * (1.0 - opacity);\n opacity = opacity + u_colorBack.a * (1.0 - opacity);\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface GrainGradientUniforms extends ShaderSizingUniforms {\n u_colorBack: [number, number, number, number];\n u_colors: vec4[];\n u_colorsCount: number;\n u_softness: number;\n u_intensity: number;\n u_noise: number;\n u_shape: (typeof GrainGradientShapes)[GrainGradientShape];\n u_noiseTexture?: HTMLImageElement;\n}\n\nexport interface GrainGradientParams extends ShaderSizingParams, ShaderMotionParams {\n colorBack?: string;\n colors?: string[];\n softness?: number;\n intensity?: number;\n noise?: number;\n shape?: GrainGradientShape;\n}\n\nexport const GrainGradientShapes = {\n wave: 1,\n dots: 2,\n truchet: 3,\n corners: 4,\n ripple: 5,\n blob: 6,\n sphere: 7,\n};\n\nexport type GrainGradientShape = keyof typeof GrainGradientShapes;\n"], + "mappings": ";;;;;AAEA;AAAA,OAGO;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEA,MAAM,oBAAoB;AAAA,EAC/B,eAAe;AACjB;AAmDO,MAAM,8BAAsC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAU1B,kBAAkB,aAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAyBtD,SAAU;AAAA,EACV,YAAa;AAAA,EACb,SAAU;AAAA,EACV,kBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmCnB,gBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAiLK,kBAAkB,aAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA0ClD,MAAM,sBAAsB;AAAA,EACjC,MAAM;AAAA,EACN,MAAM;AAAA,EACN,SAAS;AAAA,EACT,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,QAAQ;AACV;", + "names": [] +} diff --git a/public/vendor/paper-shaders/shaders/halftone-cmyk.d.ts b/public/vendor/paper-shaders/shaders/halftone-cmyk.d.ts new file mode 100644 index 0000000..c77f09b --- /dev/null +++ b/public/vendor/paper-shaders/shaders/halftone-cmyk.d.ts @@ -0,0 +1,105 @@ +import type { ShaderMotionParams } from '../shader-mount.js'; +import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js'; +/** + * CMYK halftone printing effect applied to images with customizable dot patterns + * and ink colors for each channel (Cyan, Magenta, Yellow, Black). + * + * Fragment shader uniforms: + * - u_image (sampler2D): Source image texture + * - u_imageAspectRatio (float): Aspect ratio of the source image + * - u_colorBack (vec4): Background (paper) color in RGBA + * - u_colorC (vec4): Cyan ink color in RGBA + * - u_colorM (vec4): Magenta ink color in RGBA + * - u_colorY (vec4): Yellow ink color in RGBA + * - u_colorK (vec4): Black ink color in RGBA + * - u_size (float): Halftone cell size (0 to 1) + * - u_minDot (float): Minimum dot thickness (0 to 1) + * - u_contrast (float): Image contrast adjustment (0 to 2) + * - u_softness (float): Edge softness of dots (0 to 1) + * - u_grainSize (float): Size of grain overlay texture (0 to 1) + * - u_grainMixer (float): Strength of grain affecting dot size (0 to 1) + * - u_grainOverlay (float): Strength of grain overlay on final output (0 to 1) + * - u_gridNoise (float): Strength of smooth noise applied to both dot positions and color sampling (0 to 1) + * - u_floodC (float): Flat cyan dot size adjustment applied uniformly (-1 to 1) + * - u_floodM (float): Flat magenta dot size adjustment applied uniformly (-1 to 1) + * - u_floodY (float): Flat yellow dot size adjustment applied uniformly (-1 to 1) + * - u_floodK (float): Flat black dot size adjustment applied uniformly (-1 to 1) + * - u_gainC (float): Proportional cyan dot size gain (enhances existing dots, -1 to 1) + * - u_gainM (float): Proportional magenta dot size gain (enhances existing dots, -1 to 1) + * - u_gainY (float): Proportional yellow dot size gain (enhances existing dots, -1 to 1) + * - u_gainK (float): Proportional black dot size gain (enhances existing dots, -1 to 1) + * - u_type (float): Dot shape style (0 = dots, 1 = ink, 2 = sharp) + * - u_noiseTexture (sampler2D): Pre-computed randomizer source texture + * + * Vertex shader outputs (used in fragment shader): + * - v_imageUV (vec2): UV coordinates for sampling the source image, with fit, scale, rotation, and offset applied + * + * Vertex shader uniforms: + * - u_resolution (vec2): Canvas resolution in pixels + * - u_pixelRatio (float): Device pixel ratio + * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1) + * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1) + * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover) + * - u_scale (float): Overall zoom level of the graphics (0.01 to 4) + * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360) + * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1) + * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1) + * - u_imageAspectRatio (float): Aspect ratio of the source image + * + */ +export declare const halftoneCmykFragmentShader: string; +export interface HalftoneCmykUniforms extends ShaderSizingUniforms { + u_image: HTMLImageElement | string | undefined; + u_noiseTexture?: HTMLImageElement; + u_colorBack: [number, number, number, number]; + u_colorC: [number, number, number, number]; + u_colorM: [number, number, number, number]; + u_colorY: [number, number, number, number]; + u_colorK: [number, number, number, number]; + u_size: number; + u_contrast: number; + u_softness: number; + u_grainSize: number; + u_grainMixer: number; + u_grainOverlay: number; + u_gridNoise: number; + u_floodC: number; + u_floodM: number; + u_floodY: number; + u_floodK: number; + u_gainC: number; + u_gainM: number; + u_gainY: number; + u_gainK: number; + u_type: (typeof HalftoneCmykTypes)[HalftoneCmykType]; +} +export interface HalftoneCmykParams extends ShaderSizingParams, ShaderMotionParams { + image?: HTMLImageElement | string; + colorBack?: string; + colorC?: string; + colorM?: string; + colorY?: string; + colorK?: string; + size?: number; + contrast?: number; + softness?: number; + grainSize?: number; + grainMixer?: number; + grainOverlay?: number; + gridNoise?: number; + floodC?: number; + floodM?: number; + floodY?: number; + floodK?: number; + gainC?: number; + gainM?: number; + gainY?: number; + gainK?: number; + type?: HalftoneCmykType; +} +export declare const HalftoneCmykTypes: { + readonly dots: 0; + readonly ink: 1; + readonly sharp: 2; +}; +export type HalftoneCmykType = keyof typeof HalftoneCmykTypes; diff --git a/public/vendor/paper-shaders/shaders/halftone-cmyk.js b/public/vendor/paper-shaders/shaders/halftone-cmyk.js new file mode 100644 index 0000000..e361a7c --- /dev/null +++ b/public/vendor/paper-shaders/shaders/halftone-cmyk.js @@ -0,0 +1,292 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Paper Shaders * + * https://github.com/paper-design/shaders * + * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +import {} from "../shader-sizing.js"; +import { declarePI } from "../shader-utils.js"; +const halftoneCmykFragmentShader = `#version 300 es +precision mediump float; + +uniform sampler2D u_image; +uniform float u_imageAspectRatio; + +uniform vec4 u_colorBack; +uniform vec4 u_colorC; +uniform vec4 u_colorM; +uniform vec4 u_colorY; +uniform vec4 u_colorK; +uniform float u_size; +uniform float u_minDot; +uniform float u_contrast; +uniform float u_grainSize; +uniform float u_grainMixer; +uniform float u_grainOverlay; +uniform float u_gridNoise; +uniform float u_softness; +uniform float u_floodC; +uniform float u_floodM; +uniform float u_floodY; +uniform float u_floodK; +uniform float u_gainC; +uniform float u_gainM; +uniform float u_gainY; +uniform float u_gainK; +uniform float u_type; +uniform sampler2D u_noiseTexture; + +in vec2 v_imageUV; +out vec4 fragColor; + +const float shiftC = -.5; +const float shiftM = -.25; +const float shiftY = .2; +const float shiftK = 0.; + +// Precomputed sin/cos for rotation angles (15\xB0, 75\xB0, 0\xB0, 45\xB0) +const float cosC = 0.9659258; const float sinC = 0.2588190; // 15\xB0 +const float cosM = 0.2588190; const float sinM = 0.9659258; // 75\xB0 +const float cosY = 1.0; const float sinY = 0.0; // 0\xB0 +const float cosK = 0.7071068; const float sinK = 0.7071068; // 45\xB0 + +${declarePI} + +vec2 randomRG(vec2 p) { + vec2 uv = floor(p) / 100. + .5; + return texture(u_noiseTexture, fract(uv)).rg; +} +vec3 hash23(vec2 p) { + vec3 p3 = fract(vec3(p.xyx) * vec3(0.3183099, 0.3678794, 0.3141592)) + 0.1; + p3 += dot(p3, p3.yzx + 19.19); + return fract(vec3(p3.x * p3.y, p3.y * p3.z, p3.z * p3.x)); +} + +float sst(float edge0, float edge1, float x) { + return smoothstep(edge0, edge1, x); +} + +vec3 valueNoise3(vec2 st) { + vec2 i = floor(st); + vec2 f = fract(st); + vec3 a = hash23(i); + vec3 b = hash23(i + vec2(1.0, 0.0)); + vec3 c = hash23(i + vec2(0.0, 1.0)); + vec3 d = hash23(i + vec2(1.0, 1.0)); + vec2 u = f * f * (3.0 - 2.0 * f); + vec3 x1 = mix(a, b, u.x); + vec3 x2 = mix(c, d, u.x); + return mix(x1, x2, u.y); +} + +float getUvFrame(vec2 uv, vec2 pad) { + float left = smoothstep(-pad.x, 0., uv.x); + float right = smoothstep(1. + pad.x, 1., uv.x); + float bottom = smoothstep(-pad.y, 0., uv.y); + float top = smoothstep(1. + pad.y, 1., uv.y); + + return left * right * bottom * top; +} + +vec4 RGBAtoCMYK(vec4 rgba) { + float k = 1. - max(max(rgba.r, rgba.g), rgba.b); + float denom = 1. - k; + vec3 cmy = vec3(0.); + if (denom > 1e-5) { + cmy = (1. - rgba.rgb - vec3(k)) / denom; + } + return vec4(cmy, k) * rgba.a; +} + +vec3 applyContrast(vec3 rgb) { + return clamp((rgb - 0.5) * u_contrast + 0.5, 0.0, 1.0); +} + +// Single-component CMYK extractors with contrast built-in, alpha-aware +float getCyan(vec4 rgba) { + vec3 c = clamp((rgba.rgb - 0.5) * u_contrast + 0.5, 0.0, 1.0); + float maxRGB = max(max(c.r, c.g), c.b); + return (maxRGB > 1e-5 ? (maxRGB - c.r) / maxRGB : 0.) * rgba.a; +} +float getMagenta(vec4 rgba) { + vec3 c = clamp((rgba.rgb - 0.5) * u_contrast + 0.5, 0.0, 1.0); + float maxRGB = max(max(c.r, c.g), c.b); + return (maxRGB > 1e-5 ? (maxRGB - c.g) / maxRGB : 0.) * rgba.a; +} +float getYellow(vec4 rgba) { + vec3 c = clamp((rgba.rgb - 0.5) * u_contrast + 0.5, 0.0, 1.0); + float maxRGB = max(max(c.r, c.g), c.b); + return (maxRGB > 1e-5 ? (maxRGB - c.b) / maxRGB : 0.) * rgba.a; +} +float getBlack(vec4 rgba) { + vec3 c = clamp((rgba.rgb - 0.5) * u_contrast + 0.5, 0.0, 1.0); + return (1. - max(max(c.r, c.g), c.b)) * rgba.a; +} + +vec2 cellCenterPos(vec2 uv, vec2 cellOffset, float channelIdx) { + vec2 cellCenter = floor(uv) + .5 + cellOffset; + return cellCenter + (randomRG(cellCenter + channelIdx * 50.) - .5) * u_gridNoise; +} + +vec2 gridToImageUV(vec2 cellCenter, float cosA, float sinA, float shift, vec2 pad) { + vec2 uvGrid = mat2(cosA, -sinA, sinA, cosA) * (cellCenter - shift); + return uvGrid * pad + 0.5; +} + +void colorMask(vec2 pos, vec2 cellCenter, float rad, float transparency, float grain, float channelAddon, float channelgain, float generalComp, bool isJoined, inout float outMask) { + float dist = length(pos - cellCenter); + + float radius = rad; + radius *= (1. + generalComp); + radius += (.15 + channelgain * radius); + radius = max(0., radius); + radius = mix(0., radius, transparency); + radius += channelAddon; + radius *= (1. - grain); + + float mask = 1. - sst(0., radius, dist); + if (isJoined) { + // ink or sharp (joined) + mask = pow(mask, 1.2); + } else { + // dots (separate) + mask = sst(.5 - .5 * u_softness, .51 + .49 * u_softness, mask); + } + + mask *= mix(1., mix(.5, 1., 1.5 * radius), u_softness); + outMask += mask; +} + +vec3 applyInk(vec3 paper, vec3 inkColor, float cov) { + vec3 inkEffect = mix(vec3(1.0), inkColor, clamp(cov, 0.0, 1.0)); + return paper * inkEffect; +} + +void main() { + vec2 uv = v_imageUV; + + float cellsPerSide = mix(400.0, 7.0, pow(u_size, 0.7)); + float cellSizeY = 1.0 / cellsPerSide; + vec2 pad = cellSizeY * vec2(1.0 / u_imageAspectRatio, 1.0); + vec2 uvGrid = (uv - .5) / pad; + float insideImageBox = getUvFrame(uv, pad); + + float generalComp = .1 * u_softness + .1 * u_gridNoise + .1 * (1. - step(0.5, u_type)) * (1.5 - u_softness); + + vec2 uvC = mat2(cosC, sinC, -sinC, cosC) * uvGrid + shiftC; + vec2 uvM = mat2(cosM, sinM, -sinM, cosM) * uvGrid + shiftM; + vec2 uvY = mat2(cosY, sinY, -sinY, cosY) * uvGrid + shiftY; + vec2 uvK = mat2(cosK, sinK, -sinK, cosK) * uvGrid + shiftK; + + vec2 grainSize = mix(2000., 200., u_grainSize) * vec2(1., 1. / u_imageAspectRatio); + vec2 grainUV = (v_imageUV - .5) * grainSize + .5; + vec3 noiseValues = valueNoise3(grainUV); + float grain = sst(.55, 1., noiseValues.r); + grain *= u_grainMixer; + + vec4 outMask = vec4(0.); + bool isJoined = u_type > 0.5; + + if (u_type < 1.5) { + // dots or ink: per-cell color sampling + for (int dy = -1; dy <= 1; dy++) { + for (int dx = -1; dx <= 1; dx++) { + vec2 cellOffset = vec2(float(dx), float(dy)); + + vec2 cellCenterC = cellCenterPos(uvC, cellOffset, 0.); + vec4 texC = texture(u_image, gridToImageUV(cellCenterC, cosC, sinC, shiftC, pad)); + colorMask(uvC, cellCenterC, getCyan(texC), insideImageBox * texC.a, grain, u_floodC, u_gainC, generalComp, isJoined, outMask[0]); + + vec2 cellCenterM = cellCenterPos(uvM, cellOffset, 1.); + vec4 texM = texture(u_image, gridToImageUV(cellCenterM, cosM, sinM, shiftM, pad)); + colorMask(uvM, cellCenterM, getMagenta(texM), insideImageBox * texM.a, grain, u_floodM, u_gainM, generalComp, isJoined, outMask[1]); + + vec2 cellCenterY = cellCenterPos(uvY, cellOffset, 2.); + vec4 texY = texture(u_image, gridToImageUV(cellCenterY, cosY, sinY, shiftY, pad)); + colorMask(uvY, cellCenterY, getYellow(texY), insideImageBox * texY.a, grain, u_floodY, u_gainY, generalComp, isJoined, outMask[2]); + + vec2 cellCenterK = cellCenterPos(uvK, cellOffset, 3.); + vec4 texK = texture(u_image, gridToImageUV(cellCenterK, cosK, sinK, shiftK, pad)); + colorMask(uvK, cellCenterK, getBlack(texK), insideImageBox * texK.a, grain, u_floodK, u_gainK, generalComp, isJoined, outMask[3]); + } + } + } else { + // sharp: direct px color sampling + vec4 tex = texture(u_image, uv); + tex.rgb = applyContrast(tex.rgb); + insideImageBox *= tex.a; + vec4 cmykOriginal = RGBAtoCMYK(tex); + for (int dy = -1; dy <= 1; dy++) { + for (int dx = -1; dx <= 1; dx++) { + vec2 cellOffset = vec2(float(dx), float(dy)); + + colorMask(uvC, cellCenterPos(uvC, cellOffset, 0.), cmykOriginal.x, insideImageBox, grain, u_floodC, u_gainC, generalComp, isJoined, outMask[0]); + colorMask(uvM, cellCenterPos(uvM, cellOffset, 1.), cmykOriginal.y, insideImageBox, grain, u_floodM, u_gainM, generalComp, isJoined, outMask[1]); + colorMask(uvY, cellCenterPos(uvY, cellOffset, 2.), cmykOriginal.z, insideImageBox, grain, u_floodY, u_gainY, generalComp, isJoined, outMask[2]); + colorMask(uvK, cellCenterPos(uvK, cellOffset, 3.), cmykOriginal.w, insideImageBox, grain, u_floodK, u_gainK, generalComp, isJoined, outMask[3]); + } + } + } + + float shape; + + float C = outMask[0]; + float M = outMask[1]; + float Y = outMask[2]; + float K = outMask[3]; + + if (isJoined) { + // ink or sharp: apply threshold for joined dots + float th = .5; + float sLeft = th * u_softness; + float sRight = (1. - th) * u_softness + .01; + C = smoothstep(th - sLeft - fwidth(C), th + sRight, C); + M = smoothstep(th - sLeft - fwidth(M), th + sRight, M); + Y = smoothstep(th - sLeft - fwidth(Y), th + sRight, Y); + K = smoothstep(th - sLeft - fwidth(K), th + sRight, K); + } + + C *= u_colorC.a; + M *= u_colorM.a; + Y *= u_colorY.a; + K *= u_colorK.a; + + vec3 ink = vec3(1.); + ink = applyInk(ink, u_colorK.rgb, K); + ink = applyInk(ink, u_colorC.rgb, C); + ink = applyInk(ink, u_colorM.rgb, M); + ink = applyInk(ink, u_colorY.rgb, Y); + + shape = clamp(max(max(C, M), max(Y, K)), 0., 1.); + + vec3 color = u_colorBack.rgb * u_colorBack.a; + + float opacity = u_colorBack.a; + color = mix(color, ink, shape); + opacity += shape; + opacity = clamp(opacity, 0., 1.); + + float grainOverlay = mix(noiseValues.g, noiseValues.b, .5); + grainOverlay = pow(grainOverlay, 1.3); + + float grainOverlayV = grainOverlay * 2. - 1.; + vec3 grainOverlayColor = vec3(step(0., grainOverlayV)); + float grainOverlayStrength = u_grainOverlay * abs(grainOverlayV); + grainOverlayStrength = pow(grainOverlayStrength, .8); + color = mix(color, grainOverlayColor, .5 * grainOverlayStrength); + + opacity += .5 * grainOverlayStrength; + opacity = clamp(opacity, 0., 1.); + + fragColor = vec4(color, opacity); +} +`; +const HalftoneCmykTypes = { + dots: 0, + ink: 1, + sharp: 2 +}; +export { + HalftoneCmykTypes, + halftoneCmykFragmentShader +}; +//# sourceMappingURL=halftone-cmyk.js.map diff --git a/public/vendor/paper-shaders/shaders/halftone-cmyk.js.map b/public/vendor/paper-shaders/shaders/halftone-cmyk.js.map new file mode 100644 index 0000000..3dc3d4e --- /dev/null +++ b/public/vendor/paper-shaders/shaders/halftone-cmyk.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../../src/shaders/halftone-cmyk.ts"], + "sourcesContent": ["import type { ShaderMotionParams } from '../shader-mount.js';\nimport { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { declarePI } from '../shader-utils.js';\n\n/**\n * CMYK halftone printing effect applied to images with customizable dot patterns\n * and ink colors for each channel (Cyan, Magenta, Yellow, Black).\n *\n * Fragment shader uniforms:\n * - u_image (sampler2D): Source image texture\n * - u_imageAspectRatio (float): Aspect ratio of the source image\n * - u_colorBack (vec4): Background (paper) color in RGBA\n * - u_colorC (vec4): Cyan ink color in RGBA\n * - u_colorM (vec4): Magenta ink color in RGBA\n * - u_colorY (vec4): Yellow ink color in RGBA\n * - u_colorK (vec4): Black ink color in RGBA\n * - u_size (float): Halftone cell size (0 to 1)\n * - u_minDot (float): Minimum dot thickness (0 to 1)\n * - u_contrast (float): Image contrast adjustment (0 to 2)\n * - u_softness (float): Edge softness of dots (0 to 1)\n * - u_grainSize (float): Size of grain overlay texture (0 to 1)\n * - u_grainMixer (float): Strength of grain affecting dot size (0 to 1)\n * - u_grainOverlay (float): Strength of grain overlay on final output (0 to 1)\n * - u_gridNoise (float): Strength of smooth noise applied to both dot positions and color sampling (0 to 1)\n * - u_floodC (float): Flat cyan dot size adjustment applied uniformly (-1 to 1)\n * - u_floodM (float): Flat magenta dot size adjustment applied uniformly (-1 to 1)\n * - u_floodY (float): Flat yellow dot size adjustment applied uniformly (-1 to 1)\n * - u_floodK (float): Flat black dot size adjustment applied uniformly (-1 to 1)\n * - u_gainC (float): Proportional cyan dot size gain (enhances existing dots, -1 to 1)\n * - u_gainM (float): Proportional magenta dot size gain (enhances existing dots, -1 to 1)\n * - u_gainY (float): Proportional yellow dot size gain (enhances existing dots, -1 to 1)\n * - u_gainK (float): Proportional black dot size gain (enhances existing dots, -1 to 1)\n * - u_type (float): Dot shape style (0 = dots, 1 = ink, 2 = sharp)\n * - u_noiseTexture (sampler2D): Pre-computed randomizer source texture\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_imageUV (vec2): UV coordinates for sampling the source image, with fit, scale, rotation, and offset applied\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n * - u_imageAspectRatio (float): Aspect ratio of the source image\n *\n */\n\n// language=GLSL\nexport const halftoneCmykFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform sampler2D u_image;\nuniform float u_imageAspectRatio;\n\nuniform vec4 u_colorBack;\nuniform vec4 u_colorC;\nuniform vec4 u_colorM;\nuniform vec4 u_colorY;\nuniform vec4 u_colorK;\nuniform float u_size;\nuniform float u_minDot;\nuniform float u_contrast;\nuniform float u_grainSize;\nuniform float u_grainMixer;\nuniform float u_grainOverlay;\nuniform float u_gridNoise;\nuniform float u_softness;\nuniform float u_floodC;\nuniform float u_floodM;\nuniform float u_floodY;\nuniform float u_floodK;\nuniform float u_gainC;\nuniform float u_gainM;\nuniform float u_gainY;\nuniform float u_gainK;\nuniform float u_type;\nuniform sampler2D u_noiseTexture;\n\nin vec2 v_imageUV;\nout vec4 fragColor;\n\nconst float shiftC = -.5;\nconst float shiftM = -.25;\nconst float shiftY = .2;\nconst float shiftK = 0.;\n\n// Precomputed sin/cos for rotation angles (15\u00B0, 75\u00B0, 0\u00B0, 45\u00B0)\nconst float cosC = 0.9659258; const float sinC = 0.2588190; // 15\u00B0\nconst float cosM = 0.2588190; const float sinM = 0.9659258; // 75\u00B0\nconst float cosY = 1.0; const float sinY = 0.0; // 0\u00B0\nconst float cosK = 0.7071068; const float sinK = 0.7071068; // 45\u00B0\n\n${ declarePI }\n\nvec2 randomRG(vec2 p) {\n vec2 uv = floor(p) / 100. + .5;\n return texture(u_noiseTexture, fract(uv)).rg;\n}\nvec3 hash23(vec2 p) {\n vec3 p3 = fract(vec3(p.xyx) * vec3(0.3183099, 0.3678794, 0.3141592)) + 0.1;\n p3 += dot(p3, p3.yzx + 19.19);\n return fract(vec3(p3.x * p3.y, p3.y * p3.z, p3.z * p3.x));\n}\n\nfloat sst(float edge0, float edge1, float x) {\n return smoothstep(edge0, edge1, x);\n}\n\nvec3 valueNoise3(vec2 st) {\n vec2 i = floor(st);\n vec2 f = fract(st);\n vec3 a = hash23(i);\n vec3 b = hash23(i + vec2(1.0, 0.0));\n vec3 c = hash23(i + vec2(0.0, 1.0));\n vec3 d = hash23(i + vec2(1.0, 1.0));\n vec2 u = f * f * (3.0 - 2.0 * f);\n vec3 x1 = mix(a, b, u.x);\n vec3 x2 = mix(c, d, u.x);\n return mix(x1, x2, u.y);\n}\n\nfloat getUvFrame(vec2 uv, vec2 pad) {\n float left = smoothstep(-pad.x, 0., uv.x);\n float right = smoothstep(1. + pad.x, 1., uv.x);\n float bottom = smoothstep(-pad.y, 0., uv.y);\n float top = smoothstep(1. + pad.y, 1., uv.y);\n\n return left * right * bottom * top;\n}\n\nvec4 RGBAtoCMYK(vec4 rgba) {\n float k = 1. - max(max(rgba.r, rgba.g), rgba.b);\n float denom = 1. - k;\n vec3 cmy = vec3(0.);\n if (denom > 1e-5) {\n cmy = (1. - rgba.rgb - vec3(k)) / denom;\n }\n return vec4(cmy, k) * rgba.a;\n}\n\nvec3 applyContrast(vec3 rgb) {\n return clamp((rgb - 0.5) * u_contrast + 0.5, 0.0, 1.0);\n}\n\n// Single-component CMYK extractors with contrast built-in, alpha-aware\nfloat getCyan(vec4 rgba) {\n vec3 c = clamp((rgba.rgb - 0.5) * u_contrast + 0.5, 0.0, 1.0);\n float maxRGB = max(max(c.r, c.g), c.b);\n return (maxRGB > 1e-5 ? (maxRGB - c.r) / maxRGB : 0.) * rgba.a;\n}\nfloat getMagenta(vec4 rgba) {\n vec3 c = clamp((rgba.rgb - 0.5) * u_contrast + 0.5, 0.0, 1.0);\n float maxRGB = max(max(c.r, c.g), c.b);\n return (maxRGB > 1e-5 ? (maxRGB - c.g) / maxRGB : 0.) * rgba.a;\n}\nfloat getYellow(vec4 rgba) {\n vec3 c = clamp((rgba.rgb - 0.5) * u_contrast + 0.5, 0.0, 1.0);\n float maxRGB = max(max(c.r, c.g), c.b);\n return (maxRGB > 1e-5 ? (maxRGB - c.b) / maxRGB : 0.) * rgba.a;\n}\nfloat getBlack(vec4 rgba) {\n vec3 c = clamp((rgba.rgb - 0.5) * u_contrast + 0.5, 0.0, 1.0);\n return (1. - max(max(c.r, c.g), c.b)) * rgba.a;\n}\n\nvec2 cellCenterPos(vec2 uv, vec2 cellOffset, float channelIdx) {\n vec2 cellCenter = floor(uv) + .5 + cellOffset;\n return cellCenter + (randomRG(cellCenter + channelIdx * 50.) - .5) * u_gridNoise;\n}\n\nvec2 gridToImageUV(vec2 cellCenter, float cosA, float sinA, float shift, vec2 pad) {\n vec2 uvGrid = mat2(cosA, -sinA, sinA, cosA) * (cellCenter - shift);\n return uvGrid * pad + 0.5;\n}\n\nvoid colorMask(vec2 pos, vec2 cellCenter, float rad, float transparency, float grain, float channelAddon, float channelgain, float generalComp, bool isJoined, inout float outMask) {\n float dist = length(pos - cellCenter);\n\n float radius = rad;\n radius *= (1. + generalComp);\n radius += (.15 + channelgain * radius);\n radius = max(0., radius);\n radius = mix(0., radius, transparency);\n radius += channelAddon;\n radius *= (1. - grain);\n\n float mask = 1. - sst(0., radius, dist);\n if (isJoined) {\n // ink or sharp (joined)\n mask = pow(mask, 1.2);\n } else {\n // dots (separate)\n mask = sst(.5 - .5 * u_softness, .51 + .49 * u_softness, mask);\n }\n\n mask *= mix(1., mix(.5, 1., 1.5 * radius), u_softness);\n outMask += mask;\n}\n\nvec3 applyInk(vec3 paper, vec3 inkColor, float cov) {\n vec3 inkEffect = mix(vec3(1.0), inkColor, clamp(cov, 0.0, 1.0));\n return paper * inkEffect;\n}\n\nvoid main() {\n vec2 uv = v_imageUV;\n\n float cellsPerSide = mix(400.0, 7.0, pow(u_size, 0.7));\n float cellSizeY = 1.0 / cellsPerSide;\n vec2 pad = cellSizeY * vec2(1.0 / u_imageAspectRatio, 1.0);\n vec2 uvGrid = (uv - .5) / pad;\n float insideImageBox = getUvFrame(uv, pad);\n\n float generalComp = .1 * u_softness + .1 * u_gridNoise + .1 * (1. - step(0.5, u_type)) * (1.5 - u_softness);\n\n vec2 uvC = mat2(cosC, sinC, -sinC, cosC) * uvGrid + shiftC;\n vec2 uvM = mat2(cosM, sinM, -sinM, cosM) * uvGrid + shiftM;\n vec2 uvY = mat2(cosY, sinY, -sinY, cosY) * uvGrid + shiftY;\n vec2 uvK = mat2(cosK, sinK, -sinK, cosK) * uvGrid + shiftK;\n\n vec2 grainSize = mix(2000., 200., u_grainSize) * vec2(1., 1. / u_imageAspectRatio);\n vec2 grainUV = (v_imageUV - .5) * grainSize + .5;\n vec3 noiseValues = valueNoise3(grainUV);\n float grain = sst(.55, 1., noiseValues.r);\n grain *= u_grainMixer;\n\n vec4 outMask = vec4(0.);\n bool isJoined = u_type > 0.5;\n\n if (u_type < 1.5) {\n // dots or ink: per-cell color sampling\n for (int dy = -1; dy <= 1; dy++) {\n for (int dx = -1; dx <= 1; dx++) {\n vec2 cellOffset = vec2(float(dx), float(dy));\n\n vec2 cellCenterC = cellCenterPos(uvC, cellOffset, 0.);\n vec4 texC = texture(u_image, gridToImageUV(cellCenterC, cosC, sinC, shiftC, pad));\n colorMask(uvC, cellCenterC, getCyan(texC), insideImageBox * texC.a, grain, u_floodC, u_gainC, generalComp, isJoined, outMask[0]);\n\n vec2 cellCenterM = cellCenterPos(uvM, cellOffset, 1.);\n vec4 texM = texture(u_image, gridToImageUV(cellCenterM, cosM, sinM, shiftM, pad));\n colorMask(uvM, cellCenterM, getMagenta(texM), insideImageBox * texM.a, grain, u_floodM, u_gainM, generalComp, isJoined, outMask[1]);\n\n vec2 cellCenterY = cellCenterPos(uvY, cellOffset, 2.);\n vec4 texY = texture(u_image, gridToImageUV(cellCenterY, cosY, sinY, shiftY, pad));\n colorMask(uvY, cellCenterY, getYellow(texY), insideImageBox * texY.a, grain, u_floodY, u_gainY, generalComp, isJoined, outMask[2]);\n\n vec2 cellCenterK = cellCenterPos(uvK, cellOffset, 3.);\n vec4 texK = texture(u_image, gridToImageUV(cellCenterK, cosK, sinK, shiftK, pad));\n colorMask(uvK, cellCenterK, getBlack(texK), insideImageBox * texK.a, grain, u_floodK, u_gainK, generalComp, isJoined, outMask[3]);\n }\n }\n } else {\n // sharp: direct px color sampling\n vec4 tex = texture(u_image, uv);\n tex.rgb = applyContrast(tex.rgb);\n insideImageBox *= tex.a;\n vec4 cmykOriginal = RGBAtoCMYK(tex);\n for (int dy = -1; dy <= 1; dy++) {\n for (int dx = -1; dx <= 1; dx++) {\n vec2 cellOffset = vec2(float(dx), float(dy));\n\n colorMask(uvC, cellCenterPos(uvC, cellOffset, 0.), cmykOriginal.x, insideImageBox, grain, u_floodC, u_gainC, generalComp, isJoined, outMask[0]);\n colorMask(uvM, cellCenterPos(uvM, cellOffset, 1.), cmykOriginal.y, insideImageBox, grain, u_floodM, u_gainM, generalComp, isJoined, outMask[1]);\n colorMask(uvY, cellCenterPos(uvY, cellOffset, 2.), cmykOriginal.z, insideImageBox, grain, u_floodY, u_gainY, generalComp, isJoined, outMask[2]);\n colorMask(uvK, cellCenterPos(uvK, cellOffset, 3.), cmykOriginal.w, insideImageBox, grain, u_floodK, u_gainK, generalComp, isJoined, outMask[3]);\n }\n }\n }\n\n float shape;\n\n float C = outMask[0];\n float M = outMask[1];\n float Y = outMask[2];\n float K = outMask[3];\n\n if (isJoined) {\n // ink or sharp: apply threshold for joined dots\n float th = .5;\n float sLeft = th * u_softness;\n float sRight = (1. - th) * u_softness + .01;\n C = smoothstep(th - sLeft - fwidth(C), th + sRight, C);\n M = smoothstep(th - sLeft - fwidth(M), th + sRight, M);\n Y = smoothstep(th - sLeft - fwidth(Y), th + sRight, Y);\n K = smoothstep(th - sLeft - fwidth(K), th + sRight, K);\n }\n\n C *= u_colorC.a;\n M *= u_colorM.a;\n Y *= u_colorY.a;\n K *= u_colorK.a;\n\n vec3 ink = vec3(1.);\n ink = applyInk(ink, u_colorK.rgb, K);\n ink = applyInk(ink, u_colorC.rgb, C);\n ink = applyInk(ink, u_colorM.rgb, M);\n ink = applyInk(ink, u_colorY.rgb, Y);\n\n shape = clamp(max(max(C, M), max(Y, K)), 0., 1.);\n\n vec3 color = u_colorBack.rgb * u_colorBack.a;\n\n float opacity = u_colorBack.a;\n color = mix(color, ink, shape);\n opacity += shape;\n opacity = clamp(opacity, 0., 1.);\n\n float grainOverlay = mix(noiseValues.g, noiseValues.b, .5);\n grainOverlay = pow(grainOverlay, 1.3);\n\n float grainOverlayV = grainOverlay * 2. - 1.;\n vec3 grainOverlayColor = vec3(step(0., grainOverlayV));\n float grainOverlayStrength = u_grainOverlay * abs(grainOverlayV);\n grainOverlayStrength = pow(grainOverlayStrength, .8);\n color = mix(color, grainOverlayColor, .5 * grainOverlayStrength);\n\n opacity += .5 * grainOverlayStrength;\n opacity = clamp(opacity, 0., 1.);\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface HalftoneCmykUniforms extends ShaderSizingUniforms {\n u_image: HTMLImageElement | string | undefined;\n u_noiseTexture?: HTMLImageElement;\n u_colorBack: [number, number, number, number];\n u_colorC: [number, number, number, number];\n u_colorM: [number, number, number, number];\n u_colorY: [number, number, number, number];\n u_colorK: [number, number, number, number];\n u_size: number;\n u_contrast: number;\n u_softness: number;\n u_grainSize: number;\n u_grainMixer: number;\n u_grainOverlay: number;\n u_gridNoise: number;\n u_floodC: number;\n u_floodM: number;\n u_floodY: number;\n u_floodK: number;\n u_gainC: number;\n u_gainM: number;\n u_gainY: number;\n u_gainK: number;\n u_type: (typeof HalftoneCmykTypes)[HalftoneCmykType];\n}\n\nexport interface HalftoneCmykParams extends ShaderSizingParams, ShaderMotionParams {\n image?: HTMLImageElement | string;\n colorBack?: string;\n colorC?: string;\n colorM?: string;\n colorY?: string;\n colorK?: string;\n size?: number;\n contrast?: number;\n softness?: number;\n grainSize?: number;\n grainMixer?: number;\n grainOverlay?: number;\n gridNoise?: number;\n floodC?: number;\n floodM?: number;\n floodY?: number;\n floodK?: number;\n gainC?: number;\n gainM?: number;\n gainY?: number;\n gainK?: number;\n type?: HalftoneCmykType;\n}\n\nexport const HalftoneCmykTypes = {\n dots: 0,\n ink: 1,\n sharp: 2,\n} as const;\n\nexport type HalftoneCmykType = keyof typeof HalftoneCmykTypes;\n\n"], + "mappings": ";;;;;AACA,eAAmE;AACnE,SAAS,iBAAiB;AAmDnB,MAAM,6BAAqC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA4C/C,SAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA2RN,MAAM,oBAAoB;AAAA,EAC/B,MAAM;AAAA,EACN,KAAK;AAAA,EACL,OAAO;AACT;", + "names": [] +} diff --git a/public/vendor/paper-shaders/shaders/halftone-dots.d.ts b/public/vendor/paper-shaders/shaders/halftone-dots.d.ts new file mode 100644 index 0000000..24f6a95 --- /dev/null +++ b/public/vendor/paper-shaders/shaders/halftone-dots.d.ts @@ -0,0 +1,82 @@ +import type { ShaderMotionParams } from '../shader-mount.js'; +import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js'; +/** + * A halftone-dot image filter featuring customizable grids, color palettes, and dot styles. + * + * Fragment shader uniforms: + * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360) + * - u_time (float): Animation time + * - u_image (sampler2D): Source image texture + * - u_imageAspectRatio (float): Aspect ratio of the source image + * - u_colorFront (vec4): Foreground color in RGBA + * - u_colorBack (vec4): Background color in RGBA + * - u_originalColors (bool): Use sampled image's original colors instead of colorFront + * - u_type (float): Dot style (0 = classic, 1 = gooey, 2 = holes, 3 = soft) + * - u_inverted (bool): Inverts the image luminance, doesn't affect the color scheme; not effective at zero contrast + * - u_grid (float): Grid type (0 = square, 1 = hex) + * - u_size (float): Grid size relative to the image box (0 to 1) + * - u_radius (float): Maximum dot size relative to grid cell (0 to 2) + * - u_contrast (float): Contrast applied to the sampled image (0 to 1) + * - u_grainMixer (float): Strength of grain distortion applied to shape edges (0 to 1) + * - u_grainOverlay (float): Post-processing black/white grain overlay (0 to 1) + * - u_grainSize (float): Scale applied to both grain distortion and grain overlay (0 to 1) + * + * Vertex shader outputs (used in fragment shader): + * - v_imageUV (vec2): Image UV coordinates with global sizing (rotation, scale, offset, etc) applied + * + * Vertex shader uniforms: + * - u_resolution (vec2): Canvas resolution in pixels + * - u_pixelRatio (float): Device pixel ratio + * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1) + * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1) + * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover) + * - u_scale (float): Overall zoom level of the graphics (0.01 to 4) + * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360) + * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1) + * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1) + * - u_imageAspectRatio (float): Aspect ratio of the source image + * + */ +export declare const halftoneDotsFragmentShader: string; +export interface HalftoneDotsUniforms extends ShaderSizingUniforms { + u_image: HTMLImageElement | string | undefined; + u_colorFront: [number, number, number, number]; + u_colorBack: [number, number, number, number]; + u_size: number; + u_grid: (typeof HalftoneDotsGrids)[HalftoneDotsGrid]; + u_radius: number; + u_contrast: number; + u_originalColors: boolean; + u_inverted: boolean; + u_grainMixer: number; + u_grainOverlay: number; + u_grainSize: number; + u_type: (typeof HalftoneDotsTypes)[HalftoneDotsType]; +} +export interface HalftoneDotsParams extends ShaderSizingParams, ShaderMotionParams { + image?: HTMLImageElement | string; + colorFront?: string; + colorBack?: string; + size?: number; + grid?: HalftoneDotsGrid; + radius?: number; + contrast?: number; + originalColors?: boolean; + inverted?: boolean; + grainMixer?: number; + grainOverlay?: number; + grainSize?: number; + type?: HalftoneDotsType; +} +export declare const HalftoneDotsTypes: { + readonly classic: 0; + readonly gooey: 1; + readonly holes: 2; + readonly soft: 3; +}; +export type HalftoneDotsType = keyof typeof HalftoneDotsTypes; +export declare const HalftoneDotsGrids: { + readonly square: 0; + readonly hex: 1; +}; +export type HalftoneDotsGrid = keyof typeof HalftoneDotsGrids; diff --git a/public/vendor/paper-shaders/shaders/halftone-dots.js b/public/vendor/paper-shaders/shaders/halftone-dots.js new file mode 100644 index 0000000..ffdedcf --- /dev/null +++ b/public/vendor/paper-shaders/shaders/halftone-dots.js @@ -0,0 +1,321 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Paper Shaders * + * https://github.com/paper-design/shaders * + * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +import {} from "../shader-sizing.js"; +import { declarePI, rotation2, proceduralHash21 } from "../shader-utils.js"; +const halftoneDotsFragmentShader = `#version 300 es +precision mediump float; + +uniform float u_rotation; + +uniform float u_time; + +uniform vec4 u_colorFront; +uniform vec4 u_colorBack; +uniform float u_radius; +uniform float u_contrast; + +uniform sampler2D u_image; +uniform float u_imageAspectRatio; + +uniform float u_size; +uniform float u_grainMixer; +uniform float u_grainOverlay; +uniform float u_grainSize; +uniform float u_grid; +uniform bool u_originalColors; +uniform bool u_inverted; +uniform float u_type; + +in vec2 v_imageUV; + +out vec4 fragColor; + +${declarePI} +${rotation2} +${proceduralHash21} + +float valueNoise(vec2 st) { + vec2 i = floor(st); + vec2 f = fract(st); + float a = hash21(i); + float b = hash21(i + vec2(1.0, 0.0)); + float c = hash21(i + vec2(0.0, 1.0)); + float d = hash21(i + vec2(1.0, 1.0)); + vec2 u = f * f * (3.0 - 2.0 * f); + float x1 = mix(a, b, u.x); + float x2 = mix(c, d, u.x); + return mix(x1, x2, u.y); +} + +float lst(float edge0, float edge1, float x) { + return clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0); +} + +float sst(float edge0, float edge1, float x) { + return smoothstep(edge0, edge1, x); +} + +float getCircle(vec2 uv, float r, float baseR) { + r = mix(.25 * baseR, 0., r); + float d = length(uv - .5); + float aa = fwidth(d); + return 1. - smoothstep(r - aa, r + aa, d); +} + +float getCell(vec2 uv) { + float insideX = step(0.0, uv.x) * (1.0 - step(1.0, uv.x)); + float insideY = step(0.0, uv.y) * (1.0 - step(1.0, uv.y)); + return insideX * insideY; +} + +float getCircleWithHole(vec2 uv, float r, float baseR) { + float cell = getCell(uv); + + r = mix(.75 * baseR, 0., r); + float rMod = mod(r, .5); + + float d = length(uv - .5); + float aa = fwidth(d); + float circle = 1. - smoothstep(rMod - aa, rMod + aa, d); + if (r < .5) { + return circle; + } else { + return cell - circle; + } +} + +float getGooeyBall(vec2 uv, float r, float baseR) { + float d = length(uv - .5); + float sizeRadius = .3; + if (u_grid == 1.) { + sizeRadius = .42; + } + sizeRadius = mix(sizeRadius * baseR, 0., r); + d = 1. - sst(0., sizeRadius, d); + + d = pow(d, 2. + baseR); + return d; +} + +float getSoftBall(vec2 uv, float r, float baseR) { + float d = length(uv - .5); + float sizeRadius = clamp(baseR, 0., 1.); + sizeRadius = mix(.5 * sizeRadius, 0., r); + d = 1. - lst(0., sizeRadius, d); + float powRadius = 1. - lst(0., 2., baseR); + d = pow(d, 4. + 3. * powRadius); + return d; +} + +float getUvFrame(vec2 uv, vec2 pad) { + float aa = 0.0001; + + float left = smoothstep(-pad.x, -pad.x + aa, uv.x); + float right = smoothstep(1.0 + pad.x, 1.0 + pad.x - aa, uv.x); + float bottom = smoothstep(-pad.y, -pad.y + aa, uv.y); + float top = smoothstep(1.0 + pad.y, 1.0 + pad.y - aa, uv.y); + + return left * right * bottom * top; +} + +float sigmoid(float x, float k) { + return 1.0 / (1.0 + exp(-k * (x - 0.5))); +} + +float getLumAtPx(vec2 uv, float contrast) { + vec4 tex = texture(u_image, uv); + vec3 color = vec3( + sigmoid(tex.r, contrast), + sigmoid(tex.g, contrast), + sigmoid(tex.b, contrast) + ); + float lum = dot(vec3(0.2126, 0.7152, 0.0722), color); + lum = mix(1., lum, tex.a); + lum = u_inverted ? (1. - lum) : lum; + return lum; +} + +float getLumBall(vec2 p, vec2 pad, vec2 inCellOffset, float contrast, float baseR, float stepSize, out vec4 ballColor) { + p += inCellOffset; + vec2 uv_i = floor(p); + vec2 uv_f = fract(p); + vec2 samplingUV = (uv_i + .5 - inCellOffset) * pad + vec2(.5); + float outOfFrame = getUvFrame(samplingUV, pad * stepSize); + + float lum = getLumAtPx(samplingUV, contrast); + ballColor = texture(u_image, samplingUV); + ballColor.rgb *= ballColor.a; + ballColor *= outOfFrame; + + float ball = 0.; + if (u_type == 0.) { + // classic + ball = getCircle(uv_f, lum, baseR); + } else if (u_type == 1.) { + // gooey + ball = getGooeyBall(uv_f, lum, baseR); + } else if (u_type == 2.) { + // holes + ball = getCircleWithHole(uv_f, lum, baseR); + } else if (u_type == 3.) { + // soft + ball = getSoftBall(uv_f, lum, baseR); + } + + return ball * outOfFrame; +} + + +void main() { + + float stepMultiplier = 1.; + if (u_type == 0.) { + // classic + stepMultiplier = 2.; + } else if (u_type == 1. || u_type == 3.) { + // gooey & soft + stepMultiplier = 6.; + } + + float cellsPerSide = mix(300., 7., pow(u_size, .7)); + cellsPerSide /= stepMultiplier; + float cellSizeY = 1. / cellsPerSide; + vec2 pad = cellSizeY * vec2(1. / u_imageAspectRatio, 1.); + if (u_type == 1. && u_grid == 1.) { + // gooey diagonal grid works differently + pad *= .7; + } + + vec2 uv = v_imageUV; + uv -= vec2(.5); + uv /= pad; + + float contrast = mix(0., 15., pow(u_contrast, 1.5)); + float baseRadius = u_radius; + if (u_originalColors == true) { + contrast = mix(.1, 4., pow(u_contrast, 2.)); + baseRadius = 2. * pow(.5 * u_radius, .3); + } + + float totalShape = 0.; + vec3 totalColor = vec3(0.); + float totalOpacity = 0.; + + vec4 ballColor; + float shape; + float stepSize = 1. / stepMultiplier; + for (float x = -0.5; x < 0.5; x += stepSize) { + for (float y = -0.5; y < 0.5; y += stepSize) { + vec2 offset = vec2(x, y); + + if (u_grid == 1.) { + float rowIndex = floor((y + .5) / stepSize); + float colIndex = floor((x + .5) / stepSize); + if (stepSize == 1.) { + rowIndex = floor(uv.y + y + 1.); + if (u_type == 1.) { + colIndex = floor(uv.x + x + 1.); + } + } + if (u_type == 1.) { + if (mod(rowIndex + colIndex, 2.) == 1.) { + continue; + } + } else { + if (mod(rowIndex, 2.) == 1.) { + offset.x += .5 * stepSize; + } + } + } + + shape = getLumBall(uv, pad, offset, contrast, baseRadius, stepSize, ballColor); + totalColor += ballColor.rgb * shape; + totalShape += shape; + totalOpacity += shape; + } + } + + const float eps = 1e-4; + + totalColor /= max(totalShape, eps); + totalOpacity /= max(totalShape, eps); + + float finalShape = 0.; + if (u_type == 0.) { + finalShape = min(1., totalShape); + } else if (u_type == 1.) { + float aa = fwidth(totalShape); + float th = .5; + finalShape = smoothstep(th - aa, th + aa, totalShape); + } else if (u_type == 2.) { + finalShape = min(1., totalShape); + } else if (u_type == 3.) { + finalShape = totalShape; + } + + vec2 grainSize = mix(2000., 200., u_grainSize) * vec2(1., 1. / u_imageAspectRatio); + vec2 grainUV = v_imageUV - .5; + grainUV *= grainSize; + grainUV += .5; + float grain = valueNoise(grainUV); + grain = smoothstep(.55, .7 + .2 * u_grainMixer, grain); + grain *= u_grainMixer; + finalShape = mix(finalShape, 0., grain); + + vec3 color = vec3(0.); + float opacity = 0.; + + if (u_originalColors == true) { + color = totalColor * finalShape; + opacity = totalOpacity * finalShape; + + vec3 bgColor = u_colorBack.rgb * u_colorBack.a; + color = color + bgColor * (1. - opacity); + opacity = opacity + u_colorBack.a * (1. - opacity); + } else { + vec3 fgColor = u_colorFront.rgb * u_colorFront.a; + float fgOpacity = u_colorFront.a; + vec3 bgColor = u_colorBack.rgb * u_colorBack.a; + float bgOpacity = u_colorBack.a; + + color = fgColor * finalShape; + opacity = fgOpacity * finalShape; + color += bgColor * (1. - opacity); + opacity += bgOpacity * (1. - opacity); + } + + float grainOverlay = valueNoise(rotate(grainUV, 1.) + vec2(3.)); + grainOverlay = mix(grainOverlay, valueNoise(rotate(grainUV, 2.) + vec2(-1.)), .5); + grainOverlay = pow(grainOverlay, 1.3); + + float grainOverlayV = grainOverlay * 2. - 1.; + vec3 grainOverlayColor = vec3(step(0., grainOverlayV)); + float grainOverlayStrength = u_grainOverlay * abs(grainOverlayV); + grainOverlayStrength = pow(grainOverlayStrength, .8); + color = mix(color, grainOverlayColor, .5 * grainOverlayStrength); + + opacity += .5 * grainOverlayStrength; + opacity = clamp(opacity, 0., 1.); + + fragColor = vec4(color, opacity); +} +`; +const HalftoneDotsTypes = { + classic: 0, + gooey: 1, + holes: 2, + soft: 3 +}; +const HalftoneDotsGrids = { + square: 0, + hex: 1 +}; +export { + HalftoneDotsGrids, + HalftoneDotsTypes, + halftoneDotsFragmentShader +}; +//# sourceMappingURL=halftone-dots.js.map diff --git a/public/vendor/paper-shaders/shaders/halftone-dots.js.map b/public/vendor/paper-shaders/shaders/halftone-dots.js.map new file mode 100644 index 0000000..1d1a973 --- /dev/null +++ b/public/vendor/paper-shaders/shaders/halftone-dots.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../../src/shaders/halftone-dots.ts"], + "sourcesContent": ["import type { ShaderMotionParams } from '../shader-mount.js';\nimport { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { declarePI, rotation2, proceduralHash21 } from '../shader-utils.js';\n\n/**\n * A halftone-dot image filter featuring customizable grids, color palettes, and dot styles.\n *\n * Fragment shader uniforms:\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_time (float): Animation time\n * - u_image (sampler2D): Source image texture\n * - u_imageAspectRatio (float): Aspect ratio of the source image\n * - u_colorFront (vec4): Foreground color in RGBA\n * - u_colorBack (vec4): Background color in RGBA\n * - u_originalColors (bool): Use sampled image's original colors instead of colorFront\n * - u_type (float): Dot style (0 = classic, 1 = gooey, 2 = holes, 3 = soft)\n * - u_inverted (bool): Inverts the image luminance, doesn't affect the color scheme; not effective at zero contrast\n * - u_grid (float): Grid type (0 = square, 1 = hex)\n * - u_size (float): Grid size relative to the image box (0 to 1)\n * - u_radius (float): Maximum dot size relative to grid cell (0 to 2)\n * - u_contrast (float): Contrast applied to the sampled image (0 to 1)\n * - u_grainMixer (float): Strength of grain distortion applied to shape edges (0 to 1)\n * - u_grainOverlay (float): Post-processing black/white grain overlay (0 to 1)\n * - u_grainSize (float): Scale applied to both grain distortion and grain overlay (0 to 1)\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_imageUV (vec2): Image UV coordinates with global sizing (rotation, scale, offset, etc) applied\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n * - u_imageAspectRatio (float): Aspect ratio of the source image\n *\n */\n\n// language=GLSL\nexport const halftoneDotsFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform float u_rotation;\n\nuniform float u_time;\n\nuniform vec4 u_colorFront;\nuniform vec4 u_colorBack;\nuniform float u_radius;\nuniform float u_contrast;\n\nuniform sampler2D u_image;\nuniform float u_imageAspectRatio;\n\nuniform float u_size;\nuniform float u_grainMixer;\nuniform float u_grainOverlay;\nuniform float u_grainSize;\nuniform float u_grid;\nuniform bool u_originalColors;\nuniform bool u_inverted;\nuniform float u_type;\n\nin vec2 v_imageUV;\n\nout vec4 fragColor;\n\n${ declarePI }\n${ rotation2 }\n${ proceduralHash21 }\n\nfloat valueNoise(vec2 st) {\n vec2 i = floor(st);\n vec2 f = fract(st);\n float a = hash21(i);\n float b = hash21(i + vec2(1.0, 0.0));\n float c = hash21(i + vec2(0.0, 1.0));\n float d = hash21(i + vec2(1.0, 1.0));\n vec2 u = f * f * (3.0 - 2.0 * f);\n float x1 = mix(a, b, u.x);\n float x2 = mix(c, d, u.x);\n return mix(x1, x2, u.y);\n}\n\nfloat lst(float edge0, float edge1, float x) {\n return clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);\n}\n\nfloat sst(float edge0, float edge1, float x) {\n return smoothstep(edge0, edge1, x);\n}\n\nfloat getCircle(vec2 uv, float r, float baseR) {\n r = mix(.25 * baseR, 0., r);\n float d = length(uv - .5);\n float aa = fwidth(d);\n return 1. - smoothstep(r - aa, r + aa, d);\n}\n\nfloat getCell(vec2 uv) {\n float insideX = step(0.0, uv.x) * (1.0 - step(1.0, uv.x));\n float insideY = step(0.0, uv.y) * (1.0 - step(1.0, uv.y));\n return insideX * insideY;\n}\n\nfloat getCircleWithHole(vec2 uv, float r, float baseR) {\n float cell = getCell(uv);\n\n r = mix(.75 * baseR, 0., r);\n float rMod = mod(r, .5);\n\n float d = length(uv - .5);\n float aa = fwidth(d);\n float circle = 1. - smoothstep(rMod - aa, rMod + aa, d);\n if (r < .5) {\n return circle;\n } else {\n return cell - circle;\n }\n}\n\nfloat getGooeyBall(vec2 uv, float r, float baseR) {\n float d = length(uv - .5);\n float sizeRadius = .3;\n if (u_grid == 1.) {\n sizeRadius = .42;\n }\n sizeRadius = mix(sizeRadius * baseR, 0., r);\n d = 1. - sst(0., sizeRadius, d);\n\n d = pow(d, 2. + baseR);\n return d;\n}\n\nfloat getSoftBall(vec2 uv, float r, float baseR) {\n float d = length(uv - .5);\n float sizeRadius = clamp(baseR, 0., 1.);\n sizeRadius = mix(.5 * sizeRadius, 0., r);\n d = 1. - lst(0., sizeRadius, d);\n float powRadius = 1. - lst(0., 2., baseR);\n d = pow(d, 4. + 3. * powRadius);\n return d;\n}\n\nfloat getUvFrame(vec2 uv, vec2 pad) {\n float aa = 0.0001;\n\n float left = smoothstep(-pad.x, -pad.x + aa, uv.x);\n float right = smoothstep(1.0 + pad.x, 1.0 + pad.x - aa, uv.x);\n float bottom = smoothstep(-pad.y, -pad.y + aa, uv.y);\n float top = smoothstep(1.0 + pad.y, 1.0 + pad.y - aa, uv.y);\n\n return left * right * bottom * top;\n}\n\nfloat sigmoid(float x, float k) {\n return 1.0 / (1.0 + exp(-k * (x - 0.5)));\n}\n\nfloat getLumAtPx(vec2 uv, float contrast) {\n vec4 tex = texture(u_image, uv);\n vec3 color = vec3(\n sigmoid(tex.r, contrast),\n sigmoid(tex.g, contrast),\n sigmoid(tex.b, contrast)\n );\n float lum = dot(vec3(0.2126, 0.7152, 0.0722), color);\n lum = mix(1., lum, tex.a);\n lum = u_inverted ? (1. - lum) : lum;\n return lum;\n}\n\nfloat getLumBall(vec2 p, vec2 pad, vec2 inCellOffset, float contrast, float baseR, float stepSize, out vec4 ballColor) {\n p += inCellOffset;\n vec2 uv_i = floor(p);\n vec2 uv_f = fract(p);\n vec2 samplingUV = (uv_i + .5 - inCellOffset) * pad + vec2(.5);\n float outOfFrame = getUvFrame(samplingUV, pad * stepSize);\n\n float lum = getLumAtPx(samplingUV, contrast);\n ballColor = texture(u_image, samplingUV);\n ballColor.rgb *= ballColor.a;\n ballColor *= outOfFrame;\n\n float ball = 0.;\n if (u_type == 0.) {\n // classic\n ball = getCircle(uv_f, lum, baseR);\n } else if (u_type == 1.) {\n // gooey\n ball = getGooeyBall(uv_f, lum, baseR);\n } else if (u_type == 2.) {\n // holes\n ball = getCircleWithHole(uv_f, lum, baseR);\n } else if (u_type == 3.) {\n // soft\n ball = getSoftBall(uv_f, lum, baseR);\n }\n\n return ball * outOfFrame;\n}\n\n\nvoid main() {\n\n float stepMultiplier = 1.;\n if (u_type == 0.) {\n // classic\n stepMultiplier = 2.;\n } else if (u_type == 1. || u_type == 3.) {\n // gooey & soft\n stepMultiplier = 6.;\n }\n\n float cellsPerSide = mix(300., 7., pow(u_size, .7));\n cellsPerSide /= stepMultiplier;\n float cellSizeY = 1. / cellsPerSide;\n vec2 pad = cellSizeY * vec2(1. / u_imageAspectRatio, 1.);\n if (u_type == 1. && u_grid == 1.) {\n // gooey diagonal grid works differently\n pad *= .7;\n }\n\n vec2 uv = v_imageUV;\n uv -= vec2(.5);\n uv /= pad;\n\n float contrast = mix(0., 15., pow(u_contrast, 1.5));\n float baseRadius = u_radius;\n if (u_originalColors == true) {\n contrast = mix(.1, 4., pow(u_contrast, 2.));\n baseRadius = 2. * pow(.5 * u_radius, .3);\n }\n\n float totalShape = 0.;\n vec3 totalColor = vec3(0.);\n float totalOpacity = 0.;\n\n vec4 ballColor;\n float shape;\n float stepSize = 1. / stepMultiplier;\n for (float x = -0.5; x < 0.5; x += stepSize) {\n for (float y = -0.5; y < 0.5; y += stepSize) {\n vec2 offset = vec2(x, y);\n\n if (u_grid == 1.) {\n float rowIndex = floor((y + .5) / stepSize);\n float colIndex = floor((x + .5) / stepSize);\n if (stepSize == 1.) {\n rowIndex = floor(uv.y + y + 1.);\n if (u_type == 1.) {\n colIndex = floor(uv.x + x + 1.);\n }\n }\n if (u_type == 1.) {\n if (mod(rowIndex + colIndex, 2.) == 1.) {\n continue;\n }\n } else {\n if (mod(rowIndex, 2.) == 1.) {\n offset.x += .5 * stepSize;\n }\n }\n }\n\n shape = getLumBall(uv, pad, offset, contrast, baseRadius, stepSize, ballColor);\n totalColor += ballColor.rgb * shape;\n totalShape += shape;\n totalOpacity += shape;\n }\n }\n\n const float eps = 1e-4;\n\n totalColor /= max(totalShape, eps);\n totalOpacity /= max(totalShape, eps);\n\n float finalShape = 0.;\n if (u_type == 0.) {\n finalShape = min(1., totalShape);\n } else if (u_type == 1.) {\n float aa = fwidth(totalShape);\n float th = .5;\n finalShape = smoothstep(th - aa, th + aa, totalShape);\n } else if (u_type == 2.) {\n finalShape = min(1., totalShape);\n } else if (u_type == 3.) {\n finalShape = totalShape;\n }\n\n vec2 grainSize = mix(2000., 200., u_grainSize) * vec2(1., 1. / u_imageAspectRatio);\n vec2 grainUV = v_imageUV - .5;\n grainUV *= grainSize;\n grainUV += .5;\n float grain = valueNoise(grainUV);\n grain = smoothstep(.55, .7 + .2 * u_grainMixer, grain);\n grain *= u_grainMixer;\n finalShape = mix(finalShape, 0., grain);\n\n vec3 color = vec3(0.);\n float opacity = 0.;\n\n if (u_originalColors == true) {\n color = totalColor * finalShape;\n opacity = totalOpacity * finalShape;\n\n vec3 bgColor = u_colorBack.rgb * u_colorBack.a;\n color = color + bgColor * (1. - opacity);\n opacity = opacity + u_colorBack.a * (1. - opacity);\n } else {\n vec3 fgColor = u_colorFront.rgb * u_colorFront.a;\n float fgOpacity = u_colorFront.a;\n vec3 bgColor = u_colorBack.rgb * u_colorBack.a;\n float bgOpacity = u_colorBack.a;\n\n color = fgColor * finalShape;\n opacity = fgOpacity * finalShape;\n color += bgColor * (1. - opacity);\n opacity += bgOpacity * (1. - opacity);\n }\n\n float grainOverlay = valueNoise(rotate(grainUV, 1.) + vec2(3.));\n grainOverlay = mix(grainOverlay, valueNoise(rotate(grainUV, 2.) + vec2(-1.)), .5);\n grainOverlay = pow(grainOverlay, 1.3);\n\n float grainOverlayV = grainOverlay * 2. - 1.;\n vec3 grainOverlayColor = vec3(step(0., grainOverlayV));\n float grainOverlayStrength = u_grainOverlay * abs(grainOverlayV);\n grainOverlayStrength = pow(grainOverlayStrength, .8);\n color = mix(color, grainOverlayColor, .5 * grainOverlayStrength);\n\n opacity += .5 * grainOverlayStrength;\n opacity = clamp(opacity, 0., 1.);\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface HalftoneDotsUniforms extends ShaderSizingUniforms {\n u_image: HTMLImageElement | string | undefined;\n u_colorFront: [number, number, number, number];\n u_colorBack: [number, number, number, number];\n u_size: number;\n u_grid: (typeof HalftoneDotsGrids)[HalftoneDotsGrid];\n u_radius: number;\n u_contrast: number;\n u_originalColors: boolean;\n u_inverted: boolean;\n u_grainMixer: number;\n u_grainOverlay: number;\n u_grainSize: number;\n u_type: (typeof HalftoneDotsTypes)[HalftoneDotsType];\n}\n\nexport interface HalftoneDotsParams extends ShaderSizingParams, ShaderMotionParams {\n image?: HTMLImageElement | string;\n colorFront?: string;\n colorBack?: string;\n size?: number;\n grid?: HalftoneDotsGrid;\n radius?: number;\n contrast?: number;\n originalColors?: boolean;\n inverted?: boolean;\n grainMixer?: number;\n grainOverlay?: number;\n grainSize?: number;\n type?: HalftoneDotsType;\n}\n\nexport const HalftoneDotsTypes = {\n classic: 0,\n gooey: 1,\n holes: 2,\n soft: 3,\n} as const;\n\nexport type HalftoneDotsType = keyof typeof HalftoneDotsTypes;\n\nexport const HalftoneDotsGrids = {\n square: 0,\n hex: 1,\n} as const;\n\nexport type HalftoneDotsGrid = keyof typeof HalftoneDotsGrids;\n"], + "mappings": ";;;;;AACA,eAAmE;AACnE,SAAS,WAAW,WAAW,wBAAwB;AAyChD,MAAM,6BAAqC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA4B/C,SAAU;AAAA,EACV,SAAU;AAAA,EACV,gBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA6Sb,MAAM,oBAAoB;AAAA,EAC/B,SAAS;AAAA,EACT,OAAO;AAAA,EACP,OAAO;AAAA,EACP,MAAM;AACR;AAIO,MAAM,oBAAoB;AAAA,EAC/B,QAAQ;AAAA,EACR,KAAK;AACP;", + "names": [] +} diff --git a/public/vendor/paper-shaders/shaders/heatmap.d.ts b/public/vendor/paper-shaders/shaders/heatmap.d.ts new file mode 100644 index 0000000..0e8b624 --- /dev/null +++ b/public/vendor/paper-shaders/shaders/heatmap.d.ts @@ -0,0 +1,67 @@ +import type { vec4 } from '../types.js'; +import type { ShaderMotionParams } from '../shader-mount.js'; +import type { ShaderSizingParams, ShaderSizingUniforms } from '../shader-sizing.js'; +export declare const heatmapMeta: { + readonly maxColorCount: 10; +}; +/** + * A glowing gradient of colors flowing through an input shape. + * The effect creates a smoothly animated wave of intensity across the image. + * + * Fragment shader uniforms: + * - u_time (float): Animation time + * - u_image (sampler2D): Pre-processed source image texture (R = contour, G = outer blur, B = inner blur) + * - u_imageAspectRatio (float): Aspect ratio of the source image + * - u_colorBack (vec4): Background color in RGBA + * - u_colors (vec4[]): Up to 10 heatmap colors in RGBA + * - u_colorsCount (float): Number of active colors + * - u_contour (float): Heat intensity near the edges of the input shape (0 to 1) + * - u_angle (float): Direction of the heatwaves in degrees (0 to 360) + * - u_noise (float): Grain applied across the entire graphic (0 to 1) + * - u_innerGlow (float): Size of the heated area inside the input shape (0 to 1) + * - u_outerGlow (float): Size of the heated area outside the input shape (0 to 1) + * + * Vertex shader outputs (used in fragment shader): + * - v_imageUV (vec2): UV coordinates for sampling the source image, with fit, scale, rotation, and offset applied + * - v_objectUV (vec2): Object box UV coordinates with global sizing (scale, rotation, offsets, etc) applied + * + * Vertex shader uniforms: + * - u_resolution (vec2): Canvas resolution in pixels + * - u_pixelRatio (float): Device pixel ratio + * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1) + * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1) + * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas + * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas + * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover) + * - u_scale (float): Overall zoom level of the graphics (0.01 to 4) + * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360) + * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1) + * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1) + * - u_imageAspectRatio (float): Aspect ratio of the source image + * + */ +export declare const heatmapFragmentShader: string; +export declare function toProcessedHeatmap(file: File | string): Promise<{ + blob: Blob; +}>; +export interface HeatmapUniforms extends ShaderSizingUniforms { + u_image: HTMLImageElement | string; + u_contour: number; + u_angle: number; + u_noise: number; + u_innerGlow: number; + u_outerGlow: number; + u_colorBack: [number, number, number, number]; + u_colors: vec4[]; + u_colorsCount: number; +} +export interface HeatmapParams extends ShaderSizingParams, ShaderMotionParams { + image: HTMLImageElement | string; + contour?: number; + angle?: number; + noise?: number; + innerGlow?: number; + outerGlow?: number; + colorBack?: string; + colors?: string[]; +} diff --git a/public/vendor/paper-shaders/shaders/heatmap.js b/public/vendor/paper-shaders/shaders/heatmap.js new file mode 100644 index 0000000..2e2441b --- /dev/null +++ b/public/vendor/paper-shaders/shaders/heatmap.js @@ -0,0 +1,385 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Paper Shaders * + * https://github.com/paper-design/shaders * + * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +const heatmapMeta = { + maxColorCount: 10 +}; +const heatmapFragmentShader = `#version 300 es +precision highp float; + +in mediump vec2 v_imageUV; +in mediump vec2 v_objectUV; +out vec4 fragColor; + +uniform sampler2D u_image; +uniform float u_time; +uniform mediump float u_imageAspectRatio; + +uniform vec4 u_colorBack; +uniform vec4 u_colors[${heatmapMeta.maxColorCount}]; +uniform float u_colorsCount; + +uniform float u_angle; +uniform float u_noise; +uniform float u_innerGlow; +uniform float u_outerGlow; +uniform float u_contour; + +#define TWO_PI 6.28318530718 +#define PI 3.14159265358979323846 + +float getImgFrame(vec2 uv, float th) { + float frame = 1.; + frame *= smoothstep(0., th, uv.y); + frame *= 1. - smoothstep(1. - th, 1., uv.y); + frame *= smoothstep(0., th, uv.x); + frame *= 1. - smoothstep(1. - th, 1., uv.x); + return frame; +} + +float circle(vec2 uv, vec2 c, vec2 r) { + return 1. - smoothstep(r[0], r[1], length(uv - c)); +} + +float lst(float edge0, float edge1, float x) { + return clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0); +} + +float sst(float edge0, float edge1, float x) { + return smoothstep(edge0, edge1, x); +} + +float shadowShape(vec2 uv, float t, float contour) { + vec2 scaledUV = uv; + + // base shape tranjectory + float posY = mix(-1., 2., t); + + // scaleX when it's moving down + scaledUV.y -= .5; + float mainCircleScale = sst(0., .8, posY) * lst(1.4, .9, posY); + scaledUV *= vec2(1., 1. + 1.5 * mainCircleScale); + scaledUV.y += .5; + + // base shape + float innerR = .4; + float outerR = 1. - .3 * (sst(.1, .2, t) * (1. - sst(.2, .5, t))); + float s = circle(scaledUV, vec2(.5, posY - .2), vec2(innerR, outerR)); + float shapeSizing = sst(.2, .3, t) * sst(.6, .3, t); + s = pow(s, 1.4); + s *= 1.2; + + // flat gradient to take over the shadow shape + float topFlattener = 0.; + { + float pos = posY - uv.y; + float edge = 1.2; + topFlattener = lst(-.4, 0., pos) * (1. - sst(.0, edge, pos)); + topFlattener = pow(topFlattener, 3.); + float topFlattenerMixer = (1. - sst(.0, .3, pos)); + s = mix(topFlattener, s, topFlattenerMixer); + } + + // apple right circle + { + float visibility = sst(.6, .7, t) * (1. - sst(.8, .9, t)); + float angle = -2. -t * TWO_PI; + float rightCircle = circle(uv, vec2(.95 - .2 * cos(angle), .4 - .1 * sin(angle)), vec2(.15, .3)); + rightCircle *= visibility; + s = mix(s, 0., rightCircle); + } + + // apple top circle + { + float topCircle = circle(uv, vec2(.5, .19), vec2(.05, .25)); + topCircle += 2. * contour * circle(uv, vec2(.5, .19), vec2(.2, .5)); + float visibility = .55 * sst(.2, .3, t) * (1. - sst(.3, .45, t)); + topCircle *= visibility; + s = mix(s, 0., topCircle); + } + + float leafMask = circle(uv, vec2(.53, .13), vec2(.08, .19)); + leafMask = mix(leafMask, 0., 1. - sst(.4, .54, uv.x)); + leafMask = mix(0., leafMask, sst(.0, .2, uv.y)); + leafMask *= (sst(.5, 1.1, posY) * sst(1.5, 1.3, posY)); + s += leafMask; + + // apple bottom circle + { + float visibility = sst(.0, .4, t) * (1. - sst(.6, .8, t)); + s = mix(s, 0., visibility * circle(uv, vec2(.52, .92), vec2(.09, .25))); + } + + // random balls that are invisible if apple logo is selected + { + float pos = sst(.0, .6, t) * (1. - sst(.6, 1., t)); + s = mix(s, .5, circle(uv, vec2(.0, 1.2 - .5 * pos), vec2(.1, .3))); + s = mix(s, .0, circle(uv, vec2(1., .5 + .5 * pos), vec2(.1, .3))); + + s = mix(s, 1., circle(uv, vec2(.95, .2 + .2 * sst(.3, .4, t) * sst(.7, .5, t)), vec2(.07, .22))); + s = mix(s, 1., circle(uv, vec2(.95, .2 + .2 * sst(.3, .4, t) * (1. - sst(.5, .7, t))), vec2(.07, .22))); + s /= max(1e-4, sst(1., .85, uv.y)); + } + + s = clamp(0., 1., s); + return s; +} + +float blurEdge3x3(sampler2D tex, vec2 uv, vec2 dudx, vec2 dudy, float radius, float centerSample) { + vec2 texel = 1.0 / vec2(textureSize(tex, 0)); + vec2 r = radius * texel; + + float w1 = 1.0, w2 = 2.0, w4 = 4.0; + float norm = 16.0; + float sum = w4 * centerSample; + + sum += w2 * textureGrad(tex, uv + vec2(0.0, -r.y), dudx, dudy).g; + sum += w2 * textureGrad(tex, uv + vec2(0.0, r.y), dudx, dudy).g; + sum += w2 * textureGrad(tex, uv + vec2(-r.x, 0.0), dudx, dudy).g; + sum += w2 * textureGrad(tex, uv + vec2(r.x, 0.0), dudx, dudy).g; + + sum += w1 * textureGrad(tex, uv + vec2(-r.x, -r.y), dudx, dudy).g; + sum += w1 * textureGrad(tex, uv + vec2(r.x, -r.y), dudx, dudy).g; + sum += w1 * textureGrad(tex, uv + vec2(-r.x, r.y), dudx, dudy).g; + sum += w1 * textureGrad(tex, uv + vec2(r.x, r.y), dudx, dudy).g; + + return sum / norm; +} + +void main() { + vec2 uv = v_objectUV + .5; + uv.y = 1. - uv.y; + + vec2 imgUV = v_imageUV; + imgUV -= .5; + imgUV *= 0.5714285714285714; + imgUV += .5; + float imgSoftFrame = getImgFrame(imgUV, .03); + + vec4 img = texture(u_image, imgUV); + vec2 dudx = dFdx(imgUV); + vec2 dudy = dFdy(imgUV); + + if (img.a == 0.) { + fragColor = u_colorBack; + return; + } + + float t = .1 * u_time; + t -= .3; + + float tCopy = t + 1. / 3.; + float tCopy2 = t + 2. / 3.; + + t = mod(t, 1.); + tCopy = mod(tCopy, 1.); + tCopy2 = mod(tCopy2, 1.); + + vec2 animationUV = imgUV - vec2(.5); + float angle = -u_angle * PI / 180.; + float cosA = cos(angle); + float sinA = sin(angle); + animationUV = vec2( + animationUV.x * cosA - animationUV.y * sinA, + animationUV.x * sinA + animationUV.y * cosA + ) + vec2(.5); + + float shape = img[0]; + + img[1] = blurEdge3x3(u_image, imgUV, dudx, dudy, 8., img[1]); + + float outerBlur = 1. - mix(1., img[1], shape); + float innerBlur = mix(img[1], 0., shape); + float contour = mix(img[2], 0., shape); + + outerBlur *= imgSoftFrame; + + float shadow = shadowShape(animationUV, t, innerBlur); + float shadowCopy = shadowShape(animationUV, tCopy, innerBlur); + float shadowCopy2 = shadowShape(animationUV, tCopy2, innerBlur); + + float inner = .8 + .8 * innerBlur; + inner = mix(inner, 0., shadow); + inner = mix(inner, 0., shadowCopy); + inner = mix(inner, 0., shadowCopy2); + + inner *= mix(0., 2., u_innerGlow); + + inner += (u_contour * 2.) * contour; + inner = min(1., inner); + inner *= (1. - shape); + + float outer = 0.; + { + t *= 3.; + t = mod(t - .1, 1.); + + outer = .9 * pow(outerBlur, .8); + float y = mod(animationUV.y - t, 1.); + float animatedMask = sst(.3, .65, y) * (1. - sst(.65, 1., y)); + animatedMask = .5 + animatedMask; + outer *= animatedMask; + outer *= mix(0., 5., pow(u_outerGlow, 2.)); + outer *= imgSoftFrame; + } + + inner = pow(inner, 1.2); + float heat = clamp(inner + outer, 0., 1.); + + heat += (.005 + .35 * u_noise) * (fract(sin(dot(uv, vec2(12.9898, 78.233))) * 43758.5453123) - .5); + + float mixer = heat * u_colorsCount; + vec4 gradient = u_colors[0]; + gradient.rgb *= gradient.a; + float outerShape = 0.; + for (int i = 1; i < ${heatmapMeta.maxColorCount + 1}; i++) { + if (i > int(u_colorsCount)) break; + float m = clamp(mixer - float(i - 1), 0., 1.); + if (i == 1) { + outerShape = m; + } + vec4 c = u_colors[i - 1]; + c.rgb *= c.a; + gradient = mix(gradient, c, m); + } + + vec3 color = gradient.rgb * outerShape; + float opacity = gradient.a * outerShape; + + vec3 bgColor = u_colorBack.rgb * u_colorBack.a; + color = color + bgColor * (1.0 - opacity); + opacity = opacity + u_colorBack.a * (1.0 - opacity); + + color += .02 * (fract(sin(dot(uv + 1., vec2(12.9898, 78.233))) * 43758.5453123) - .5); + + fragColor = vec4(color, opacity); +} +`; +function toProcessedHeatmap(file) { + const canvas = document.createElement("canvas"); + const canvasSize = 1e3; + return new Promise((resolve, reject) => { + const image = new Image(); + image.crossOrigin = "anonymous"; + image.addEventListener("load", () => { + if (typeof file === "string" ? file.endsWith(".svg") : file.type === "image/svg+xml") { + image.width = canvasSize; + image.height = canvasSize; + } + const ratio = image.naturalWidth / image.naturalHeight; + const maxBlur = Math.floor(canvasSize * 0.15); + const padding = Math.ceil(maxBlur * 2.5); + let imgWidth = canvasSize; + let imgHeight = canvasSize; + if (ratio > 1) { + imgHeight = Math.floor(canvasSize / ratio); + } else { + imgWidth = Math.floor(canvasSize * ratio); + } + canvas.width = imgWidth + 2 * padding; + canvas.height = imgHeight + 2 * padding; + const ctx = canvas.getContext("2d", { willReadFrequently: true }); + if (!ctx) { + throw new Error("Failed to get canvas 2d context"); + } + ctx.fillStyle = "white"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + ctx.drawImage(image, padding, padding, imgWidth, imgHeight); + const { width, height } = canvas; + const srcImageData = ctx.getImageData(0, 0, width, height); + const src = srcImageData.data; + const totalPixels = width * height; + const gray = new Uint8ClampedArray(totalPixels); + for (let i = 0; i < totalPixels; i++) { + const px = i * 4; + const r = src[px] ?? 0; + const g = src[px + 1] ?? 0; + const b = src[px + 2] ?? 0; + gray[i] = 0.299 * r + 0.587 * g + 0.114 * b | 0; + } + const bigBlurRadius = maxBlur; + const innerBlurRadius = Math.max(1, Math.round(0.12 * maxBlur)); + const contourRadius = 5; + const bigBlurGray = multiPassBlurGray(gray, width, height, bigBlurRadius, 3); + const innerBlurGray = multiPassBlurGray(gray, width, height, innerBlurRadius, 3); + const contourGray = multiPassBlurGray(gray, width, height, contourRadius, 1); + const processedImageData = ctx.createImageData(width, height); + const dst = processedImageData.data; + for (let i = 0; i < totalPixels; i++) { + const px = i * 4; + dst[px] = contourGray[i] ?? 0; + dst[px + 1] = bigBlurGray[i] ?? 0; + dst[px + 2] = innerBlurGray[i] ?? 0; + dst[px + 3] = 255; + } + ctx.putImageData(processedImageData, 0, 0); + canvas.toBlob((blob) => { + if (!blob) { + reject(new Error("Failed to create PNG blob")); + return; + } + resolve({ blob }); + }, "image/png"); + }); + image.addEventListener("error", () => { + reject(new Error("Failed to load image")); + }); + image.src = typeof file === "string" ? file : URL.createObjectURL(file); + }); +} +function blurGray(gray, width, height, radius) { + if (radius <= 0) { + return gray.slice(); + } + const out = new Uint8ClampedArray(width * height); + const integral = new Uint32Array(width * height); + for (let y = 0; y < height; y++) { + let rowSum = 0; + for (let x = 0; x < width; x++) { + const idx = y * width + x; + const v = gray[idx] ?? 0; + rowSum += v; + integral[idx] = rowSum + (y > 0 ? integral[idx - width] ?? 0 : 0); + } + } + for (let y = 0; y < height; y++) { + const y1 = Math.max(0, y - radius); + const y2 = Math.min(height - 1, y + radius); + for (let x = 0; x < width; x++) { + const x1 = Math.max(0, x - radius); + const x2 = Math.min(width - 1, x + radius); + const idxA = y2 * width + x2; + const idxB = y2 * width + (x1 - 1); + const idxC = (y1 - 1) * width + x2; + const idxD = (y1 - 1) * width + (x1 - 1); + const A = integral[idxA] ?? 0; + const B = x1 > 0 ? integral[idxB] ?? 0 : 0; + const C = y1 > 0 ? integral[idxC] ?? 0 : 0; + const D = x1 > 0 && y1 > 0 ? integral[idxD] ?? 0 : 0; + const sum = A - B - C + D; + const area = (x2 - x1 + 1) * (y2 - y1 + 1); + out[y * width + x] = Math.round(sum / area); + } + } + return out; +} +function multiPassBlurGray(gray, width, height, radius, passes) { + if (radius <= 0 || passes <= 1) { + return blurGray(gray, width, height, radius); + } + let input = gray; + let tmp = gray; + for (let p = 0; p < passes; p++) { + tmp = blurGray(input, width, height, radius); + input = tmp; + } + return tmp; +} +export { + heatmapFragmentShader, + heatmapMeta, + toProcessedHeatmap +}; +//# sourceMappingURL=heatmap.js.map diff --git a/public/vendor/paper-shaders/shaders/heatmap.js.map b/public/vendor/paper-shaders/shaders/heatmap.js.map new file mode 100644 index 0000000..36f6d7a --- /dev/null +++ b/public/vendor/paper-shaders/shaders/heatmap.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../../src/shaders/heatmap.ts"], + "sourcesContent": ["import type { vec4 } from '../types.js';\nimport type { ShaderMotionParams } from '../shader-mount.js';\nimport type { ShaderSizingParams, ShaderSizingUniforms } from '../shader-sizing.js';\n\nexport const heatmapMeta = {\n maxColorCount: 10,\n} as const;\n\n/**\n * A glowing gradient of colors flowing through an input shape.\n * The effect creates a smoothly animated wave of intensity across the image.\n *\n * Fragment shader uniforms:\n * - u_time (float): Animation time\n * - u_image (sampler2D): Pre-processed source image texture (R = contour, G = outer blur, B = inner blur)\n * - u_imageAspectRatio (float): Aspect ratio of the source image\n * - u_colorBack (vec4): Background color in RGBA\n * - u_colors (vec4[]): Up to 10 heatmap colors in RGBA\n * - u_colorsCount (float): Number of active colors\n * - u_contour (float): Heat intensity near the edges of the input shape (0 to 1)\n * - u_angle (float): Direction of the heatwaves in degrees (0 to 360)\n * - u_noise (float): Grain applied across the entire graphic (0 to 1)\n * - u_innerGlow (float): Size of the heated area inside the input shape (0 to 1)\n * - u_outerGlow (float): Size of the heated area outside the input shape (0 to 1)\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_imageUV (vec2): UV coordinates for sampling the source image, with fit, scale, rotation, and offset applied\n * - v_objectUV (vec2): Object box UV coordinates with global sizing (scale, rotation, offsets, etc) applied\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n * - u_imageAspectRatio (float): Aspect ratio of the source image\n *\n */\n\n// language=GLSL\nexport const heatmapFragmentShader: string = `#version 300 es\nprecision highp float;\n\nin mediump vec2 v_imageUV;\nin mediump vec2 v_objectUV;\nout vec4 fragColor;\n\nuniform sampler2D u_image;\nuniform float u_time;\nuniform mediump float u_imageAspectRatio;\n\nuniform vec4 u_colorBack;\nuniform vec4 u_colors[${ heatmapMeta.maxColorCount }];\nuniform float u_colorsCount;\n\nuniform float u_angle;\nuniform float u_noise;\nuniform float u_innerGlow;\nuniform float u_outerGlow;\nuniform float u_contour;\n\n#define TWO_PI 6.28318530718\n#define PI 3.14159265358979323846\n\nfloat getImgFrame(vec2 uv, float th) {\n float frame = 1.;\n frame *= smoothstep(0., th, uv.y);\n frame *= 1. - smoothstep(1. - th, 1., uv.y);\n frame *= smoothstep(0., th, uv.x);\n frame *= 1. - smoothstep(1. - th, 1., uv.x);\n return frame;\n}\n\nfloat circle(vec2 uv, vec2 c, vec2 r) {\n return 1. - smoothstep(r[0], r[1], length(uv - c));\n}\n\nfloat lst(float edge0, float edge1, float x) {\n return clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);\n}\n\nfloat sst(float edge0, float edge1, float x) {\n return smoothstep(edge0, edge1, x);\n}\n\nfloat shadowShape(vec2 uv, float t, float contour) {\n vec2 scaledUV = uv;\n\n // base shape tranjectory\n float posY = mix(-1., 2., t);\n\n // scaleX when it's moving down\n scaledUV.y -= .5;\n float mainCircleScale = sst(0., .8, posY) * lst(1.4, .9, posY);\n scaledUV *= vec2(1., 1. + 1.5 * mainCircleScale);\n scaledUV.y += .5;\n\n // base shape\n float innerR = .4;\n float outerR = 1. - .3 * (sst(.1, .2, t) * (1. - sst(.2, .5, t)));\n float s = circle(scaledUV, vec2(.5, posY - .2), vec2(innerR, outerR));\n float shapeSizing = sst(.2, .3, t) * sst(.6, .3, t);\n s = pow(s, 1.4);\n s *= 1.2;\n\n // flat gradient to take over the shadow shape\n float topFlattener = 0.;\n {\n float pos = posY - uv.y;\n float edge = 1.2;\n topFlattener = lst(-.4, 0., pos) * (1. - sst(.0, edge, pos));\n topFlattener = pow(topFlattener, 3.);\n float topFlattenerMixer = (1. - sst(.0, .3, pos));\n s = mix(topFlattener, s, topFlattenerMixer);\n }\n\n // apple right circle\n {\n float visibility = sst(.6, .7, t) * (1. - sst(.8, .9, t));\n float angle = -2. -t * TWO_PI;\n float rightCircle = circle(uv, vec2(.95 - .2 * cos(angle), .4 - .1 * sin(angle)), vec2(.15, .3));\n rightCircle *= visibility;\n s = mix(s, 0., rightCircle);\n }\n\n // apple top circle\n {\n float topCircle = circle(uv, vec2(.5, .19), vec2(.05, .25));\n topCircle += 2. * contour * circle(uv, vec2(.5, .19), vec2(.2, .5));\n float visibility = .55 * sst(.2, .3, t) * (1. - sst(.3, .45, t));\n topCircle *= visibility;\n s = mix(s, 0., topCircle);\n }\n\n float leafMask = circle(uv, vec2(.53, .13), vec2(.08, .19));\n leafMask = mix(leafMask, 0., 1. - sst(.4, .54, uv.x));\n leafMask = mix(0., leafMask, sst(.0, .2, uv.y));\n leafMask *= (sst(.5, 1.1, posY) * sst(1.5, 1.3, posY));\n s += leafMask;\n\n // apple bottom circle\n {\n float visibility = sst(.0, .4, t) * (1. - sst(.6, .8, t));\n s = mix(s, 0., visibility * circle(uv, vec2(.52, .92), vec2(.09, .25)));\n }\n\n // random balls that are invisible if apple logo is selected\n {\n float pos = sst(.0, .6, t) * (1. - sst(.6, 1., t));\n s = mix(s, .5, circle(uv, vec2(.0, 1.2 - .5 * pos), vec2(.1, .3)));\n s = mix(s, .0, circle(uv, vec2(1., .5 + .5 * pos), vec2(.1, .3)));\n\n s = mix(s, 1., circle(uv, vec2(.95, .2 + .2 * sst(.3, .4, t) * sst(.7, .5, t)), vec2(.07, .22)));\n s = mix(s, 1., circle(uv, vec2(.95, .2 + .2 * sst(.3, .4, t) * (1. - sst(.5, .7, t))), vec2(.07, .22)));\n s /= max(1e-4, sst(1., .85, uv.y));\n }\n\n s = clamp(0., 1., s);\n return s;\n}\n\nfloat blurEdge3x3(sampler2D tex, vec2 uv, vec2 dudx, vec2 dudy, float radius, float centerSample) {\n vec2 texel = 1.0 / vec2(textureSize(tex, 0));\n vec2 r = radius * texel;\n\n float w1 = 1.0, w2 = 2.0, w4 = 4.0;\n float norm = 16.0;\n float sum = w4 * centerSample;\n\n sum += w2 * textureGrad(tex, uv + vec2(0.0, -r.y), dudx, dudy).g;\n sum += w2 * textureGrad(tex, uv + vec2(0.0, r.y), dudx, dudy).g;\n sum += w2 * textureGrad(tex, uv + vec2(-r.x, 0.0), dudx, dudy).g;\n sum += w2 * textureGrad(tex, uv + vec2(r.x, 0.0), dudx, dudy).g;\n\n sum += w1 * textureGrad(tex, uv + vec2(-r.x, -r.y), dudx, dudy).g;\n sum += w1 * textureGrad(tex, uv + vec2(r.x, -r.y), dudx, dudy).g;\n sum += w1 * textureGrad(tex, uv + vec2(-r.x, r.y), dudx, dudy).g;\n sum += w1 * textureGrad(tex, uv + vec2(r.x, r.y), dudx, dudy).g;\n\n return sum / norm;\n}\n\nvoid main() {\n vec2 uv = v_objectUV + .5;\n uv.y = 1. - uv.y;\n\n vec2 imgUV = v_imageUV;\n imgUV -= .5;\n imgUV *= 0.5714285714285714;\n imgUV += .5;\n float imgSoftFrame = getImgFrame(imgUV, .03);\n\n vec4 img = texture(u_image, imgUV);\n vec2 dudx = dFdx(imgUV);\n vec2 dudy = dFdy(imgUV);\n\n if (img.a == 0.) {\n fragColor = u_colorBack;\n return;\n }\n\n float t = .1 * u_time;\n t -= .3;\n\n float tCopy = t + 1. / 3.;\n float tCopy2 = t + 2. / 3.;\n\n t = mod(t, 1.);\n tCopy = mod(tCopy, 1.);\n tCopy2 = mod(tCopy2, 1.);\n\n vec2 animationUV = imgUV - vec2(.5);\n float angle = -u_angle * PI / 180.;\n float cosA = cos(angle);\n float sinA = sin(angle);\n animationUV = vec2(\n animationUV.x * cosA - animationUV.y * sinA,\n animationUV.x * sinA + animationUV.y * cosA\n ) + vec2(.5);\n\n float shape = img[0];\n\n img[1] = blurEdge3x3(u_image, imgUV, dudx, dudy, 8., img[1]);\n\n float outerBlur = 1. - mix(1., img[1], shape);\n float innerBlur = mix(img[1], 0., shape);\n float contour = mix(img[2], 0., shape);\n\n outerBlur *= imgSoftFrame;\n\n float shadow = shadowShape(animationUV, t, innerBlur);\n float shadowCopy = shadowShape(animationUV, tCopy, innerBlur);\n float shadowCopy2 = shadowShape(animationUV, tCopy2, innerBlur);\n\n float inner = .8 + .8 * innerBlur;\n inner = mix(inner, 0., shadow);\n inner = mix(inner, 0., shadowCopy);\n inner = mix(inner, 0., shadowCopy2);\n\n inner *= mix(0., 2., u_innerGlow);\n\n inner += (u_contour * 2.) * contour;\n inner = min(1., inner);\n inner *= (1. - shape);\n\n float outer = 0.;\n {\n t *= 3.;\n t = mod(t - .1, 1.);\n\n outer = .9 * pow(outerBlur, .8);\n float y = mod(animationUV.y - t, 1.);\n float animatedMask = sst(.3, .65, y) * (1. - sst(.65, 1., y));\n animatedMask = .5 + animatedMask;\n outer *= animatedMask;\n outer *= mix(0., 5., pow(u_outerGlow, 2.));\n outer *= imgSoftFrame;\n }\n\n inner = pow(inner, 1.2);\n float heat = clamp(inner + outer, 0., 1.);\n\n heat += (.005 + .35 * u_noise) * (fract(sin(dot(uv, vec2(12.9898, 78.233))) * 43758.5453123) - .5);\n\n float mixer = heat * u_colorsCount;\n vec4 gradient = u_colors[0];\n gradient.rgb *= gradient.a;\n float outerShape = 0.;\n for (int i = 1; i < ${ heatmapMeta.maxColorCount + 1 }; i++) {\n if (i > int(u_colorsCount)) break;\n float m = clamp(mixer - float(i - 1), 0., 1.);\n if (i == 1) {\n outerShape = m;\n }\n vec4 c = u_colors[i - 1];\n c.rgb *= c.a;\n gradient = mix(gradient, c, m);\n }\n\n vec3 color = gradient.rgb * outerShape;\n float opacity = gradient.a * outerShape;\n\n vec3 bgColor = u_colorBack.rgb * u_colorBack.a;\n color = color + bgColor * (1.0 - opacity);\n opacity = opacity + u_colorBack.a * (1.0 - opacity);\n\n color += .02 * (fract(sin(dot(uv + 1., vec2(12.9898, 78.233))) * 43758.5453123) - .5);\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport function toProcessedHeatmap(file: File | string): Promise<{ blob: Blob }> {\n const canvas = document.createElement('canvas');\n const canvasSize = 1000;\n\n return new Promise((resolve, reject) => {\n const image = new Image();\n image.crossOrigin = 'anonymous';\n\n image.addEventListener('load', () => {\n if (typeof file === 'string' ? file.endsWith('.svg') : file.type === 'image/svg+xml') {\n // Force SVG to load at a high fidelity size if it's an SVG\n image.width = canvasSize;\n image.height = canvasSize;\n }\n\n const ratio = image.naturalWidth / image.naturalHeight;\n\n const maxBlur = Math.floor(canvasSize * 0.15);\n const padding = Math.ceil(maxBlur * 2.5);\n let imgWidth = canvasSize;\n let imgHeight = canvasSize;\n if (ratio > 1) {\n imgHeight = Math.floor(canvasSize / ratio);\n } else {\n imgWidth = Math.floor(canvasSize * ratio);\n }\n\n canvas.width = imgWidth + 2 * padding;\n canvas.height = imgHeight + 2 * padding;\n\n const ctx = canvas.getContext('2d', { willReadFrequently: true });\n if (!ctx) {\n throw new Error('Failed to get canvas 2d context');\n }\n\n // 1) Draw original image once, no filters\n ctx.fillStyle = 'white';\n ctx.fillRect(0, 0, canvas.width, canvas.height);\n ctx.drawImage(image, padding, padding, imgWidth, imgHeight);\n\n const { width, height } = canvas;\n const srcImageData = ctx.getImageData(0, 0, width, height);\n const src = srcImageData.data; // RGBA\n\n // 2) Build grayscale array (luma)\n const totalPixels = width * height;\n const gray = new Uint8ClampedArray(totalPixels);\n for (let i = 0; i < totalPixels; i++) {\n const px = i * 4;\n const r = src[px] ?? 0;\n const g = src[px + 1] ?? 0;\n const b = src[px + 2] ?? 0;\n // Standard luma conversion\n gray[i] = (0.299 * r + 0.587 * g + 0.114 * b) | 0;\n }\n\n // 3) Blur grayscale for each \"filter\" you previously used\n const bigBlurRadius = maxBlur;\n const innerBlurRadius = Math.max(1, Math.round(0.12 * maxBlur));\n const contourRadius = 5;\n\n const bigBlurGray = multiPassBlurGray(gray, width, height, bigBlurRadius, 3);\n const innerBlurGray = multiPassBlurGray(gray, width, height, innerBlurRadius, 3);\n const contourGray = multiPassBlurGray(gray, width, height, contourRadius, 1);\n\n // 4) Combine into final ImageData\n const processedImageData = ctx.createImageData(width, height);\n const dst = processedImageData.data;\n\n for (let i = 0; i < totalPixels; i++) {\n const px = i * 4;\n dst[px] = contourGray[i] ?? 0;\n dst[px + 1] = bigBlurGray[i] ?? 0;\n dst[px + 2] = innerBlurGray[i] ?? 0;\n dst[px + 3] = 255;\n }\n\n ctx.putImageData(processedImageData, 0, 0);\n\n canvas.toBlob((blob) => {\n if (!blob) {\n reject(new Error('Failed to create PNG blob'));\n return;\n }\n resolve({ blob });\n }, 'image/png');\n });\n\n image.addEventListener('error', () => {\n reject(new Error('Failed to load image'));\n });\n\n image.src = typeof file === 'string' ? file : URL.createObjectURL(file);\n });\n}\n\n/**\n * Fast box blur for grayscale images using an integral image.\n * gray: Uint8ClampedArray of length width * height\n * radius: blur radius in pixels\n */\nfunction blurGray(gray: Uint8ClampedArray, width: number, height: number, radius: number): Uint8ClampedArray {\n if (radius <= 0) {\n return gray.slice();\n }\n\n const out = new Uint8ClampedArray(width * height);\n const integral = new Uint32Array(width * height);\n\n // Build integral image\n for (let y = 0; y < height; y++) {\n let rowSum = 0;\n for (let x = 0; x < width; x++) {\n const idx = y * width + x;\n const v = gray[idx] ?? 0;\n rowSum += v;\n integral[idx] = rowSum + (y > 0 ? (integral[idx - width] ?? 0) : 0);\n }\n }\n\n // Blur using integral image\n for (let y = 0; y < height; y++) {\n const y1 = Math.max(0, y - radius);\n const y2 = Math.min(height - 1, y + radius);\n for (let x = 0; x < width; x++) {\n const x1 = Math.max(0, x - radius);\n const x2 = Math.min(width - 1, x + radius);\n\n const idxA = y2 * width + x2;\n const idxB = y2 * width + (x1 - 1);\n const idxC = (y1 - 1) * width + x2;\n const idxD = (y1 - 1) * width + (x1 - 1);\n\n const A = integral[idxA] ?? 0;\n const B = x1 > 0 ? (integral[idxB] ?? 0) : 0;\n const C = y1 > 0 ? (integral[idxC] ?? 0) : 0;\n const D = x1 > 0 && y1 > 0 ? (integral[idxD] ?? 0) : 0;\n\n const sum = A - B - C + D;\n const area = (x2 - x1 + 1) * (y2 - y1 + 1);\n out[y * width + x] = Math.round(sum / area);\n }\n }\n\n return out;\n}\n\nfunction multiPassBlurGray(\n gray: Uint8ClampedArray,\n width: number,\n height: number,\n radius: number,\n passes: number\n): Uint8ClampedArray {\n if (radius <= 0 || passes <= 1) {\n return blurGray(gray, width, height, radius);\n }\n\n let input = gray;\n let tmp: Uint8ClampedArray = gray;\n\n for (let p = 0; p < passes; p++) {\n tmp = blurGray(input, width, height, radius);\n input = tmp;\n }\n\n return tmp;\n}\n\nexport interface HeatmapUniforms extends ShaderSizingUniforms {\n u_image: HTMLImageElement | string;\n u_contour: number;\n u_angle: number;\n u_noise: number;\n u_innerGlow: number;\n u_outerGlow: number;\n u_colorBack: [number, number, number, number];\n u_colors: vec4[];\n u_colorsCount: number;\n}\n\nexport interface HeatmapParams extends ShaderSizingParams, ShaderMotionParams {\n image: HTMLImageElement | string;\n contour?: number;\n angle?: number;\n noise?: number;\n innerGlow?: number;\n outerGlow?: number;\n colorBack?: string;\n colors?: string[];\n}\n"], + "mappings": "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", + "names": [] +} diff --git a/public/vendor/paper-shaders/shaders/image-dithering.d.ts b/public/vendor/paper-shaders/shaders/image-dithering.d.ts new file mode 100644 index 0000000..3392dfa --- /dev/null +++ b/public/vendor/paper-shaders/shaders/image-dithering.d.ts @@ -0,0 +1,66 @@ +import type { ShaderMotionParams } from '../shader-mount.js'; +import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js'; +/** + * A dithering image filter with support for 4 dithering modes and multiple color palettes + * (2-color, 3-color, and multicolor options, using either predefined colors or colors sampled + * from the original image). + * + * SIZING NOTE: This shader performs sizing in the fragment shader (not vertex shader) to keep + * u_pxSize in consistent actual pixels. The pixel grid is computed from gl_FragCoord before any + * transforms, so scaling/rotating only affects the underlying image. + * No vertex shader outputs (v_imageUV, v_objectUV, etc.) are used. + * + * Fragment shader uniforms: + * - u_resolution (vec2): Canvas resolution in pixels + * - u_pixelRatio (float): Device pixel ratio + * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1) + * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1) + * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas + * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas + * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover) + * - u_scale (float): Overall zoom level of the graphics (0.01 to 4) + * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360) + * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1) + * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1) + * - u_image (sampler2D): Source image texture + * - u_imageAspectRatio (float): Aspect ratio of the source image + * - u_colorFront (vec4): Foreground color in RGBA + * - u_colorBack (vec4): Background color in RGBA + * - u_colorHighlight (vec4): Secondary foreground color in RGBA (set same as colorFront for classic 2-color dithering) + * - u_originalColors (bool): Use the original colors of the image instead of the color palette + * - u_inverted (bool): Inverts the image luminance, doesn't affect the color scheme; not effective at zero contrast + * - u_type (float): Dithering type (1 = random, 2 = 2x2 Bayer, 3 = 4x4 Bayer, 4 = 8x8 Bayer) + * - u_pxSize (float): Pixel size of dithering grid (0.5 to 20) + * - u_colorSteps (float): Number of colors to use, applies to both color modes (1 to 7) + * + */ +export declare const imageDitheringFragmentShader: string; +export interface ImageDitheringUniforms extends ShaderSizingUniforms { + u_image: HTMLImageElement | string; + u_colorFront: [number, number, number, number]; + u_colorBack: [number, number, number, number]; + u_colorHighlight: [number, number, number, number]; + u_type: (typeof DitheringTypes)[DitheringType]; + u_pxSize: number; + u_colorSteps: number; + u_originalColors: boolean; + u_inverted: boolean; +} +export interface ImageDitheringParams extends ShaderSizingParams, ShaderMotionParams { + image: HTMLImageElement | string; + colorFront?: string; + colorBack?: string; + colorHighlight?: string; + type?: DitheringType; + size?: number; + colorSteps?: number; + originalColors?: boolean; + inverted?: boolean; +} +export declare const DitheringTypes: { + readonly random: 1; + readonly '2x2': 2; + readonly '4x4': 3; + readonly '8x8': 4; +}; +export type DitheringType = keyof typeof DitheringTypes; diff --git a/public/vendor/paper-shaders/shaders/image-dithering.js b/public/vendor/paper-shaders/shaders/image-dithering.js new file mode 100644 index 0000000..82f3fcf --- /dev/null +++ b/public/vendor/paper-shaders/shaders/image-dithering.js @@ -0,0 +1,201 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Paper Shaders * + * https://github.com/paper-design/shaders * + * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +import {} from "../shader-sizing.js"; +import { proceduralHash21, declarePI } from "../shader-utils.js"; +const imageDitheringFragmentShader = `#version 300 es +precision mediump float; + +uniform vec2 u_resolution; +uniform float u_pixelRatio; +uniform float u_originX; +uniform float u_originY; +uniform float u_worldWidth; +uniform float u_worldHeight; +uniform float u_fit; + +uniform float u_scale; +uniform float u_rotation; +uniform float u_offsetX; +uniform float u_offsetY; + +uniform vec4 u_colorFront; +uniform vec4 u_colorBack; +uniform vec4 u_colorHighlight; + +uniform sampler2D u_image; +uniform float u_imageAspectRatio; + +uniform float u_type; +uniform float u_pxSize; +uniform bool u_originalColors; +uniform bool u_inverted; +uniform float u_colorSteps; + +out vec4 fragColor; + + +${proceduralHash21} +${declarePI} + +float getUvFrame(vec2 uv, vec2 pad) { + float aa = 0.0001; + + float left = smoothstep(-pad.x, -pad.x + aa, uv.x); + float right = smoothstep(1.0 + pad.x, 1.0 + pad.x - aa, uv.x); + float bottom = smoothstep(-pad.y, -pad.y + aa, uv.y); + float top = smoothstep(1.0 + pad.y, 1.0 + pad.y - aa, uv.y); + + return left * right * bottom * top; +} + +vec2 getImageUV(vec2 uv) { + vec2 boxOrigin = vec2(.5 - u_originX, u_originY - .5); + float r = u_rotation * PI / 180.; + mat2 graphicRotation = mat2(cos(r), sin(r), -sin(r), cos(r)); + vec2 graphicOffset = vec2(-u_offsetX, u_offsetY); + + vec2 imageBoxSize; + if (u_fit == 1.) { // contain + imageBoxSize.x = min(u_resolution.x / u_imageAspectRatio, u_resolution.y) * u_imageAspectRatio; + } else if (u_fit == 2.) { // cover + imageBoxSize.x = max(u_resolution.x / u_imageAspectRatio, u_resolution.y) * u_imageAspectRatio; + } else { + imageBoxSize.x = min(10.0, 10.0 / u_imageAspectRatio * u_imageAspectRatio); + } + imageBoxSize.y = imageBoxSize.x / u_imageAspectRatio; + vec2 imageBoxScale = u_resolution.xy / imageBoxSize; + + vec2 imageUV = uv; + imageUV *= imageBoxScale; + imageUV += boxOrigin * (imageBoxScale - 1.); + imageUV += graphicOffset; + imageUV /= u_scale; + imageUV.x *= u_imageAspectRatio; + imageUV = graphicRotation * imageUV; + imageUV.x /= u_imageAspectRatio; + + imageUV += .5; + imageUV.y = 1. - imageUV.y; + + return imageUV; +} + +const int bayer2x2[4] = int[4](0, 2, 3, 1); +const int bayer4x4[16] = int[16]( +0, 8, 2, 10, +12, 4, 14, 6, +3, 11, 1, 9, +15, 7, 13, 5 +); + +const int bayer8x8[64] = int[64]( +0, 32, 8, 40, 2, 34, 10, 42, +48, 16, 56, 24, 50, 18, 58, 26, +12, 44, 4, 36, 14, 46, 6, 38, +60, 28, 52, 20, 62, 30, 54, 22, +3, 35, 11, 43, 1, 33, 9, 41, +51, 19, 59, 27, 49, 17, 57, 25, +15, 47, 7, 39, 13, 45, 5, 37, +63, 31, 55, 23, 61, 29, 53, 21 +); + +float getBayerValue(vec2 uv, int size) { + ivec2 pos = ivec2(fract(uv / float(size)) * float(size)); + int index = pos.y * size + pos.x; + + if (size == 2) { + return float(bayer2x2[index]) / 4.0; + } else if (size == 4) { + return float(bayer4x4[index]) / 16.0; + } else if (size == 8) { + return float(bayer8x8[index]) / 64.0; + } + return 0.0; +} + + +void main() { + + float pxSize = u_pxSize * u_pixelRatio; + vec2 pxSizeUV = gl_FragCoord.xy - .5 * u_resolution; + pxSizeUV /= pxSize; + vec2 canvasPixelizedUV = (floor(pxSizeUV) + .5) * pxSize; + vec2 normalizedUV = canvasPixelizedUV / u_resolution; + + vec2 imageUV = getImageUV(normalizedUV); + vec2 ditheringNoiseUV = canvasPixelizedUV; + vec4 image = texture(u_image, imageUV); + float frame = getUvFrame(imageUV, pxSize / u_resolution); + + int type = int(floor(u_type)); + float dithering = 0.0; + + float lum = dot(vec3(.2126, .7152, .0722), image.rgb); + lum = u_inverted ? (1. - lum) : lum; + + switch (type) { + case 1: { + dithering = step(hash21(ditheringNoiseUV), lum); + } break; + case 2: + dithering = getBayerValue(pxSizeUV, 2); + break; + case 3: + dithering = getBayerValue(pxSizeUV, 4); + break; + default : + dithering = getBayerValue(pxSizeUV, 8); + break; + } + + float colorSteps = max(floor(u_colorSteps), 1.); + vec3 color = vec3(0.0); + float opacity = 1.; + + dithering -= .5; + float brightness = clamp(lum + dithering / colorSteps, 0.0, 1.0); + brightness = mix(0.0, brightness, frame); + brightness = mix(0.0, brightness, image.a); + float quantLum = floor(brightness * colorSteps + 0.5) / colorSteps; + quantLum = mix(0.0, quantLum, frame); + + if (u_originalColors == true) { + vec3 normColor = image.rgb / max(lum, 0.001); + color = normColor * quantLum; + + float quantAlpha = floor(image.a * colorSteps + 0.5) / colorSteps; + opacity = mix(quantLum, 1., quantAlpha); + } else { + vec3 fgColor = u_colorFront.rgb * u_colorFront.a; + float fgOpacity = u_colorFront.a; + vec3 bgColor = u_colorBack.rgb * u_colorBack.a; + float bgOpacity = u_colorBack.a; + vec3 hlColor = u_colorHighlight.rgb * u_colorHighlight.a; + float hlOpacity = u_colorHighlight.a; + + fgColor = mix(fgColor, hlColor, step(1.02 - .02 * u_colorSteps, brightness)); + fgOpacity = mix(fgOpacity, hlOpacity, step(1.02 - .02 * u_colorSteps, brightness)); + + color = fgColor * quantLum; + opacity = fgOpacity * quantLum; + color += bgColor * (1.0 - opacity); + opacity += bgOpacity * (1.0 - opacity); + } + + fragColor = vec4(color, opacity); +} +`; +const DitheringTypes = { + "random": 1, + "2x2": 2, + "4x4": 3, + "8x8": 4 +}; +export { + DitheringTypes, + imageDitheringFragmentShader +}; +//# sourceMappingURL=image-dithering.js.map diff --git a/public/vendor/paper-shaders/shaders/image-dithering.js.map b/public/vendor/paper-shaders/shaders/image-dithering.js.map new file mode 100644 index 0000000..eb53c89 --- /dev/null +++ b/public/vendor/paper-shaders/shaders/image-dithering.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../../src/shaders/image-dithering.ts"], + "sourcesContent": ["import type { ShaderMotionParams } from '../shader-mount.js';\nimport { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { proceduralHash21, declarePI } from '../shader-utils.js';\n\n/**\n * A dithering image filter with support for 4 dithering modes and multiple color palettes\n * (2-color, 3-color, and multicolor options, using either predefined colors or colors sampled\n * from the original image).\n *\n * SIZING NOTE: This shader performs sizing in the fragment shader (not vertex shader) to keep\n * u_pxSize in consistent actual pixels. The pixel grid is computed from gl_FragCoord before any\n * transforms, so scaling/rotating only affects the underlying image.\n * No vertex shader outputs (v_imageUV, v_objectUV, etc.) are used.\n *\n * Fragment shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n * - u_image (sampler2D): Source image texture\n * - u_imageAspectRatio (float): Aspect ratio of the source image\n * - u_colorFront (vec4): Foreground color in RGBA\n * - u_colorBack (vec4): Background color in RGBA\n * - u_colorHighlight (vec4): Secondary foreground color in RGBA (set same as colorFront for classic 2-color dithering)\n * - u_originalColors (bool): Use the original colors of the image instead of the color palette\n * - u_inverted (bool): Inverts the image luminance, doesn't affect the color scheme; not effective at zero contrast\n * - u_type (float): Dithering type (1 = random, 2 = 2x2 Bayer, 3 = 4x4 Bayer, 4 = 8x8 Bayer)\n * - u_pxSize (float): Pixel size of dithering grid (0.5 to 20)\n * - u_colorSteps (float): Number of colors to use, applies to both color modes (1 to 7)\n *\n */\n\n// language=GLSL\nexport const imageDitheringFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform vec2 u_resolution;\nuniform float u_pixelRatio;\nuniform float u_originX;\nuniform float u_originY;\nuniform float u_worldWidth;\nuniform float u_worldHeight;\nuniform float u_fit;\n\nuniform float u_scale;\nuniform float u_rotation;\nuniform float u_offsetX;\nuniform float u_offsetY;\n\nuniform vec4 u_colorFront;\nuniform vec4 u_colorBack;\nuniform vec4 u_colorHighlight;\n\nuniform sampler2D u_image;\nuniform float u_imageAspectRatio;\n\nuniform float u_type;\nuniform float u_pxSize;\nuniform bool u_originalColors;\nuniform bool u_inverted;\nuniform float u_colorSteps;\n\nout vec4 fragColor;\n\n\n${ proceduralHash21 }\n${ declarePI }\n\nfloat getUvFrame(vec2 uv, vec2 pad) {\n float aa = 0.0001;\n\n float left = smoothstep(-pad.x, -pad.x + aa, uv.x);\n float right = smoothstep(1.0 + pad.x, 1.0 + pad.x - aa, uv.x);\n float bottom = smoothstep(-pad.y, -pad.y + aa, uv.y);\n float top = smoothstep(1.0 + pad.y, 1.0 + pad.y - aa, uv.y);\n\n return left * right * bottom * top;\n}\n\nvec2 getImageUV(vec2 uv) {\n vec2 boxOrigin = vec2(.5 - u_originX, u_originY - .5);\n float r = u_rotation * PI / 180.;\n mat2 graphicRotation = mat2(cos(r), sin(r), -sin(r), cos(r));\n vec2 graphicOffset = vec2(-u_offsetX, u_offsetY);\n\n vec2 imageBoxSize;\n if (u_fit == 1.) { // contain\n imageBoxSize.x = min(u_resolution.x / u_imageAspectRatio, u_resolution.y) * u_imageAspectRatio;\n } else if (u_fit == 2.) { // cover\n imageBoxSize.x = max(u_resolution.x / u_imageAspectRatio, u_resolution.y) * u_imageAspectRatio;\n } else {\n imageBoxSize.x = min(10.0, 10.0 / u_imageAspectRatio * u_imageAspectRatio);\n }\n imageBoxSize.y = imageBoxSize.x / u_imageAspectRatio;\n vec2 imageBoxScale = u_resolution.xy / imageBoxSize;\n\n vec2 imageUV = uv;\n imageUV *= imageBoxScale;\n imageUV += boxOrigin * (imageBoxScale - 1.);\n imageUV += graphicOffset;\n imageUV /= u_scale;\n imageUV.x *= u_imageAspectRatio;\n imageUV = graphicRotation * imageUV;\n imageUV.x /= u_imageAspectRatio;\n\n imageUV += .5;\n imageUV.y = 1. - imageUV.y;\n\n return imageUV;\n}\n\nconst int bayer2x2[4] = int[4](0, 2, 3, 1);\nconst int bayer4x4[16] = int[16](\n0, 8, 2, 10,\n12, 4, 14, 6,\n3, 11, 1, 9,\n15, 7, 13, 5\n);\n\nconst int bayer8x8[64] = int[64](\n0, 32, 8, 40, 2, 34, 10, 42,\n48, 16, 56, 24, 50, 18, 58, 26,\n12, 44, 4, 36, 14, 46, 6, 38,\n60, 28, 52, 20, 62, 30, 54, 22,\n3, 35, 11, 43, 1, 33, 9, 41,\n51, 19, 59, 27, 49, 17, 57, 25,\n15, 47, 7, 39, 13, 45, 5, 37,\n63, 31, 55, 23, 61, 29, 53, 21\n);\n\nfloat getBayerValue(vec2 uv, int size) {\n ivec2 pos = ivec2(fract(uv / float(size)) * float(size));\n int index = pos.y * size + pos.x;\n\n if (size == 2) {\n return float(bayer2x2[index]) / 4.0;\n } else if (size == 4) {\n return float(bayer4x4[index]) / 16.0;\n } else if (size == 8) {\n return float(bayer8x8[index]) / 64.0;\n }\n return 0.0;\n}\n\n\nvoid main() {\n\n float pxSize = u_pxSize * u_pixelRatio;\n vec2 pxSizeUV = gl_FragCoord.xy - .5 * u_resolution;\n pxSizeUV /= pxSize;\n vec2 canvasPixelizedUV = (floor(pxSizeUV) + .5) * pxSize;\n vec2 normalizedUV = canvasPixelizedUV / u_resolution;\n\n vec2 imageUV = getImageUV(normalizedUV);\n vec2 ditheringNoiseUV = canvasPixelizedUV;\n vec4 image = texture(u_image, imageUV);\n float frame = getUvFrame(imageUV, pxSize / u_resolution);\n\n int type = int(floor(u_type));\n float dithering = 0.0;\n\n float lum = dot(vec3(.2126, .7152, .0722), image.rgb);\n lum = u_inverted ? (1. - lum) : lum;\n\n switch (type) {\n case 1: {\n dithering = step(hash21(ditheringNoiseUV), lum);\n } break;\n case 2:\n dithering = getBayerValue(pxSizeUV, 2);\n break;\n case 3:\n dithering = getBayerValue(pxSizeUV, 4);\n break;\n default :\n dithering = getBayerValue(pxSizeUV, 8);\n break;\n }\n\n float colorSteps = max(floor(u_colorSteps), 1.);\n vec3 color = vec3(0.0);\n float opacity = 1.;\n\n dithering -= .5;\n float brightness = clamp(lum + dithering / colorSteps, 0.0, 1.0);\n brightness = mix(0.0, brightness, frame);\n brightness = mix(0.0, brightness, image.a);\n float quantLum = floor(brightness * colorSteps + 0.5) / colorSteps;\n quantLum = mix(0.0, quantLum, frame);\n\n if (u_originalColors == true) {\n vec3 normColor = image.rgb / max(lum, 0.001);\n color = normColor * quantLum;\n\n float quantAlpha = floor(image.a * colorSteps + 0.5) / colorSteps;\n opacity = mix(quantLum, 1., quantAlpha);\n } else {\n vec3 fgColor = u_colorFront.rgb * u_colorFront.a;\n float fgOpacity = u_colorFront.a;\n vec3 bgColor = u_colorBack.rgb * u_colorBack.a;\n float bgOpacity = u_colorBack.a;\n vec3 hlColor = u_colorHighlight.rgb * u_colorHighlight.a;\n float hlOpacity = u_colorHighlight.a;\n\n fgColor = mix(fgColor, hlColor, step(1.02 - .02 * u_colorSteps, brightness));\n fgOpacity = mix(fgOpacity, hlOpacity, step(1.02 - .02 * u_colorSteps, brightness));\n\n color = fgColor * quantLum;\n opacity = fgOpacity * quantLum;\n color += bgColor * (1.0 - opacity);\n opacity += bgOpacity * (1.0 - opacity);\n }\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface ImageDitheringUniforms extends ShaderSizingUniforms {\n u_image: HTMLImageElement | string;\n u_colorFront: [number, number, number, number];\n u_colorBack: [number, number, number, number];\n u_colorHighlight: [number, number, number, number];\n u_type: (typeof DitheringTypes)[DitheringType];\n u_pxSize: number;\n u_colorSteps: number;\n u_originalColors: boolean;\n u_inverted: boolean;\n}\n\nexport interface ImageDitheringParams extends ShaderSizingParams, ShaderMotionParams {\n image: HTMLImageElement | string;\n colorFront?: string;\n colorBack?: string;\n colorHighlight?: string;\n type?: DitheringType;\n size?: number;\n colorSteps?: number;\n originalColors?: boolean;\n inverted?: boolean;\n}\n\nexport const DitheringTypes = {\n 'random': 1,\n '2x2': 2,\n '4x4': 3,\n '8x8': 4,\n} as const;\n\nexport type DitheringType = keyof typeof DitheringTypes;\n"], + "mappings": ";;;;;AACA,eAAmE;AACnE,SAAS,kBAAkB,iBAAiB;AAsCrC,MAAM,+BAAuC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgCjD,gBAAiB;AAAA,EACjB,SAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA+KN,MAAM,iBAAiB;AAAA,EAC5B,UAAU;AAAA,EACV,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AACT;", + "names": [] +} diff --git a/public/vendor/paper-shaders/shaders/lens-distortion.d.ts b/public/vendor/paper-shaders/shaders/lens-distortion.d.ts new file mode 100644 index 0000000..8a1970c --- /dev/null +++ b/public/vendor/paper-shaders/shaders/lens-distortion.d.ts @@ -0,0 +1,97 @@ +import type { ShaderMotionParams } from '../shader-mount.js'; +import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js'; +export declare const lensDistortionMeta: { + readonly maxSamples: 50; +}; +/** + * + * Lens Distortion image filter separates an image into shifting color layers + * (recreating the chromatic aberration of a lens) and warps the image geometry, + * curving it outward or inward like barrel and pincushion distortion. + * + * Fragment shader uniforms: + * - u_image (sampler2D): Source image texture + * - u_spread (float): Strength of the color split; how far the color layers are pushed apart; 0 is off (0 to 1) + * - u_bias (float): Shifts the colors toward one end of the spread; 0 spaces them evenly (-1 to 1) + * - u_angle (float): Direction of the spread in degrees (0 to 360) + * - u_perspective (float): Shapes the spread direction from a straight line (0) to a radial burst out from the centre (1) (0 to 1) + * - u_count (float): Number of sampled color layers along the spread; higher is smoother and costlier (2 to 50) + * - u_dispersion (float): Overall amount of color dispersion; 1 gives each layer its own color from the spectrum, 0 keeps the original image color (0 to 1) + * - u_dispersionShift (float): Balance of the dispersion between a soft circular zone at the centre and the rest of the image; 0 applies it evenly, -1 keeps it in the centre only, 1 keeps it at the edges only (-1 to 1) + * - u_dispersionColor (float): Rotates the colors around the hue wheel, 0 to 1 for a full turn + * - u_focusCenter (float): Reduces the spread in a circular zone at the centre; 0 keeps it full to the centre (0 to 1) + * - u_focusEdges (float): Reduces the spread toward the edges; 0 keeps it full to the edges, 1 restores the original image there (0 to 1) + * - u_swirl (float): Rotates the color layers around the centre by an angle growing along the spread; 0 is off (-1 to 1) + * - u_noise (float): Scatters the spread direction with noise; 0 is off (0 to 1) + * - u_noiseFrequency (float): Frequency of the noise, 0 to 1 mapped internally to 0 to 18; higher is finer (no effect with noise = 0) + * - u_noiseOffset (float): Offsets the noise pattern for a different seed, 0 to 1 mapped internally to 0 to 30 (no effect with noise = 0) + * - u_lensBulge (float): Radial lens warp of the image geometry; positive bulges out like a fisheye/barrel, negative pinches in like a pincushion; strong positive values fade out the corners (-1 to 1) + * - u_lensCircle (float): Squeezes pixels outside the inscribed circle inward so the outline becomes a circle; also turns the spread radial and damps it near the rim; 0 is off, 1 is full (0 to 1) + * - u_grainMixer (float): Scatters the spread with grain noise, breaking up the edges of the color layers (0 to 1) + * - u_grainOverlay (float): Post-processing black/white grain overlay (0 to 1) + * - u_imageX (float): Pans the image horizontally behind the effect; 0 is centred (-1 to 1) + * - u_imageY (float): Pans the image vertically behind the effect; 0 is centred (-1 to 1) + * + * Vertex shader outputs (used in fragment shader): + * - v_imageUV (vec2): Image UV coordinates with global sizing (rotation, scale, offset, etc) applied + * + * Vertex shader uniforms: + * - u_resolution (vec2): Canvas resolution in pixels + * - u_pixelRatio (float): Device pixel ratio + * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1) + * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1) + * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover) + * - u_scale (float): Overall zoom level of the graphics (0.01 to 4) + * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360) + * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1) + * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1) + * - u_imageAspectRatio (float): Aspect ratio of the source image + * + */ +export declare const lensDistortionFragmentShader: string; +export interface LensDistortionUniforms extends ShaderSizingUniforms { + u_image: HTMLImageElement | string | undefined; + u_spread: number; + u_bias: number; + u_angle: number; + u_perspective: number; + u_count: number; + u_dispersion: number; + u_dispersionShift: number; + u_dispersionColor: number; + u_focusCenter: number; + u_focusEdges: number; + u_swirl: number; + u_noise: number; + u_noiseFrequency: number; + u_noiseOffset: number; + u_lensBulge: number; + u_lensCircle: number; + u_grainMixer: number; + u_grainOverlay: number; + u_imageX: number; + u_imageY: number; +} +export interface LensDistortionParams extends ShaderSizingParams, ShaderMotionParams { + image?: HTMLImageElement | string; + spread?: number; + bias?: number; + angle?: number; + perspective?: number; + count?: number; + dispersion?: number; + dispersionShift?: number; + dispersionColor?: number; + focusCenter?: number; + focusEdges?: number; + swirl?: number; + noise?: number; + noiseFrequency?: number; + noiseOffset?: number; + lensBulge?: number; + lensCircle?: number; + grainMixer?: number; + grainOverlay?: number; + imageX?: number; + imageY?: number; +} diff --git a/public/vendor/paper-shaders/shaders/lens-distortion.js b/public/vendor/paper-shaders/shaders/lens-distortion.js new file mode 100644 index 0000000..98a6cc4 --- /dev/null +++ b/public/vendor/paper-shaders/shaders/lens-distortion.js @@ -0,0 +1,276 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Paper Shaders * + * https://github.com/paper-design/shaders * + * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +import {} from "../shader-sizing.js"; +import { declarePI, proceduralHash21, rotation2 } from "../shader-utils.js"; +const lensDistortionMeta = { + maxSamples: 50 +}; +const lensDistortionFragmentShader = `#version 300 es +precision mediump float; + +uniform sampler2D u_image; +uniform float u_imageAspectRatio; +uniform float u_spread; +uniform float u_bias; +uniform float u_angle; +uniform float u_perspective; +uniform float u_count; +uniform float u_dispersion; +uniform float u_dispersionShift; +uniform float u_dispersionColor; +uniform float u_focusCenter; +uniform float u_focusEdges; +uniform float u_swirl; +uniform float u_noise; +uniform float u_noiseFrequency; +uniform float u_noiseOffset; +uniform float u_lensBulge; +uniform float u_lensCircle; +uniform float u_grainMixer; +uniform float u_grainOverlay; +uniform float u_imageX; +uniform float u_imageY; + +in vec2 v_imageUV; + +out vec4 fragColor; + +${declarePI} +${proceduralHash21} +${rotation2} + +float valueNoise(vec2 st) { + vec2 i = floor(st); + vec2 f = fract(st); + float a = hash21(i); + float b = hash21(i + vec2(1., 0.)); + float c = hash21(i + vec2(0., 1.)); + float d = hash21(i + vec2(1., 1.)); + vec2 u = f * f * (3. - 2. * f); + return mix(mix(a, b, u.x), mix(c, d, u.x), u.y); +} + +float getUvFrame(vec2 uv) { + vec2 invAA = 1. / clamp(fwidth(uv), 1e-5, .02); + vec2 lo = clamp(uv * invAA + .5, 0., 1.); + vec2 hi = clamp((1. - uv) * invAA + .5, 0., 1.); + return lo.x * hi.x * lo.y * hi.y; +} + +vec4 sampleOverWhite(vec2 uv) { + vec4 img = texture(u_image, uv); + float cover = img.a * getUvFrame(uv); + vec3 colorOverWhite = mix(vec3(1.), img.rgb, cover); + return vec4(colorOverWhite, cover); +} + +vec3 hueColor(float hue) { + vec3 rgb = clamp(abs(mod(hue * 6. + vec3(0., 4., 2.), 6.) - 3.) - 1., 0., 1.); + rgb = rgb * rgb * (3. - 2. * rgb); + return rgb; +} + +float boxInradius() { + return .5 * min(u_imageAspectRatio, 1.); +} + +float boxOutradius() { + return .5 * length(vec2(u_imageAspectRatio, 1.)); +} + +float spreadReach() { + return .7 * pow(u_spread, 1.3 + 2.7 * u_spread); +} + +float innerCircleMask(float radius, float inradius) { + return 1. - smoothstep(.5 * inradius, 1.1 * inradius, radius); +} + +float dispersionCurve(float t, float biasPow) { + float mirroredT = u_bias < 0. ? 1. - t : t; + float curved = pow(mirroredT, biasPow); + return u_bias < 0. ? 1. - curved : curved; +} + +vec2 getSpread(vec2 fromCenter, float radius, vec2 warpedUV, float edgeAA, float inradius, float outradius, float reach, out float outStrength) { + float angleRad = radians(u_angle); + vec2 uniformDir = vec2(cos(angleRad), sin(angleRad)); + + float invInradius = 1. / inradius; + vec2 radialDir = fromCenter * invInradius; + float maxLen = (outradius + reach) * invInradius; + float radialLen = radius * invInradius; + if (radialLen > maxLen) radialDir *= maxLen / radialLen; + vec2 spreadDir = mix(uniformDir, radialDir, u_perspective); + + float bandProximity = smoothstep(inradius * .8, inradius, radius); + float lensCircleMaxing = bandProximity * u_lensCircle * u_lensCircle * u_lensCircle; + spreadDir = mix(spreadDir, radialDir, lensCircleMaxing); + + vec2 warpedAbs = abs(warpedUV - .5); + float inner = mix(1., smoothstep(0., mix(inradius, outradius, u_focusCenter), radius), u_focusCenter); + float boxDist = max(warpedAbs.x, warpedAbs.y) * 2.; + float outer = mix(1., 1. - min(boxDist, 1.), u_focusEdges); + float strength = inner * outer; + + strength *= mix(1., mix(.15, .03, max(-u_lensBulge, 0.)), lensCircleMaxing); + + vec2 outside = max(warpedAbs - .5, 0.); + float margin = max(reach * length(spreadDir) * (1. - u_lensCircle), edgeAA); + strength *= 1. - smoothstep(0., margin, length(outside)); + + outStrength = strength; + vec2 axis = spreadDir * (reach * strength); + + if (u_noise > 0.) { + float turn = (valueNoise(fromCenter * u_noiseFrequency * 18. + u_noiseOffset * 30.) - .5) * 2. * u_noise; + float cs = cos(turn), sn = sin(turn); + axis = mat2(cs, -sn, sn, cs) * axis; + } + + axis.x /= u_imageAspectRatio; + return axis; +} + +vec2 lensWarp(vec2 fromCenter, float radius, float inradius, out float bulgeFade) { + bulgeFade = 1.; + if (u_lensBulge == 0. && u_lensCircle <= 0.) return fromCenter; + if (radius < 1e-5) return fromCenter; + + float r = radius; + + if (u_lensBulge != 0.) { + float rn = radius / inradius; + float bulge = abs(u_lensBulge) * (u_lensBulge > 0. ? 1.4 : 1.2); + if (u_lensBulge > 0.) bulgeFade = 1. - smoothstep(1.45, 1.53, rn * bulge); + float map = u_lensBulge > 0. + ? tan(min(rn * bulge, 1.53)) / tan(bulge) + : atan(rn * tan(bulge)) / bulge; + float bulgeScale = map / rn; + fromCenter *= bulgeScale; + r *= bulgeScale; + } + + if (u_lensCircle > 0.) { + vec2 dir = fromCenter / max(r, 1e-5); + vec2 halfBox = vec2(u_imageAspectRatio, 1.) * .5; + float rBox = min(halfBox.x / max(abs(dir.x), 1e-4), halfBox.y / max(abs(dir.y), 1e-4)); + float band = inradius * mix(.03, .2, .5 * (u_lensBulge + 1.)); + float innerEdge = inradius - band; + float over = smoothstep(0., 1., (r - innerEdge) / band); + float g = r + (rBox - inradius) * pow(over, 14.); + fromCenter = dir * mix(r, g, u_lensCircle); + } + + return fromCenter; +} + +void main() { + vec2 uv = v_imageUV; + + float invAspect = 1. / u_imageAspectRatio; + float inradius = boxInradius(); + float outradius = boxOutradius(); + float reach = spreadReach(); + + vec2 fromCenter = uv - .5; + fromCenter.x *= u_imageAspectRatio; + float radius = length(fromCenter); + + float bulgeFade; + vec2 warpedFromCenter = lensWarp(fromCenter, radius, inradius, bulgeFade); + vec2 baseUV = vec2(warpedFromCenter.x * invAspect, warpedFromCenter.y) + .5; + + vec2 baseDerivative = fwidth(baseUV); + float edgeAA = clamp(2. * max(baseDerivative.x, baseDerivative.y), .001, .02); + + float spreadStrength; + vec2 spreadAxis = getSpread(fromCenter, radius, baseUV, edgeAA, inradius, outradius, reach, spreadStrength); + + vec2 grainUV = vec2(0.); + if (u_grainMixer > 0. || u_grainOverlay > 0.) { + vec2 dudx = dFdx(v_imageUV); + vec2 dudy = dFdy(v_imageUV); + grainUV = (v_imageUV - .5) * (.8 / vec2(length(dudx), length(dudy))) + .5; + } + + if (u_grainMixer > 0.) { + float grainSeed = valueNoise(grainUV); + vec2 jit = fract(grainSeed * vec2(157.31, 113.57)) * 2. - 1.; + spreadAxis += jit * .3 * u_grainMixer * length(spreadAxis); + } + + float count = floor(u_count); + int countInteger = int(count); + + float invCount = 1. / count; + float invSpan = 1. / max(count - 1., 1.); + float hueBase = u_dispersionColor + .5; + float biasPower = 1. + 2. * abs(u_bias); + vec2 tapBias = .5 - vec2(u_imageX, u_imageY); + + float centerAmount = clamp(1. - u_dispersionShift, 0., 1.); + float edgesAmount = clamp(1. + u_dispersionShift, 0., 1.); + float dispersion = u_dispersion * mix(edgesAmount, centerAmount, innerCircleMask(radius, inradius)); + float dispersionPower = pow(dispersion, .8); + + float warpedRadius = length(warpedFromCenter); + float swirlAngle = u_swirl * .4 * PI * spreadStrength * u_spread * min(1., inradius / max(warpedRadius, 1e-4)); + + vec3 colorSum = vec3(0.); + vec3 weightSum = vec3(0.); + float coverSum = 0.; + + for (int i = 0; i < ${lensDistortionMeta.maxSamples}; i++) { + if (i >= countInteger) break; + + float layer = float(i); + float hue = hueBase + layer * invCount; + + float spread = layer * invSpan; + if (u_bias != 0.) spread = dispersionCurve(spread, biasPower); + + // mix(axis, -axis, spread) is axis scaled by the signed position along the fan + float fanPos = 1. - 2. * spread; + vec2 tapUV = baseUV + spreadAxis * fanPos - .5; + + if (u_swirl != 0.) { + tapUV.x *= u_imageAspectRatio; + tapUV = rotate(tapUV, swirlAngle * fanPos); + tapUV.x *= invAspect; + } + + vec4 tap = sampleOverWhite(tapUV + tapBias); + vec3 weight = 1. - dispersionPower * hueColor(hue); + + colorSum += tap.rgb * weight; + weightSum += weight; + coverSum += tap.a; + } + + vec3 color = colorSum / max(weightSum, 1e-4); + float coverAvg = coverSum * invCount; + + float ground = min(color.r, min(color.g, color.b)); + float alpha = max(coverAvg, 1. - ground); + vec3 premult = max(color - (1. - alpha), 0.); + fragColor = vec4(premult, alpha) * bulgeFade; + + if (u_grainOverlay > 0.) { + float grain = valueNoise(rotate(grainUV, 1.) + vec2(3.)); + grain = mix(grain, valueNoise(rotate(grainUV, 2.) + vec2(-1.)), .5); + grain = pow(grain, 1.3); + float grainV = grain * 2. - 1.; + float grainStrength = pow(u_grainOverlay * abs(grainV), .8) * fragColor.a; + fragColor.rgb = mix(fragColor.rgb, vec3(step(0., grainV)) * fragColor.a, .35 * grainStrength); + } +} +`; +export { + lensDistortionFragmentShader, + lensDistortionMeta +}; +//# sourceMappingURL=lens-distortion.js.map diff --git a/public/vendor/paper-shaders/shaders/lens-distortion.js.map b/public/vendor/paper-shaders/shaders/lens-distortion.js.map new file mode 100644 index 0000000..e5e6c2c --- /dev/null +++ b/public/vendor/paper-shaders/shaders/lens-distortion.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../../src/shaders/lens-distortion.ts"], + "sourcesContent": ["import type { ShaderMotionParams } from '../shader-mount.js';\nimport { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { declarePI, proceduralHash21, rotation2 } from '../shader-utils.js';\n\nexport const lensDistortionMeta = {\n maxSamples: 50,\n} as const;\n\n/**\n *\n * Lens Distortion image filter separates an image into shifting color layers\n * (recreating the chromatic aberration of a lens) and warps the image geometry,\n * curving it outward or inward like barrel and pincushion distortion.\n *\n * Fragment shader uniforms:\n * - u_image (sampler2D): Source image texture\n * - u_spread (float): Strength of the color split; how far the color layers are pushed apart; 0 is off (0 to 1)\n * - u_bias (float): Shifts the colors toward one end of the spread; 0 spaces them evenly (-1 to 1)\n * - u_angle (float): Direction of the spread in degrees (0 to 360)\n * - u_perspective (float): Shapes the spread direction from a straight line (0) to a radial burst out from the centre (1) (0 to 1)\n * - u_count (float): Number of sampled color layers along the spread; higher is smoother and costlier (2 to 50)\n * - u_dispersion (float): Overall amount of color dispersion; 1 gives each layer its own color from the spectrum, 0 keeps the original image color (0 to 1)\n * - u_dispersionShift (float): Balance of the dispersion between a soft circular zone at the centre and the rest of the image; 0 applies it evenly, -1 keeps it in the centre only, 1 keeps it at the edges only (-1 to 1)\n * - u_dispersionColor (float): Rotates the colors around the hue wheel, 0 to 1 for a full turn\n * - u_focusCenter (float): Reduces the spread in a circular zone at the centre; 0 keeps it full to the centre (0 to 1)\n * - u_focusEdges (float): Reduces the spread toward the edges; 0 keeps it full to the edges, 1 restores the original image there (0 to 1)\n * - u_swirl (float): Rotates the color layers around the centre by an angle growing along the spread; 0 is off (-1 to 1)\n * - u_noise (float): Scatters the spread direction with noise; 0 is off (0 to 1)\n * - u_noiseFrequency (float): Frequency of the noise, 0 to 1 mapped internally to 0 to 18; higher is finer (no effect with noise = 0)\n * - u_noiseOffset (float): Offsets the noise pattern for a different seed, 0 to 1 mapped internally to 0 to 30 (no effect with noise = 0)\n * - u_lensBulge (float): Radial lens warp of the image geometry; positive bulges out like a fisheye/barrel, negative pinches in like a pincushion; strong positive values fade out the corners (-1 to 1)\n * - u_lensCircle (float): Squeezes pixels outside the inscribed circle inward so the outline becomes a circle; also turns the spread radial and damps it near the rim; 0 is off, 1 is full (0 to 1)\n * - u_grainMixer (float): Scatters the spread with grain noise, breaking up the edges of the color layers (0 to 1)\n * - u_grainOverlay (float): Post-processing black/white grain overlay (0 to 1)\n * - u_imageX (float): Pans the image horizontally behind the effect; 0 is centred (-1 to 1)\n * - u_imageY (float): Pans the image vertically behind the effect; 0 is centred (-1 to 1)\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_imageUV (vec2): Image UV coordinates with global sizing (rotation, scale, offset, etc) applied\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n * - u_imageAspectRatio (float): Aspect ratio of the source image\n *\n */\n\n// language=GLSL\nexport const lensDistortionFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform sampler2D u_image;\nuniform float u_imageAspectRatio;\nuniform float u_spread;\nuniform float u_bias;\nuniform float u_angle;\nuniform float u_perspective;\nuniform float u_count;\nuniform float u_dispersion;\nuniform float u_dispersionShift;\nuniform float u_dispersionColor;\nuniform float u_focusCenter;\nuniform float u_focusEdges;\nuniform float u_swirl;\nuniform float u_noise;\nuniform float u_noiseFrequency;\nuniform float u_noiseOffset;\nuniform float u_lensBulge;\nuniform float u_lensCircle;\nuniform float u_grainMixer;\nuniform float u_grainOverlay;\nuniform float u_imageX;\nuniform float u_imageY;\n\nin vec2 v_imageUV;\n\nout vec4 fragColor;\n\n${declarePI}\n${proceduralHash21}\n${rotation2}\n\nfloat valueNoise(vec2 st) {\n vec2 i = floor(st);\n vec2 f = fract(st);\n float a = hash21(i);\n float b = hash21(i + vec2(1., 0.));\n float c = hash21(i + vec2(0., 1.));\n float d = hash21(i + vec2(1., 1.));\n vec2 u = f * f * (3. - 2. * f);\n return mix(mix(a, b, u.x), mix(c, d, u.x), u.y);\n}\n\nfloat getUvFrame(vec2 uv) {\n vec2 invAA = 1. / clamp(fwidth(uv), 1e-5, .02);\n vec2 lo = clamp(uv * invAA + .5, 0., 1.);\n vec2 hi = clamp((1. - uv) * invAA + .5, 0., 1.);\n return lo.x * hi.x * lo.y * hi.y;\n}\n\nvec4 sampleOverWhite(vec2 uv) {\n vec4 img = texture(u_image, uv);\n float cover = img.a * getUvFrame(uv);\n vec3 colorOverWhite = mix(vec3(1.), img.rgb, cover);\n return vec4(colorOverWhite, cover);\n}\n\nvec3 hueColor(float hue) {\n vec3 rgb = clamp(abs(mod(hue * 6. + vec3(0., 4., 2.), 6.) - 3.) - 1., 0., 1.);\n rgb = rgb * rgb * (3. - 2. * rgb);\n return rgb;\n}\n \nfloat boxInradius() {\n return .5 * min(u_imageAspectRatio, 1.);\n}\n\nfloat boxOutradius() {\n return .5 * length(vec2(u_imageAspectRatio, 1.));\n}\n\nfloat spreadReach() {\n return .7 * pow(u_spread, 1.3 + 2.7 * u_spread);\n}\n\nfloat innerCircleMask(float radius, float inradius) {\n return 1. - smoothstep(.5 * inradius, 1.1 * inradius, radius);\n}\n\nfloat dispersionCurve(float t, float biasPow) {\n float mirroredT = u_bias < 0. ? 1. - t : t;\n float curved = pow(mirroredT, biasPow);\n return u_bias < 0. ? 1. - curved : curved;\n}\n\nvec2 getSpread(vec2 fromCenter, float radius, vec2 warpedUV, float edgeAA, float inradius, float outradius, float reach, out float outStrength) {\n float angleRad = radians(u_angle);\n vec2 uniformDir = vec2(cos(angleRad), sin(angleRad));\n\n float invInradius = 1. / inradius;\n vec2 radialDir = fromCenter * invInradius;\n float maxLen = (outradius + reach) * invInradius;\n float radialLen = radius * invInradius;\n if (radialLen > maxLen) radialDir *= maxLen / radialLen;\n vec2 spreadDir = mix(uniformDir, radialDir, u_perspective);\n\n float bandProximity = smoothstep(inradius * .8, inradius, radius);\n float lensCircleMaxing = bandProximity * u_lensCircle * u_lensCircle * u_lensCircle;\n spreadDir = mix(spreadDir, radialDir, lensCircleMaxing);\n\n vec2 warpedAbs = abs(warpedUV - .5);\n float inner = mix(1., smoothstep(0., mix(inradius, outradius, u_focusCenter), radius), u_focusCenter);\n float boxDist = max(warpedAbs.x, warpedAbs.y) * 2.;\n float outer = mix(1., 1. - min(boxDist, 1.), u_focusEdges);\n float strength = inner * outer;\n\n strength *= mix(1., mix(.15, .03, max(-u_lensBulge, 0.)), lensCircleMaxing);\n\n vec2 outside = max(warpedAbs - .5, 0.);\n float margin = max(reach * length(spreadDir) * (1. - u_lensCircle), edgeAA);\n strength *= 1. - smoothstep(0., margin, length(outside));\n\n outStrength = strength;\n vec2 axis = spreadDir * (reach * strength);\n\n if (u_noise > 0.) {\n float turn = (valueNoise(fromCenter * u_noiseFrequency * 18. + u_noiseOffset * 30.) - .5) * 2. * u_noise;\n float cs = cos(turn), sn = sin(turn);\n axis = mat2(cs, -sn, sn, cs) * axis;\n }\n\n axis.x /= u_imageAspectRatio;\n return axis;\n}\n\nvec2 lensWarp(vec2 fromCenter, float radius, float inradius, out float bulgeFade) {\n bulgeFade = 1.;\n if (u_lensBulge == 0. && u_lensCircle <= 0.) return fromCenter;\n if (radius < 1e-5) return fromCenter;\n \n float r = radius;\n\n if (u_lensBulge != 0.) {\n float rn = radius / inradius;\n float bulge = abs(u_lensBulge) * (u_lensBulge > 0. ? 1.4 : 1.2);\n if (u_lensBulge > 0.) bulgeFade = 1. - smoothstep(1.45, 1.53, rn * bulge);\n float map = u_lensBulge > 0.\n ? tan(min(rn * bulge, 1.53)) / tan(bulge)\n : atan(rn * tan(bulge)) / bulge;\n float bulgeScale = map / rn;\n fromCenter *= bulgeScale;\n r *= bulgeScale;\n }\n\n if (u_lensCircle > 0.) {\n vec2 dir = fromCenter / max(r, 1e-5);\n vec2 halfBox = vec2(u_imageAspectRatio, 1.) * .5;\n float rBox = min(halfBox.x / max(abs(dir.x), 1e-4), halfBox.y / max(abs(dir.y), 1e-4));\n float band = inradius * mix(.03, .2, .5 * (u_lensBulge + 1.));\n float innerEdge = inradius - band;\n float over = smoothstep(0., 1., (r - innerEdge) / band);\n float g = r + (rBox - inradius) * pow(over, 14.);\n fromCenter = dir * mix(r, g, u_lensCircle);\n }\n\n return fromCenter;\n}\n\nvoid main() {\n vec2 uv = v_imageUV;\n\n float invAspect = 1. / u_imageAspectRatio;\n float inradius = boxInradius();\n float outradius = boxOutradius();\n float reach = spreadReach();\n\n vec2 fromCenter = uv - .5;\n fromCenter.x *= u_imageAspectRatio;\n float radius = length(fromCenter);\n\n float bulgeFade;\n vec2 warpedFromCenter = lensWarp(fromCenter, radius, inradius, bulgeFade);\n vec2 baseUV = vec2(warpedFromCenter.x * invAspect, warpedFromCenter.y) + .5;\n\n vec2 baseDerivative = fwidth(baseUV);\n float edgeAA = clamp(2. * max(baseDerivative.x, baseDerivative.y), .001, .02);\n\n float spreadStrength;\n vec2 spreadAxis = getSpread(fromCenter, radius, baseUV, edgeAA, inradius, outradius, reach, spreadStrength);\n\n vec2 grainUV = vec2(0.);\n if (u_grainMixer > 0. || u_grainOverlay > 0.) {\n vec2 dudx = dFdx(v_imageUV);\n vec2 dudy = dFdy(v_imageUV);\n grainUV = (v_imageUV - .5) * (.8 / vec2(length(dudx), length(dudy))) + .5;\n }\n\n if (u_grainMixer > 0.) {\n float grainSeed = valueNoise(grainUV);\n vec2 jit = fract(grainSeed * vec2(157.31, 113.57)) * 2. - 1.;\n spreadAxis += jit * .3 * u_grainMixer * length(spreadAxis);\n }\n\n float count = floor(u_count);\n int countInteger = int(count);\n\n float invCount = 1. / count;\n float invSpan = 1. / max(count - 1., 1.);\n float hueBase = u_dispersionColor + .5;\n float biasPower = 1. + 2. * abs(u_bias);\n vec2 tapBias = .5 - vec2(u_imageX, u_imageY);\n\n float centerAmount = clamp(1. - u_dispersionShift, 0., 1.);\n float edgesAmount = clamp(1. + u_dispersionShift, 0., 1.);\n float dispersion = u_dispersion * mix(edgesAmount, centerAmount, innerCircleMask(radius, inradius));\n float dispersionPower = pow(dispersion, .8);\n\n float warpedRadius = length(warpedFromCenter);\n float swirlAngle = u_swirl * .4 * PI * spreadStrength * u_spread * min(1., inradius / max(warpedRadius, 1e-4));\n\n vec3 colorSum = vec3(0.);\n vec3 weightSum = vec3(0.);\n float coverSum = 0.;\n\n for (int i = 0; i < ${lensDistortionMeta.maxSamples}; i++) {\n if (i >= countInteger) break;\n\n float layer = float(i);\n float hue = hueBase + layer * invCount;\n\n float spread = layer * invSpan;\n if (u_bias != 0.) spread = dispersionCurve(spread, biasPower);\n\n // mix(axis, -axis, spread) is axis scaled by the signed position along the fan\n float fanPos = 1. - 2. * spread;\n vec2 tapUV = baseUV + spreadAxis * fanPos - .5;\n\n if (u_swirl != 0.) {\n tapUV.x *= u_imageAspectRatio;\n tapUV = rotate(tapUV, swirlAngle * fanPos);\n tapUV.x *= invAspect;\n }\n\n vec4 tap = sampleOverWhite(tapUV + tapBias);\n vec3 weight = 1. - dispersionPower * hueColor(hue);\n\n colorSum += tap.rgb * weight;\n weightSum += weight;\n coverSum += tap.a;\n }\n\n vec3 color = colorSum / max(weightSum, 1e-4);\n float coverAvg = coverSum * invCount;\n\n float ground = min(color.r, min(color.g, color.b));\n float alpha = max(coverAvg, 1. - ground);\n vec3 premult = max(color - (1. - alpha), 0.);\n fragColor = vec4(premult, alpha) * bulgeFade;\n\n if (u_grainOverlay > 0.) {\n float grain = valueNoise(rotate(grainUV, 1.) + vec2(3.));\n grain = mix(grain, valueNoise(rotate(grainUV, 2.) + vec2(-1.)), .5);\n grain = pow(grain, 1.3);\n float grainV = grain * 2. - 1.;\n float grainStrength = pow(u_grainOverlay * abs(grainV), .8) * fragColor.a;\n fragColor.rgb = mix(fragColor.rgb, vec3(step(0., grainV)) * fragColor.a, .35 * grainStrength);\n }\n}\n`;\n\nexport interface LensDistortionUniforms extends ShaderSizingUniforms {\n u_image: HTMLImageElement | string | undefined;\n u_spread: number;\n u_bias: number;\n u_angle: number;\n u_perspective: number;\n u_count: number;\n u_dispersion: number;\n u_dispersionShift: number;\n u_dispersionColor: number;\n u_focusCenter: number;\n u_focusEdges: number;\n u_swirl: number;\n u_noise: number;\n u_noiseFrequency: number;\n u_noiseOffset: number;\n u_lensBulge: number;\n u_lensCircle: number;\n u_grainMixer: number;\n u_grainOverlay: number;\n u_imageX: number;\n u_imageY: number;\n}\n\nexport interface LensDistortionParams extends ShaderSizingParams, ShaderMotionParams {\n image?: HTMLImageElement | string;\n spread?: number;\n bias?: number;\n angle?: number;\n perspective?: number;\n count?: number;\n dispersion?: number;\n dispersionShift?: number;\n dispersionColor?: number;\n focusCenter?: number;\n focusEdges?: number;\n swirl?: number;\n noise?: number;\n noiseFrequency?: number;\n noiseOffset?: number;\n lensBulge?: number;\n lensCircle?: number;\n grainMixer?: number;\n grainOverlay?: number;\n imageX?: number;\n imageY?: number;\n}\n"], + "mappings": ";;;;;AACA,eAAmE;AACnE,SAAS,WAAW,kBAAkB,iBAAiB;AAEhD,MAAM,qBAAqB;AAAA,EAChC,YAAY;AACd;AAiDO,MAAM,+BAAuC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA8BlD,SAAS;AAAA,EACT,gBAAgB;AAAA,EAChB,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAwLa,mBAAmB,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;", + "names": [] +} diff --git a/public/vendor/paper-shaders/shaders/liquid-metal.d.ts b/public/vendor/paper-shaders/shaders/liquid-metal.d.ts new file mode 100644 index 0000000..fd09ed5 --- /dev/null +++ b/public/vendor/paper-shaders/shaders/liquid-metal.d.ts @@ -0,0 +1,90 @@ +import type { ShaderMotionParams } from '../shader-mount.js'; +import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js'; +/** + * Futuristic liquid metal material applied to uploaded logo or abstract shape. + * Fluid motion imitation applied over user image with animated stripe pattern + * getting distorted along shape edges. + * + * Fragment shader uniforms: + * - u_time (float): Animation time + * - u_resolution (vec2): Canvas resolution in pixels + * - u_image (sampler2D): Pre-processed source image texture (R = edge gradient, G = opacity) + * - u_imageAspectRatio (float): Aspect ratio of the source image + * - u_colorBack (vec4): Background color in RGBA + * - u_colorTint (vec4): Overlay color in RGBA (color burn blending used) + * - u_repetition (float): Density of pattern stripes (1 to 10) + * - u_softness (float): Color transition sharpness, 0 = hard edge, 1 = smooth gradient (0 to 1) + * - u_shiftRed (float): R-channel dispersion (-1 to 1) + * - u_shiftBlue (float): B-channel dispersion (-1 to 1) + * - u_distortion (float): Noise distortion over the stripes pattern (0 to 1) + * - u_contour (float): Strength of the distortion on the shape edges (0 to 1) + * - u_angle (float): Direction of pattern animation in degrees (0 to 360) + * - u_shape (float): Predefined shape when no image provided (0 = none, 1 = circle, 2 = daisy, 3 = diamond, 4 = metaballs) + * - u_isImage (bool): Whether an image is being used as the effect mask + * + * Vertex shader outputs (used in fragment shader): + * - v_imageUV (vec2): UV coordinates for sampling the source image, with fit, scale, rotation, and offset applied + * - v_objectUV (vec2): Object box UV coordinates with global sizing (scale, rotation, offsets, etc) applied (used when no image) + * - v_responsiveUV (vec2): Responsive UV coordinates that adapt to canvas aspect ratio (used for canvas-fill mode) + * - v_responsiveBoxGivenSize (vec2): TBD + * + * Vertex shader uniforms: + * - u_resolution (vec2): Canvas resolution in pixels + * - u_pixelRatio (float): Device pixel ratio + * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1) + * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1) + * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas + * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas + * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover) + * - u_scale (float): Overall zoom level of the graphics (0.01 to 4) + * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360) + * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1) + * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1) + * - u_imageAspectRatio (float): Aspect ratio of the source image + * + */ +export declare const liquidMetalFragmentShader: string; +export declare const POISSON_CONFIG_OPTIMIZED: { + measurePerformance: boolean; + workingSize: number; + iterations: number; +}; +export declare function toProcessedLiquidMetal(file: File | string): Promise<{ + imageData: ImageData; + pngBlob: Blob; +}>; +export interface LiquidMetalUniforms extends ShaderSizingUniforms { + u_colorBack: [number, number, number, number]; + u_colorTint: [number, number, number, number]; + u_image: HTMLImageElement | string | undefined; + u_repetition: number; + u_shiftRed: number; + u_shiftBlue: number; + u_contour: number; + u_softness: number; + u_distortion: number; + u_angle: number; + u_shape: (typeof LiquidMetalShapes)[LiquidMetalShape]; + u_isImage: boolean; +} +export interface LiquidMetalParams extends ShaderSizingParams, ShaderMotionParams { + colorBack?: string; + colorTint?: string; + image?: HTMLImageElement | string | undefined; + repetition?: number; + shiftRed?: number; + shiftBlue?: number; + contour?: number; + softness?: number; + distortion?: number; + angle?: number; + shape?: LiquidMetalShape; +} +export declare const LiquidMetalShapes: { + readonly none: 0; + readonly circle: 1; + readonly daisy: 2; + readonly diamond: 3; + readonly metaballs: 4; +}; +export type LiquidMetalShape = keyof typeof LiquidMetalShapes; diff --git a/public/vendor/paper-shaders/shaders/liquid-metal.js b/public/vendor/paper-shaders/shaders/liquid-metal.js new file mode 100644 index 0000000..31fb3ea --- /dev/null +++ b/public/vendor/paper-shaders/shaders/liquid-metal.js @@ -0,0 +1,630 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Paper Shaders * + * https://github.com/paper-design/shaders * + * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +import {} from "../shader-sizing.js"; +import { declarePI, rotation2, simplexNoise, colorBandingFix } from "../shader-utils.js"; +const liquidMetalFragmentShader = `#version 300 es +precision mediump float; + +uniform sampler2D u_image; +uniform float u_imageAspectRatio; + +uniform vec2 u_resolution; +uniform float u_time; + +uniform vec4 u_colorBack; +uniform vec4 u_colorTint; + +uniform float u_softness; +uniform float u_repetition; +uniform float u_shiftRed; +uniform float u_shiftBlue; +uniform float u_distortion; +uniform float u_contour; +uniform float u_angle; + +uniform float u_shape; +uniform bool u_isImage; + +in vec2 v_objectUV; +in vec2 v_responsiveUV; +in vec2 v_responsiveBoxGivenSize; +in vec2 v_imageUV; + +out vec4 fragColor; + +${declarePI} +${rotation2} +${simplexNoise} + +float getColorChanges(float c1, float c2, float stripe_p, vec3 w, float blur, float bump, float tint) { + + float ch = mix(c2, c1, smoothstep(.0, 2. * blur, stripe_p)); + + float border = w[0]; + ch = mix(ch, c2, smoothstep(border, border + 2. * blur, stripe_p)); + + if (u_isImage == true) { + bump = smoothstep(.2, .8, bump); + } + border = w[0] + .4 * (1. - bump) * w[1]; + ch = mix(ch, c1, smoothstep(border, border + 2. * blur, stripe_p)); + + border = w[0] + .5 * (1. - bump) * w[1]; + ch = mix(ch, c2, smoothstep(border, border + 2. * blur, stripe_p)); + + border = w[0] + w[1]; + ch = mix(ch, c1, smoothstep(border, border + 2. * blur, stripe_p)); + + float gradient_t = (stripe_p - w[0] - w[1]) / w[2]; + float gradient = mix(c1, c2, smoothstep(0., 1., gradient_t)); + ch = mix(ch, gradient, smoothstep(border, border + .5 * blur, stripe_p)); + + // Tint color is applied with color burn blending + ch = mix(ch, 1. - min(1., (1. - ch) / max(tint, 0.0001)), u_colorTint.a); + return ch; +} + +float getImgFrame(vec2 uv, float th) { + float frame = 1.; + frame *= smoothstep(0., th, uv.y); + frame *= 1.0 - smoothstep(1. - th, 1., uv.y); + frame *= smoothstep(0., th, uv.x); + frame *= 1.0 - smoothstep(1. - th, 1., uv.x); + return frame; +} + +float blurEdge3x3(sampler2D tex, vec2 uv, vec2 dudx, vec2 dudy, float radius, float centerSample) { + vec2 texel = 1.0 / vec2(textureSize(tex, 0)); + vec2 r = radius * texel; + + float w1 = 1.0, w2 = 2.0, w4 = 4.0; + float norm = 16.0; + float sum = w4 * centerSample; + + sum += w2 * textureGrad(tex, uv + vec2(0.0, -r.y), dudx, dudy).r; + sum += w2 * textureGrad(tex, uv + vec2(0.0, r.y), dudx, dudy).r; + sum += w2 * textureGrad(tex, uv + vec2(-r.x, 0.0), dudx, dudy).r; + sum += w2 * textureGrad(tex, uv + vec2(r.x, 0.0), dudx, dudy).r; + + sum += w1 * textureGrad(tex, uv + vec2(-r.x, -r.y), dudx, dudy).r; + sum += w1 * textureGrad(tex, uv + vec2(r.x, -r.y), dudx, dudy).r; + sum += w1 * textureGrad(tex, uv + vec2(-r.x, r.y), dudx, dudy).r; + sum += w1 * textureGrad(tex, uv + vec2(r.x, r.y), dudx, dudy).r; + + return sum / norm; +} + +float lst(float edge0, float edge1, float x) { + return clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0); +} + +void main() { + + const float firstFrameOffset = 2.8; + float t = .3 * (u_time + firstFrameOffset); + + vec2 uv = v_imageUV; + vec2 dudx = dFdx(v_imageUV); + vec2 dudy = dFdy(v_imageUV); + vec4 img = textureGrad(u_image, uv, dudx, dudy); + + if (u_isImage == false) { + uv = v_objectUV + .5; + uv.y = 1. - uv.y; + } + + float cycleWidth = u_repetition; + float edge = 0.; + float contOffset = 1.; + + vec2 rotatedUV = uv - vec2(.5); + float angle = (-u_angle + 70.) * PI / 180.; + float cosA = cos(angle); + float sinA = sin(angle); + rotatedUV = vec2( + rotatedUV.x * cosA - rotatedUV.y * sinA, + rotatedUV.x * sinA + rotatedUV.y * cosA + ) + vec2(.5); + + if (u_isImage == true) { + float edgeRaw = img.r; + edge = blurEdge3x3(u_image, uv, dudx, dudy, 6., edgeRaw); + edge = pow(edge, 1.6); + edge *= mix(0.0, 1.0, smoothstep(0.0, 0.4, u_contour)); + } else { + if (u_shape < 1.) { + // full-fill on canvas + vec2 borderUV = v_responsiveUV + .5; + float ratio = v_responsiveBoxGivenSize.x / v_responsiveBoxGivenSize.y; + vec2 mask = min(borderUV, 1. - borderUV); + vec2 pixel_thickness = min(250. / v_responsiveBoxGivenSize, vec2(.5)); + float maskX = smoothstep(0.0, pixel_thickness.x, mask.x); + float maskY = smoothstep(0.0, pixel_thickness.y, mask.y); + maskX = pow(maskX, .25); + maskY = pow(maskY, .25); + edge = clamp(1. - maskX * maskY, 0., 1.); + + uv = v_responsiveUV; + if (ratio > 1.) { + uv.y /= ratio; + } else { + uv.x *= ratio; + } + uv += .5; + uv.y = 1. - uv.y; + + cycleWidth *= 2.; + contOffset = 1.5; + + } else if (u_shape < 2.) { + // circle + vec2 shapeUV = uv - .5; + shapeUV *= .67; + edge = pow(clamp(3. * length(shapeUV), 0., 1.), 18.); + } else if (u_shape < 3.) { + // daisy + vec2 shapeUV = uv - .5; + shapeUV *= 1.68; + + float r = length(shapeUV) * 2.; + float a = atan(shapeUV.y, shapeUV.x) + .2; + r *= (1. + .05 * sin(3. * a + 2. * t)); + float f = abs(cos(a * 3.)); + edge = smoothstep(f, f + .7, r); + edge *= edge; + + uv *= .8; + cycleWidth *= 1.6; + + } else if (u_shape < 4.) { + // diamond + vec2 shapeUV = uv - .5; + shapeUV = rotate(shapeUV, .25 * PI); + shapeUV *= 1.42; + shapeUV += .5; + vec2 mask = min(shapeUV, 1. - shapeUV); + vec2 pixel_thickness = vec2(.15); + float maskX = smoothstep(0.0, pixel_thickness.x, mask.x); + float maskY = smoothstep(0.0, pixel_thickness.y, mask.y); + maskX = pow(maskX, .25); + maskY = pow(maskY, .25); + edge = clamp(1. - maskX * maskY, 0., 1.); + } else if (u_shape < 5.) { + // metaballs + vec2 shapeUV = uv - .5; + shapeUV *= 1.3; + edge = 0.; + for (int i = 0; i < 5; i++) { + float fi = float(i); + float speed = 1.5 + 2./3. * sin(fi * 12.345); + float angle = -fi * 1.5; + vec2 dir1 = vec2(cos(angle), sin(angle)); + vec2 dir2 = vec2(cos(angle + 1.57), sin(angle + 1.)); + vec2 traj = .4 * (dir1 * sin(t * speed + fi * 1.23) + dir2 * cos(t * (speed * 0.7) + fi * 2.17)); + float d = length(shapeUV + traj); + edge += pow(1.0 - clamp(d, 0.0, 1.0), 4.0); + } + edge = 1. - smoothstep(.65, .9, edge); + edge = pow(edge, 4.); + } + + edge = mix(smoothstep(.9 - 2. * fwidth(edge), .9, edge), edge, smoothstep(0.0, 0.4, u_contour)); + + } + + float opacity = 0.; + if (u_isImage == true) { + opacity = img.g; + float frame = getImgFrame(v_imageUV, 0.); + opacity *= frame; + } else { + opacity = 1. - smoothstep(.9 - 2. * fwidth(edge), .9, edge); + if (u_shape < 2.) { + edge = 1.2 * edge; + } else if (u_shape < 5.) { + edge = 1.8 * pow(edge, 1.5); + } + } + + float diagBLtoTR = rotatedUV.x - rotatedUV.y; + float diagTLtoBR = rotatedUV.x + rotatedUV.y; + + vec3 color = vec3(0.); + vec3 color1 = vec3(.98, 0.98, 1.); + vec3 color2 = vec3(.1, .1, .1 + .1 * smoothstep(.7, 1.3, diagTLtoBR)); + + vec2 grad_uv = uv - .5; + + float dist = length(grad_uv + vec2(0., .2 * diagBLtoTR)); + grad_uv = rotate(grad_uv, (.25 - .2 * diagBLtoTR) * PI); + float direction = grad_uv.x; + + float bump = pow(1.8 * dist, 1.2); + bump = 1. - bump; + bump *= pow(uv.y, .3); + + + float thin_strip_1_ratio = .12 / cycleWidth * (1. - .4 * bump); + float thin_strip_2_ratio = .07 / cycleWidth * (1. + .4 * bump); + float wide_strip_ratio = (1. - thin_strip_1_ratio - thin_strip_2_ratio); + + float thin_strip_1_width = cycleWidth * thin_strip_1_ratio; + float thin_strip_2_width = cycleWidth * thin_strip_2_ratio; + + float noise = snoise(uv - t); + + edge += (1. - edge) * u_distortion * noise; + + direction += diagBLtoTR; + float contour = 0.; + direction -= 2. * noise * diagBLtoTR * (smoothstep(0., 1., edge) * (1.0 - smoothstep(0., 1., edge))); + direction *= mix(1., 1. - edge, smoothstep(.5, 1., u_contour)); + direction -= 1.7 * edge * smoothstep(.5, 1., u_contour); + direction += .2 * pow(u_contour, 4.) * (1.0 - smoothstep(0., 1., edge)); + + bump *= clamp(pow(uv.y, .1), .3, 1.); + direction *= (.1 + (1.1 - edge) * bump); + + direction *= (.4 + .6 * (1.0 - smoothstep(.5, 1., edge))); + direction += .18 * (smoothstep(.1, .2, uv.y) * (1.0 - smoothstep(.2, .4, uv.y))); + direction += .03 * (smoothstep(.1, .2, 1. - uv.y) * (1.0 - smoothstep(.2, .4, 1. - uv.y))); + + direction *= (.5 + .5 * pow(uv.y, 2.)); + direction *= cycleWidth; + direction -= t; + + + float colorDispersion = (1. - bump); + colorDispersion = clamp(colorDispersion, 0., 1.); + float dispersionRed = colorDispersion; + dispersionRed += .03 * bump * noise; + dispersionRed += 5. * (smoothstep(-.1, .2, uv.y) * (1.0 - smoothstep(.1, .5, uv.y))) * (smoothstep(.4, .6, bump) * (1.0 - smoothstep(.4, 1., bump))); + dispersionRed -= diagBLtoTR; + + float dispersionBlue = colorDispersion; + dispersionBlue *= 1.3; + dispersionBlue += (smoothstep(0., .4, uv.y) * (1.0 - smoothstep(.1, .8, uv.y))) * (smoothstep(.4, .6, bump) * (1.0 - smoothstep(.4, .8, bump))); + dispersionBlue -= .2 * edge; + + dispersionRed *= (u_shiftRed / 20.); + dispersionBlue *= (u_shiftBlue / 20.); + + float blur = 0.; + float rExtraBlur = 0.; + float gExtraBlur = 0.; + if (u_isImage == true) { + float softness = 0.05 * u_softness; + blur = softness + .5 * smoothstep(1., 10., u_repetition) * smoothstep(.0, 1., edge); + float smallCanvasT = 1.0 - smoothstep(100., 500., min(u_resolution.x, u_resolution.y)); + blur += smallCanvasT * smoothstep(.0, 1., edge); + rExtraBlur = softness * (0.05 + .1 * (u_shiftRed / 20.) * bump); + gExtraBlur = softness * 0.05 / max(0.001, abs(1. - diagBLtoTR)); + } else { + blur = u_softness / 15. + .3 * contour; + } + + vec3 w = vec3(thin_strip_1_width, thin_strip_2_width, wide_strip_ratio); + w[1] -= .02 * smoothstep(.0, 1., edge + bump); + float stripe_r = fract(direction + dispersionRed); + float r = getColorChanges(color1.r, color2.r, stripe_r, w, blur + fwidth(stripe_r) + rExtraBlur, bump, u_colorTint.r); + float stripe_g = fract(direction); + float g = getColorChanges(color1.g, color2.g, stripe_g, w, blur + fwidth(stripe_g) + gExtraBlur, bump, u_colorTint.g); + float stripe_b = fract(direction - dispersionBlue); + float b = getColorChanges(color1.b, color2.b, stripe_b, w, blur + fwidth(stripe_b), bump, u_colorTint.b); + + color = vec3(r, g, b); + color *= opacity; + + vec3 bgColor = u_colorBack.rgb * u_colorBack.a; + color = color + bgColor * (1. - opacity); + opacity = opacity + u_colorBack.a * (1. - opacity); + + ${colorBandingFix} + + fragColor = vec4(color, opacity); +} +`; +const POISSON_CONFIG_OPTIMIZED = { + measurePerformance: false, + // Set to true to see performance metrics + workingSize: 512, + // Size to solve Poisson at (will upscale to original size) + iterations: 40 + // SOR converges ~2-20x faster than standard Gauss-Seidel +}; +function toProcessedLiquidMetal(file) { + const canvas = document.createElement("canvas"); + const ctx = canvas.getContext("2d"); + const isBlob = typeof file === "string" && file.startsWith("blob:"); + return new Promise((resolve, reject) => { + if (!file || !ctx) { + reject(new Error("Invalid file or canvas context")); + return; + } + const blobContentTypePromise = isBlob && fetch(file).then((res) => res.headers.get("Content-Type")); + const img = new Image(); + img.crossOrigin = "anonymous"; + const totalStartTime = performance.now(); + img.onload = async () => { + let isSVG; + const blobContentType = await blobContentTypePromise; + if (blobContentType) { + isSVG = blobContentType === "image/svg+xml"; + } else if (typeof file === "string") { + isSVG = file.endsWith(".svg") || file.startsWith("data:image/svg+xml"); + } else { + isSVG = file.type === "image/svg+xml"; + } + let originalWidth = img.width || img.naturalWidth; + let originalHeight = img.height || img.naturalHeight; + if (isSVG) { + const svgMaxSize = 4096; + const aspectRatio = originalWidth / originalHeight; + if (originalWidth > originalHeight) { + originalWidth = svgMaxSize; + originalHeight = svgMaxSize / aspectRatio; + } else { + originalHeight = svgMaxSize; + originalWidth = svgMaxSize * aspectRatio; + } + img.width = originalWidth; + img.height = originalHeight; + } + const minDimension = Math.min(originalWidth, originalHeight); + const targetSize = POISSON_CONFIG_OPTIMIZED.workingSize; + const scaleFactor = targetSize / minDimension; + const width = Math.round(originalWidth * scaleFactor); + const height = Math.round(originalHeight * scaleFactor); + if (POISSON_CONFIG_OPTIMIZED.measurePerformance) { + console.log(`[Processing Mode]`); + console.log(` Original: ${originalWidth}\xD7${originalHeight}`); + console.log(` Working: ${width}\xD7${height} (${(scaleFactor * 100).toFixed(1)}% scale)`); + if (scaleFactor < 1) { + console.log(` Speedup: ~${Math.round(1 / (scaleFactor * scaleFactor))}\xD7`); + } + } + canvas.width = originalWidth; + canvas.height = originalHeight; + const shapeCanvas = document.createElement("canvas"); + shapeCanvas.width = width; + shapeCanvas.height = height; + const shapeCtx = shapeCanvas.getContext("2d"); + shapeCtx.drawImage(img, 0, 0, width, height); + const startMask = performance.now(); + const shapeImageData = shapeCtx.getImageData(0, 0, width, height); + const data = shapeImageData.data; + const shapeMask = new Uint8Array(width * height); + const boundaryMask = new Uint8Array(width * height); + let shapePixelCount = 0; + for (let i = 0, idx = 0; i < data.length; i += 4, idx++) { + const a = data[i + 3]; + const isShape = a === 0 ? 0 : 1; + shapeMask[idx] = isShape; + shapePixelCount += isShape; + } + const boundaryIndices = []; + const interiorIndices = []; + for (let y = 0; y < height; y++) { + for (let x = 0; x < width; x++) { + const idx = y * width + x; + if (!shapeMask[idx]) continue; + let isBoundary = false; + if (x === 0 || x === width - 1 || y === 0 || y === height - 1) { + isBoundary = true; + } else { + isBoundary = !shapeMask[idx - 1] || // left + !shapeMask[idx + 1] || // right + !shapeMask[idx - width] || // top + !shapeMask[idx + width] || // bottom + !shapeMask[idx - width - 1] || // top-left + !shapeMask[idx - width + 1] || // top-right + !shapeMask[idx + width - 1] || // bottom-left + !shapeMask[idx + width + 1]; + } + if (isBoundary) { + boundaryMask[idx] = 1; + boundaryIndices.push(idx); + } else { + interiorIndices.push(idx); + } + } + } + if (POISSON_CONFIG_OPTIMIZED.measurePerformance) { + console.log(`[Mask Building] Time: ${(performance.now() - startMask).toFixed(2)}ms`); + console.log( + ` Shape pixels: ${shapePixelCount} / ${width * height} (${(shapePixelCount / (width * height) * 100).toFixed(1)}%)` + ); + console.log(` Interior pixels: ${interiorIndices.length}`); + console.log(` Boundary pixels: ${boundaryIndices.length}`); + } + const sparseData = buildSparseData( + shapeMask, + boundaryMask, + new Uint32Array(interiorIndices), + new Uint32Array(boundaryIndices), + width, + height + ); + const startSolve = performance.now(); + const u = solvePoissonSparse(sparseData, shapeMask, boundaryMask, width, height); + if (POISSON_CONFIG_OPTIMIZED.measurePerformance) { + console.log(`[Poisson Solve] Time: ${(performance.now() - startSolve).toFixed(2)}ms`); + } + let maxVal = 0; + let finalImageData; + for (let i = 0; i < interiorIndices.length; i++) { + const idx = interiorIndices[i]; + if (u[idx] > maxVal) maxVal = u[idx]; + } + const tempCanvas = document.createElement("canvas"); + tempCanvas.width = width; + tempCanvas.height = height; + const tempCtx = tempCanvas.getContext("2d"); + const tempImg = tempCtx.createImageData(width, height); + for (let y = 0; y < height; y++) { + for (let x = 0; x < width; x++) { + const idx = y * width + x; + const px = idx * 4; + if (!shapeMask[idx]) { + tempImg.data[px] = 255; + tempImg.data[px + 1] = 255; + tempImg.data[px + 2] = 255; + tempImg.data[px + 3] = 0; + } else { + const poissonRatio = u[idx] / maxVal; + const gray = 255 * (1 - poissonRatio); + tempImg.data[px] = gray; + tempImg.data[px + 1] = gray; + tempImg.data[px + 2] = gray; + tempImg.data[px + 3] = 255; + } + } + } + tempCtx.putImageData(tempImg, 0, 0); + ctx.imageSmoothingEnabled = true; + ctx.imageSmoothingQuality = "high"; + ctx.drawImage(tempCanvas, 0, 0, width, height, 0, 0, originalWidth, originalHeight); + const outImg = ctx.getImageData(0, 0, originalWidth, originalHeight); + const originalCanvas = document.createElement("canvas"); + originalCanvas.width = originalWidth; + originalCanvas.height = originalHeight; + const originalCtx = originalCanvas.getContext("2d"); + originalCtx.drawImage(img, 0, 0, originalWidth, originalHeight); + const originalData = originalCtx.getImageData(0, 0, originalWidth, originalHeight); + for (let i = 0; i < outImg.data.length; i += 4) { + const a = originalData.data[i + 3]; + const upscaledAlpha = outImg.data[i + 3]; + if (a === 0) { + outImg.data[i] = 255; + outImg.data[i + 1] = 0; + } else { + outImg.data[i] = upscaledAlpha === 0 ? 0 : outImg.data[i]; + outImg.data[i + 1] = a; + } + outImg.data[i + 2] = 255; + outImg.data[i + 3] = 255; + } + ctx.putImageData(outImg, 0, 0); + finalImageData = outImg; + canvas.toBlob((blob) => { + if (!blob) { + reject(new Error("Failed to create PNG blob")); + return; + } + if (POISSON_CONFIG_OPTIMIZED.measurePerformance) { + const totalTime = performance.now() - totalStartTime; + console.log(`[Total Processing Time] ${totalTime.toFixed(2)}ms`); + if (scaleFactor < 1) { + const estimatedFullResTime = totalTime * Math.pow(originalWidth * originalHeight / (width * height), 1.5); + console.log(`[Estimated time at full resolution] ~${estimatedFullResTime.toFixed(0)}ms`); + console.log( + `[Time saved] ~${(estimatedFullResTime - totalTime).toFixed(0)}ms (${Math.round(estimatedFullResTime / totalTime)}\xD7 faster)` + ); + } + } + resolve({ + imageData: finalImageData, + pngBlob: blob + }); + }, "image/png"); + }; + img.onerror = () => reject(new Error("Failed to load image")); + img.src = typeof file === "string" ? file : URL.createObjectURL(file); + }); +} +function buildSparseData(shapeMask, boundaryMask, interiorPixels, boundaryPixels, width, height) { + const pixelCount = interiorPixels.length; + const neighborIndices = new Int32Array(pixelCount * 4); + for (let i = 0; i < pixelCount; i++) { + const idx = interiorPixels[i]; + const x = idx % width; + const y = Math.floor(idx / width); + neighborIndices[i * 4 + 0] = x < width - 1 && shapeMask[idx + 1] ? idx + 1 : -1; + neighborIndices[i * 4 + 1] = x > 0 && shapeMask[idx - 1] ? idx - 1 : -1; + neighborIndices[i * 4 + 2] = y > 0 && shapeMask[idx - width] ? idx - width : -1; + neighborIndices[i * 4 + 3] = y < height - 1 && shapeMask[idx + width] ? idx + width : -1; + } + return { + interiorPixels, + boundaryPixels, + pixelCount, + neighborIndices + }; +} +function solvePoissonSparse(sparseData, shapeMask, boundaryMask, width, height) { + const ITERATIONS = POISSON_CONFIG_OPTIMIZED.iterations; + const C = 0.01; + const u = new Float32Array(width * height); + const { interiorPixels, neighborIndices, pixelCount } = sparseData; + const startTime = performance.now(); + const omega = 1.9; + const redPixels = []; + const blackPixels = []; + for (let i = 0; i < pixelCount; i++) { + const idx = interiorPixels[i]; + const x = idx % width; + const y = Math.floor(idx / width); + if ((x + y) % 2 === 0) { + redPixels.push(i); + } else { + blackPixels.push(i); + } + } + for (let iter = 0; iter < ITERATIONS; iter++) { + for (const i of redPixels) { + const idx = interiorPixels[i]; + const eastIdx = neighborIndices[i * 4 + 0]; + const westIdx = neighborIndices[i * 4 + 1]; + const northIdx = neighborIndices[i * 4 + 2]; + const southIdx = neighborIndices[i * 4 + 3]; + let sumN = 0; + if (eastIdx >= 0) sumN += u[eastIdx]; + if (westIdx >= 0) sumN += u[westIdx]; + if (northIdx >= 0) sumN += u[northIdx]; + if (southIdx >= 0) sumN += u[southIdx]; + const newValue = (C + sumN) / 4; + u[idx] = omega * newValue + (1 - omega) * u[idx]; + } + for (const i of blackPixels) { + const idx = interiorPixels[i]; + const eastIdx = neighborIndices[i * 4 + 0]; + const westIdx = neighborIndices[i * 4 + 1]; + const northIdx = neighborIndices[i * 4 + 2]; + const southIdx = neighborIndices[i * 4 + 3]; + let sumN = 0; + if (eastIdx >= 0) sumN += u[eastIdx]; + if (westIdx >= 0) sumN += u[westIdx]; + if (northIdx >= 0) sumN += u[northIdx]; + if (southIdx >= 0) sumN += u[southIdx]; + const newValue = (C + sumN) / 4; + u[idx] = omega * newValue + (1 - omega) * u[idx]; + } + } + if (POISSON_CONFIG_OPTIMIZED.measurePerformance) { + const elapsed = performance.now() - startTime; + console.log(`[Optimized Poisson Solver (SOR \u03C9=${omega})]`); + console.log(` Working size: ${width}\xD7${height}`); + console.log(` Iterations: ${ITERATIONS}`); + console.log(` Time: ${elapsed.toFixed(2)}ms`); + console.log(` Interior pixels processed: ${pixelCount}`); + console.log(` Speed: ${(ITERATIONS * pixelCount / (elapsed * 1e3)).toFixed(2)} Mpixels/sec`); + } + return u; +} +const LiquidMetalShapes = { + none: 0, + circle: 1, + daisy: 2, + diamond: 3, + metaballs: 4 +}; +export { + LiquidMetalShapes, + POISSON_CONFIG_OPTIMIZED, + liquidMetalFragmentShader, + toProcessedLiquidMetal +}; +//# sourceMappingURL=liquid-metal.js.map diff --git a/public/vendor/paper-shaders/shaders/liquid-metal.js.map b/public/vendor/paper-shaders/shaders/liquid-metal.js.map new file mode 100644 index 0000000..1cdd58b --- /dev/null +++ b/public/vendor/paper-shaders/shaders/liquid-metal.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../../src/shaders/liquid-metal.ts"], + "sourcesContent": ["import type { ShaderMotionParams } from '../shader-mount.js';\nimport { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { declarePI, rotation2, simplexNoise, colorBandingFix } from '../shader-utils.js';\n\n/**\n * Futuristic liquid metal material applied to uploaded logo or abstract shape.\n * Fluid motion imitation applied over user image with animated stripe pattern\n * getting distorted along shape edges.\n *\n * Fragment shader uniforms:\n * - u_time (float): Animation time\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_image (sampler2D): Pre-processed source image texture (R = edge gradient, G = opacity)\n * - u_imageAspectRatio (float): Aspect ratio of the source image\n * - u_colorBack (vec4): Background color in RGBA\n * - u_colorTint (vec4): Overlay color in RGBA (color burn blending used)\n * - u_repetition (float): Density of pattern stripes (1 to 10)\n * - u_softness (float): Color transition sharpness, 0 = hard edge, 1 = smooth gradient (0 to 1)\n * - u_shiftRed (float): R-channel dispersion (-1 to 1)\n * - u_shiftBlue (float): B-channel dispersion (-1 to 1)\n * - u_distortion (float): Noise distortion over the stripes pattern (0 to 1)\n * - u_contour (float): Strength of the distortion on the shape edges (0 to 1)\n * - u_angle (float): Direction of pattern animation in degrees (0 to 360)\n * - u_shape (float): Predefined shape when no image provided (0 = none, 1 = circle, 2 = daisy, 3 = diamond, 4 = metaballs)\n * - u_isImage (bool): Whether an image is being used as the effect mask\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_imageUV (vec2): UV coordinates for sampling the source image, with fit, scale, rotation, and offset applied\n * - v_objectUV (vec2): Object box UV coordinates with global sizing (scale, rotation, offsets, etc) applied (used when no image)\n * - v_responsiveUV (vec2): Responsive UV coordinates that adapt to canvas aspect ratio (used for canvas-fill mode)\n * - v_responsiveBoxGivenSize (vec2): TBD\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n * - u_imageAspectRatio (float): Aspect ratio of the source image\n *\n */\n\n// language=GLSL\nexport const liquidMetalFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform sampler2D u_image;\nuniform float u_imageAspectRatio;\n\nuniform vec2 u_resolution;\nuniform float u_time;\n\nuniform vec4 u_colorBack;\nuniform vec4 u_colorTint;\n\nuniform float u_softness;\nuniform float u_repetition;\nuniform float u_shiftRed;\nuniform float u_shiftBlue;\nuniform float u_distortion;\nuniform float u_contour;\nuniform float u_angle;\n\nuniform float u_shape;\nuniform bool u_isImage;\n\nin vec2 v_objectUV;\nin vec2 v_responsiveUV;\nin vec2 v_responsiveBoxGivenSize;\nin vec2 v_imageUV;\n\nout vec4 fragColor;\n\n${ declarePI }\n${ rotation2 }\n${ simplexNoise }\n\nfloat getColorChanges(float c1, float c2, float stripe_p, vec3 w, float blur, float bump, float tint) {\n\n float ch = mix(c2, c1, smoothstep(.0, 2. * blur, stripe_p));\n\n float border = w[0];\n ch = mix(ch, c2, smoothstep(border, border + 2. * blur, stripe_p));\n\n if (u_isImage == true) {\n bump = smoothstep(.2, .8, bump);\n }\n border = w[0] + .4 * (1. - bump) * w[1];\n ch = mix(ch, c1, smoothstep(border, border + 2. * blur, stripe_p));\n\n border = w[0] + .5 * (1. - bump) * w[1];\n ch = mix(ch, c2, smoothstep(border, border + 2. * blur, stripe_p));\n\n border = w[0] + w[1];\n ch = mix(ch, c1, smoothstep(border, border + 2. * blur, stripe_p));\n\n float gradient_t = (stripe_p - w[0] - w[1]) / w[2];\n float gradient = mix(c1, c2, smoothstep(0., 1., gradient_t));\n ch = mix(ch, gradient, smoothstep(border, border + .5 * blur, stripe_p));\n\n // Tint color is applied with color burn blending\n ch = mix(ch, 1. - min(1., (1. - ch) / max(tint, 0.0001)), u_colorTint.a);\n return ch;\n}\n\nfloat getImgFrame(vec2 uv, float th) {\n float frame = 1.;\n frame *= smoothstep(0., th, uv.y);\n frame *= 1.0 - smoothstep(1. - th, 1., uv.y);\n frame *= smoothstep(0., th, uv.x);\n frame *= 1.0 - smoothstep(1. - th, 1., uv.x);\n return frame;\n}\n\nfloat blurEdge3x3(sampler2D tex, vec2 uv, vec2 dudx, vec2 dudy, float radius, float centerSample) {\n vec2 texel = 1.0 / vec2(textureSize(tex, 0));\n vec2 r = radius * texel;\n\n float w1 = 1.0, w2 = 2.0, w4 = 4.0;\n float norm = 16.0;\n float sum = w4 * centerSample;\n\n sum += w2 * textureGrad(tex, uv + vec2(0.0, -r.y), dudx, dudy).r;\n sum += w2 * textureGrad(tex, uv + vec2(0.0, r.y), dudx, dudy).r;\n sum += w2 * textureGrad(tex, uv + vec2(-r.x, 0.0), dudx, dudy).r;\n sum += w2 * textureGrad(tex, uv + vec2(r.x, 0.0), dudx, dudy).r;\n\n sum += w1 * textureGrad(tex, uv + vec2(-r.x, -r.y), dudx, dudy).r;\n sum += w1 * textureGrad(tex, uv + vec2(r.x, -r.y), dudx, dudy).r;\n sum += w1 * textureGrad(tex, uv + vec2(-r.x, r.y), dudx, dudy).r;\n sum += w1 * textureGrad(tex, uv + vec2(r.x, r.y), dudx, dudy).r;\n\n return sum / norm;\n}\n\nfloat lst(float edge0, float edge1, float x) {\n return clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);\n}\n\nvoid main() {\n\n const float firstFrameOffset = 2.8;\n float t = .3 * (u_time + firstFrameOffset);\n\n vec2 uv = v_imageUV;\n vec2 dudx = dFdx(v_imageUV);\n vec2 dudy = dFdy(v_imageUV);\n vec4 img = textureGrad(u_image, uv, dudx, dudy);\n\n if (u_isImage == false) {\n uv = v_objectUV + .5;\n uv.y = 1. - uv.y;\n }\n\n float cycleWidth = u_repetition;\n float edge = 0.;\n float contOffset = 1.;\n\n vec2 rotatedUV = uv - vec2(.5);\n float angle = (-u_angle + 70.) * PI / 180.;\n float cosA = cos(angle);\n float sinA = sin(angle);\n rotatedUV = vec2(\n rotatedUV.x * cosA - rotatedUV.y * sinA,\n rotatedUV.x * sinA + rotatedUV.y * cosA\n ) + vec2(.5);\n\n if (u_isImage == true) {\n float edgeRaw = img.r;\n edge = blurEdge3x3(u_image, uv, dudx, dudy, 6., edgeRaw);\n edge = pow(edge, 1.6);\n edge *= mix(0.0, 1.0, smoothstep(0.0, 0.4, u_contour));\n } else {\n if (u_shape < 1.) {\n // full-fill on canvas\n vec2 borderUV = v_responsiveUV + .5;\n float ratio = v_responsiveBoxGivenSize.x / v_responsiveBoxGivenSize.y;\n vec2 mask = min(borderUV, 1. - borderUV);\n vec2 pixel_thickness = min(250. / v_responsiveBoxGivenSize, vec2(.5));\n float maskX = smoothstep(0.0, pixel_thickness.x, mask.x);\n float maskY = smoothstep(0.0, pixel_thickness.y, mask.y);\n maskX = pow(maskX, .25);\n maskY = pow(maskY, .25);\n edge = clamp(1. - maskX * maskY, 0., 1.);\n\n uv = v_responsiveUV;\n if (ratio > 1.) {\n uv.y /= ratio;\n } else {\n uv.x *= ratio;\n }\n uv += .5;\n uv.y = 1. - uv.y;\n\n cycleWidth *= 2.;\n contOffset = 1.5;\n\n } else if (u_shape < 2.) {\n // circle\n vec2 shapeUV = uv - .5;\n shapeUV *= .67;\n edge = pow(clamp(3. * length(shapeUV), 0., 1.), 18.);\n } else if (u_shape < 3.) {\n // daisy\n vec2 shapeUV = uv - .5;\n shapeUV *= 1.68;\n\n float r = length(shapeUV) * 2.;\n float a = atan(shapeUV.y, shapeUV.x) + .2;\n r *= (1. + .05 * sin(3. * a + 2. * t));\n float f = abs(cos(a * 3.));\n edge = smoothstep(f, f + .7, r);\n edge *= edge;\n\n uv *= .8;\n cycleWidth *= 1.6;\n\n } else if (u_shape < 4.) {\n // diamond\n vec2 shapeUV = uv - .5;\n shapeUV = rotate(shapeUV, .25 * PI);\n shapeUV *= 1.42;\n shapeUV += .5;\n vec2 mask = min(shapeUV, 1. - shapeUV);\n vec2 pixel_thickness = vec2(.15);\n float maskX = smoothstep(0.0, pixel_thickness.x, mask.x);\n float maskY = smoothstep(0.0, pixel_thickness.y, mask.y);\n maskX = pow(maskX, .25);\n maskY = pow(maskY, .25);\n edge = clamp(1. - maskX * maskY, 0., 1.);\n } else if (u_shape < 5.) {\n // metaballs\n vec2 shapeUV = uv - .5;\n shapeUV *= 1.3;\n edge = 0.;\n for (int i = 0; i < 5; i++) {\n float fi = float(i);\n float speed = 1.5 + 2./3. * sin(fi * 12.345);\n float angle = -fi * 1.5;\n vec2 dir1 = vec2(cos(angle), sin(angle));\n vec2 dir2 = vec2(cos(angle + 1.57), sin(angle + 1.));\n vec2 traj = .4 * (dir1 * sin(t * speed + fi * 1.23) + dir2 * cos(t * (speed * 0.7) + fi * 2.17));\n float d = length(shapeUV + traj);\n edge += pow(1.0 - clamp(d, 0.0, 1.0), 4.0);\n }\n edge = 1. - smoothstep(.65, .9, edge);\n edge = pow(edge, 4.);\n }\n\n edge = mix(smoothstep(.9 - 2. * fwidth(edge), .9, edge), edge, smoothstep(0.0, 0.4, u_contour));\n\n }\n\n float opacity = 0.;\n if (u_isImage == true) {\n opacity = img.g;\n float frame = getImgFrame(v_imageUV, 0.);\n opacity *= frame;\n } else {\n opacity = 1. - smoothstep(.9 - 2. * fwidth(edge), .9, edge);\n if (u_shape < 2.) {\n edge = 1.2 * edge;\n } else if (u_shape < 5.) {\n edge = 1.8 * pow(edge, 1.5);\n }\n }\n\n float diagBLtoTR = rotatedUV.x - rotatedUV.y;\n float diagTLtoBR = rotatedUV.x + rotatedUV.y;\n\n vec3 color = vec3(0.);\n vec3 color1 = vec3(.98, 0.98, 1.);\n vec3 color2 = vec3(.1, .1, .1 + .1 * smoothstep(.7, 1.3, diagTLtoBR));\n\n vec2 grad_uv = uv - .5;\n\n float dist = length(grad_uv + vec2(0., .2 * diagBLtoTR));\n grad_uv = rotate(grad_uv, (.25 - .2 * diagBLtoTR) * PI);\n float direction = grad_uv.x;\n\n float bump = pow(1.8 * dist, 1.2);\n bump = 1. - bump;\n bump *= pow(uv.y, .3);\n\n\n float thin_strip_1_ratio = .12 / cycleWidth * (1. - .4 * bump);\n float thin_strip_2_ratio = .07 / cycleWidth * (1. + .4 * bump);\n float wide_strip_ratio = (1. - thin_strip_1_ratio - thin_strip_2_ratio);\n\n float thin_strip_1_width = cycleWidth * thin_strip_1_ratio;\n float thin_strip_2_width = cycleWidth * thin_strip_2_ratio;\n\n float noise = snoise(uv - t);\n\n edge += (1. - edge) * u_distortion * noise;\n\n direction += diagBLtoTR;\n float contour = 0.;\n direction -= 2. * noise * diagBLtoTR * (smoothstep(0., 1., edge) * (1.0 - smoothstep(0., 1., edge)));\n direction *= mix(1., 1. - edge, smoothstep(.5, 1., u_contour));\n direction -= 1.7 * edge * smoothstep(.5, 1., u_contour);\n direction += .2 * pow(u_contour, 4.) * (1.0 - smoothstep(0., 1., edge));\n\n bump *= clamp(pow(uv.y, .1), .3, 1.);\n direction *= (.1 + (1.1 - edge) * bump);\n\n direction *= (.4 + .6 * (1.0 - smoothstep(.5, 1., edge)));\n direction += .18 * (smoothstep(.1, .2, uv.y) * (1.0 - smoothstep(.2, .4, uv.y)));\n direction += .03 * (smoothstep(.1, .2, 1. - uv.y) * (1.0 - smoothstep(.2, .4, 1. - uv.y)));\n\n direction *= (.5 + .5 * pow(uv.y, 2.));\n direction *= cycleWidth;\n direction -= t;\n\n\n float colorDispersion = (1. - bump);\n colorDispersion = clamp(colorDispersion, 0., 1.);\n float dispersionRed = colorDispersion;\n dispersionRed += .03 * bump * noise;\n dispersionRed += 5. * (smoothstep(-.1, .2, uv.y) * (1.0 - smoothstep(.1, .5, uv.y))) * (smoothstep(.4, .6, bump) * (1.0 - smoothstep(.4, 1., bump)));\n dispersionRed -= diagBLtoTR;\n\n float dispersionBlue = colorDispersion;\n dispersionBlue *= 1.3;\n dispersionBlue += (smoothstep(0., .4, uv.y) * (1.0 - smoothstep(.1, .8, uv.y))) * (smoothstep(.4, .6, bump) * (1.0 - smoothstep(.4, .8, bump)));\n dispersionBlue -= .2 * edge;\n\n dispersionRed *= (u_shiftRed / 20.);\n dispersionBlue *= (u_shiftBlue / 20.);\n\n float blur = 0.;\n float rExtraBlur = 0.;\n float gExtraBlur = 0.;\n if (u_isImage == true) {\n float softness = 0.05 * u_softness;\n blur = softness + .5 * smoothstep(1., 10., u_repetition) * smoothstep(.0, 1., edge);\n float smallCanvasT = 1.0 - smoothstep(100., 500., min(u_resolution.x, u_resolution.y));\n blur += smallCanvasT * smoothstep(.0, 1., edge);\n rExtraBlur = softness * (0.05 + .1 * (u_shiftRed / 20.) * bump);\n gExtraBlur = softness * 0.05 / max(0.001, abs(1. - diagBLtoTR));\n } else {\n blur = u_softness / 15. + .3 * contour;\n }\n\n vec3 w = vec3(thin_strip_1_width, thin_strip_2_width, wide_strip_ratio);\n w[1] -= .02 * smoothstep(.0, 1., edge + bump);\n float stripe_r = fract(direction + dispersionRed);\n float r = getColorChanges(color1.r, color2.r, stripe_r, w, blur + fwidth(stripe_r) + rExtraBlur, bump, u_colorTint.r);\n float stripe_g = fract(direction);\n float g = getColorChanges(color1.g, color2.g, stripe_g, w, blur + fwidth(stripe_g) + gExtraBlur, bump, u_colorTint.g);\n float stripe_b = fract(direction - dispersionBlue);\n float b = getColorChanges(color1.b, color2.b, stripe_b, w, blur + fwidth(stripe_b), bump, u_colorTint.b);\n\n color = vec3(r, g, b);\n color *= opacity;\n\n vec3 bgColor = u_colorBack.rgb * u_colorBack.a;\n color = color + bgColor * (1. - opacity);\n opacity = opacity + u_colorBack.a * (1. - opacity);\n\n ${ colorBandingFix }\n\n fragColor = vec4(color, opacity);\n}\n`;\n\n// Configuration for Poisson solver\nexport const POISSON_CONFIG_OPTIMIZED = {\n measurePerformance: false, // Set to true to see performance metrics\n workingSize: 512, // Size to solve Poisson at (will upscale to original size)\n iterations: 40, // SOR converges ~2-20x faster than standard Gauss-Seidel\n};\n\n// Precomputed pixel data for sparse processing\ninterface SparsePixelData {\n interiorPixels: Uint32Array; // Indices of interior pixels\n boundaryPixels: Uint32Array; // Indices of boundary pixels\n pixelCount: number;\n // Neighbor indices for each interior pixel (4 neighbors per pixel)\n // Layout: [east, west, north, south] for each pixel\n neighborIndices: Int32Array;\n}\n\nexport function toProcessedLiquidMetal(file: File | string): Promise<{ imageData: ImageData; pngBlob: Blob }> {\n const canvas = document.createElement('canvas');\n const ctx = canvas.getContext('2d');\n const isBlob = typeof file === 'string' && file.startsWith('blob:');\n\n return new Promise((resolve, reject) => {\n if (!file || !ctx) {\n reject(new Error('Invalid file or canvas context'));\n return;\n }\n\n const blobContentTypePromise = isBlob && fetch(file).then((res) => res.headers.get('Content-Type'));\n const img = new Image();\n img.crossOrigin = 'anonymous';\n const totalStartTime = performance.now();\n\n img.onload = async () => {\n // Force SVG to load at a high fidelity size if it's an SVG\n let isSVG;\n\n const blobContentType = await blobContentTypePromise;\n\n if (blobContentType) {\n isSVG = blobContentType === 'image/svg+xml';\n } else if (typeof file === 'string') {\n isSVG = file.endsWith('.svg') || file.startsWith('data:image/svg+xml');\n } else {\n isSVG = file.type === 'image/svg+xml';\n }\n\n let originalWidth = img.width || img.naturalWidth;\n let originalHeight = img.height || img.naturalHeight;\n\n if (isSVG) {\n // Scale SVG to max dimension while preserving aspect ratio\n const svgMaxSize = 4096;\n const aspectRatio = originalWidth / originalHeight;\n\n if (originalWidth > originalHeight) {\n originalWidth = svgMaxSize;\n originalHeight = svgMaxSize / aspectRatio;\n } else {\n originalHeight = svgMaxSize;\n originalWidth = svgMaxSize * aspectRatio;\n }\n\n img.width = originalWidth;\n img.height = originalHeight;\n }\n\n // Always scale to working resolution for consistency\n const minDimension = Math.min(originalWidth, originalHeight);\n const targetSize = POISSON_CONFIG_OPTIMIZED.workingSize;\n\n // Calculate scale to fit within workingSize\n const scaleFactor = targetSize / minDimension;\n const width = Math.round(originalWidth * scaleFactor);\n const height = Math.round(originalHeight * scaleFactor);\n\n if (POISSON_CONFIG_OPTIMIZED.measurePerformance) {\n console.log(`[Processing Mode]`);\n console.log(` Original: ${originalWidth}\u00D7${originalHeight}`);\n console.log(` Working: ${width}\u00D7${height} (${(scaleFactor * 100).toFixed(1)}% scale)`);\n if (scaleFactor < 1) {\n console.log(` Speedup: ~${Math.round(1 / (scaleFactor * scaleFactor))}\u00D7`);\n }\n }\n\n canvas.width = originalWidth;\n canvas.height = originalHeight;\n\n // Use a smaller canvas for shape detection and Poisson solving\n const shapeCanvas = document.createElement('canvas');\n shapeCanvas.width = width;\n shapeCanvas.height = height;\n\n const shapeCtx = shapeCanvas.getContext('2d')!;\n shapeCtx.drawImage(img, 0, 0, width, height);\n\n // 1) Build optimized masks using TypedArrays\n const startMask = performance.now();\n\n const shapeImageData = shapeCtx.getImageData(0, 0, width, height);\n const data = shapeImageData.data;\n\n // Use Uint8Array for masks (1 byte per pixel vs 8+ bytes for boolean array)\n const shapeMask = new Uint8Array(width * height);\n const boundaryMask = new Uint8Array(width * height);\n\n // First pass: identify shape pixels\n let shapePixelCount = 0;\n for (let i = 0, idx = 0; i < data.length; i += 4, idx++) {\n const a = data[i + 3];\n const isShape = a === 0 ? 0 : 1;\n shapeMask[idx] = isShape;\n shapePixelCount += isShape;\n }\n\n // 2) Optimized boundary detection using sparse approach\n // Only check shape pixels, not all pixels\n const boundaryIndices: number[] = [];\n const interiorIndices: number[] = [];\n\n for (let y = 0; y < height; y++) {\n for (let x = 0; x < width; x++) {\n const idx = y * width + x;\n if (!shapeMask[idx]) continue;\n\n // Check if pixel is on boundary (optimized: early exit)\n let isBoundary = false;\n\n // Check 4-connected neighbors first (most common case)\n if (x === 0 || x === width - 1 || y === 0 || y === height - 1) {\n isBoundary = true;\n } else {\n // Check all 8 neighbors (including diagonals) for comprehensive boundary detection\n isBoundary =\n !shapeMask[idx - 1] || // left\n !shapeMask[idx + 1] || // right\n !shapeMask[idx - width] || // top\n !shapeMask[idx + width] || // bottom\n !shapeMask[idx - width - 1] || // top-left\n !shapeMask[idx - width + 1] || // top-right\n !shapeMask[idx + width - 1] || // bottom-left\n !shapeMask[idx + width + 1]; // bottom-right\n }\n\n if (isBoundary) {\n boundaryMask[idx] = 1;\n boundaryIndices.push(idx);\n } else {\n interiorIndices.push(idx);\n }\n }\n }\n\n if (POISSON_CONFIG_OPTIMIZED.measurePerformance) {\n console.log(`[Mask Building] Time: ${(performance.now() - startMask).toFixed(2)}ms`);\n console.log(\n ` Shape pixels: ${shapePixelCount} / ${width * height} (${((shapePixelCount / (width * height)) * 100).toFixed(1)}%)`\n );\n console.log(` Interior pixels: ${interiorIndices.length}`);\n console.log(` Boundary pixels: ${boundaryIndices.length}`);\n }\n\n // 3) Precompute sparse data structure for solver\n const sparseData = buildSparseData(\n shapeMask,\n boundaryMask,\n new Uint32Array(interiorIndices),\n new Uint32Array(boundaryIndices),\n width,\n height\n );\n\n // 4) Solve Poisson equation with optimized sparse solver\n const startSolve = performance.now();\n const u = solvePoissonSparse(sparseData, shapeMask, boundaryMask, width, height);\n\n if (POISSON_CONFIG_OPTIMIZED.measurePerformance) {\n console.log(`[Poisson Solve] Time: ${(performance.now() - startSolve).toFixed(2)}ms`);\n }\n\n // 5) Generate output image\n let maxVal = 0;\n let finalImageData: ImageData;\n\n // Only check shape pixels for max value\n for (let i = 0; i < interiorIndices.length; i++) {\n const idx = interiorIndices[i]!;\n if (u[idx]! > maxVal) maxVal = u[idx]!;\n }\n\n // Create gradient image at working resolution\n const tempCanvas = document.createElement('canvas');\n tempCanvas.width = width;\n tempCanvas.height = height;\n const tempCtx = tempCanvas.getContext('2d')!;\n\n const tempImg = tempCtx.createImageData(width, height);\n for (let y = 0; y < height; y++) {\n for (let x = 0; x < width; x++) {\n const idx = y * width + x;\n const px = idx * 4;\n\n if (!shapeMask[idx]) {\n tempImg.data[px] = 255;\n tempImg.data[px + 1] = 255;\n tempImg.data[px + 2] = 255;\n tempImg.data[px + 3] = 0; // Alpha = 0 for background\n } else {\n const poissonRatio = u[idx]! / maxVal;\n const gray = 255 * (1 - poissonRatio);\n tempImg.data[px] = gray;\n tempImg.data[px + 1] = gray;\n tempImg.data[px + 2] = gray;\n tempImg.data[px + 3] = 255; // Alpha = 255 for shape\n }\n }\n }\n tempCtx.putImageData(tempImg, 0, 0);\n\n // Upscale to original resolution with smooth interpolation\n ctx.imageSmoothingEnabled = true;\n ctx.imageSmoothingQuality = 'high';\n ctx.drawImage(tempCanvas, 0, 0, width, height, 0, 0, originalWidth, originalHeight);\n\n // Now get the upscaled image data for final output\n const outImg = ctx.getImageData(0, 0, originalWidth, originalHeight);\n\n // Re-apply edges from original resolution with anti-aliasing\n // This ensures edges are pixel-perfect while gradient is smooth\n const originalCanvas = document.createElement('canvas');\n originalCanvas.width = originalWidth;\n originalCanvas.height = originalHeight;\n const originalCtx = originalCanvas.getContext('2d')!;\n // originalCtx.fillStyle = \"white\";\n // originalCtx.fillRect(0, 0, originalWidth, originalHeight);\n originalCtx.drawImage(img, 0, 0, originalWidth, originalHeight);\n const originalData = originalCtx.getImageData(0, 0, originalWidth, originalHeight);\n\n // Process each pixel: Red channel = gradient, Alpha channel = original alpha\n for (let i = 0; i < outImg.data.length; i += 4) {\n const a = originalData.data[i + 3]!;\n // Use only alpha to determine background vs shape\n const upscaledAlpha = outImg.data[i + 3]!;\n if (a === 0) {\n // Background pixel\n outImg.data[i] = 255;\n outImg.data[i + 1] = 0;\n } else {\n // Red channel carries the gradient\n // Check if upscale missed this pixel by looking at alpha channel\n // If upscaled alpha is 0, the low-res version thought this was background\n outImg.data[i] = upscaledAlpha === 0 ? 0 : outImg.data[i]!; // gradient or 0\n outImg.data[i + 1] = a; // original alpha\n }\n\n // Unused channels fixed\n outImg.data[i + 2] = 255;\n outImg.data[i + 3] = 255;\n }\n\n ctx.putImageData(outImg, 0, 0);\n finalImageData = outImg;\n canvas.toBlob((blob) => {\n if (!blob) {\n reject(new Error('Failed to create PNG blob'));\n return;\n }\n\n if (POISSON_CONFIG_OPTIMIZED.measurePerformance) {\n const totalTime = performance.now() - totalStartTime;\n console.log(`[Total Processing Time] ${totalTime.toFixed(2)}ms`);\n if (scaleFactor < 1) {\n const estimatedFullResTime = totalTime * Math.pow((originalWidth * originalHeight) / (width * height), 1.5);\n console.log(`[Estimated time at full resolution] ~${estimatedFullResTime.toFixed(0)}ms`);\n console.log(\n `[Time saved] ~${(estimatedFullResTime - totalTime).toFixed(0)}ms (${Math.round(estimatedFullResTime / totalTime)}\u00D7 faster)`\n );\n }\n }\n\n resolve({\n imageData: finalImageData,\n pngBlob: blob,\n });\n }, 'image/png');\n };\n\n img.onerror = () => reject(new Error('Failed to load image'));\n img.src = typeof file === 'string' ? file : URL.createObjectURL(file);\n });\n}\n\nfunction buildSparseData(\n shapeMask: Uint8Array,\n boundaryMask: Uint8Array,\n interiorPixels: Uint32Array,\n boundaryPixels: Uint32Array,\n width: number,\n height: number\n): SparsePixelData {\n const pixelCount = interiorPixels.length;\n\n // Build neighbor indices for sparse processing\n // For each interior pixel, store indices of its 4 neighbors\n // Use -1 for out-of-bounds or non-shape neighbors\n const neighborIndices = new Int32Array(pixelCount * 4);\n\n for (let i = 0; i < pixelCount; i++) {\n const idx = interiorPixels[i]!;\n const x = idx % width;\n const y = Math.floor(idx / width);\n\n // East neighbor\n neighborIndices[i * 4 + 0] = x < width - 1 && shapeMask[idx + 1] ? idx + 1 : -1;\n // West neighbor\n neighborIndices[i * 4 + 1] = x > 0 && shapeMask[idx - 1] ? idx - 1 : -1;\n // North neighbor\n neighborIndices[i * 4 + 2] = y > 0 && shapeMask[idx - width] ? idx - width : -1;\n // South neighbor\n neighborIndices[i * 4 + 3] = y < height - 1 && shapeMask[idx + width] ? idx + width : -1;\n }\n\n return {\n interiorPixels,\n boundaryPixels,\n pixelCount,\n neighborIndices,\n };\n}\n\nfunction solvePoissonSparse(\n sparseData: SparsePixelData,\n shapeMask: Uint8Array,\n boundaryMask: Uint8Array,\n width: number,\n height: number\n): Float32Array {\n // This controls how smooth the falloff gradient will be and extend into the shape\n const ITERATIONS = POISSON_CONFIG_OPTIMIZED.iterations;\n\n // Keep C constant - only iterations control gradient spread\n const C = 0.01;\n\n const u = new Float32Array(width * height);\n const { interiorPixels, neighborIndices, pixelCount } = sparseData;\n\n // Performance tracking\n const startTime = performance.now();\n\n // Red-Black SOR for better symmetry with fewer iterations\n // omega between 1.8-1.95 typically gives best convergence for Poisson\n const omega = 1.9;\n\n // Pre-classify pixels as red or black for efficient processing\n const redPixels: number[] = [];\n const blackPixels: number[] = [];\n\n for (let i = 0; i < pixelCount; i++) {\n const idx = interiorPixels[i]!;\n const x = idx % width;\n const y = Math.floor(idx / width);\n\n if ((x + y) % 2 === 0) {\n redPixels.push(i);\n } else {\n blackPixels.push(i);\n }\n }\n\n for (let iter = 0; iter < ITERATIONS; iter++) {\n // Red pass: update red pixels\n for (const i of redPixels) {\n const idx = interiorPixels[i]!;\n\n // Get precomputed neighbor indices\n const eastIdx = neighborIndices[i * 4 + 0]!;\n const westIdx = neighborIndices[i * 4 + 1]!;\n const northIdx = neighborIndices[i * 4 + 2]!;\n const southIdx = neighborIndices[i * 4 + 3]!;\n\n // Sum neighbors (use 0 for out-of-bounds)\n let sumN = 0;\n if (eastIdx >= 0) sumN += u[eastIdx]!;\n if (westIdx >= 0) sumN += u[westIdx]!;\n if (northIdx >= 0) sumN += u[northIdx]!;\n if (southIdx >= 0) sumN += u[southIdx]!;\n\n // SOR update: blend new value with old value\n const newValue = (C + sumN) / 4;\n u[idx] = omega * newValue + (1 - omega) * u[idx]!;\n }\n\n // Black pass: update black pixels\n for (const i of blackPixels) {\n const idx = interiorPixels[i]!;\n\n // Get precomputed neighbor indices\n const eastIdx = neighborIndices[i * 4 + 0]!;\n const westIdx = neighborIndices[i * 4 + 1]!;\n const northIdx = neighborIndices[i * 4 + 2]!;\n const southIdx = neighborIndices[i * 4 + 3]!;\n\n // Sum neighbors (use 0 for out-of-bounds)\n let sumN = 0;\n if (eastIdx >= 0) sumN += u[eastIdx]!;\n if (westIdx >= 0) sumN += u[westIdx]!;\n if (northIdx >= 0) sumN += u[northIdx]!;\n if (southIdx >= 0) sumN += u[southIdx]!;\n\n // SOR update: blend new value with old value\n const newValue = (C + sumN) / 4;\n u[idx] = omega * newValue + (1 - omega) * u[idx]!;\n }\n }\n\n if (POISSON_CONFIG_OPTIMIZED.measurePerformance) {\n const elapsed = performance.now() - startTime;\n\n console.log(`[Optimized Poisson Solver (SOR \u03C9=${omega})]`);\n console.log(` Working size: ${width}\u00D7${height}`);\n console.log(` Iterations: ${ITERATIONS}`);\n console.log(` Time: ${elapsed.toFixed(2)}ms`);\n console.log(` Interior pixels processed: ${pixelCount}`);\n console.log(` Speed: ${((ITERATIONS * pixelCount) / (elapsed * 1000)).toFixed(2)} Mpixels/sec`);\n }\n\n return u;\n}\n\nexport interface LiquidMetalUniforms extends ShaderSizingUniforms {\n u_colorBack: [number, number, number, number];\n u_colorTint: [number, number, number, number];\n u_image: HTMLImageElement | string | undefined;\n u_repetition: number;\n u_shiftRed: number;\n u_shiftBlue: number;\n u_contour: number;\n u_softness: number;\n u_distortion: number;\n u_angle: number;\n u_shape: (typeof LiquidMetalShapes)[LiquidMetalShape];\n u_isImage: boolean;\n}\n\nexport interface LiquidMetalParams extends ShaderSizingParams, ShaderMotionParams {\n colorBack?: string;\n colorTint?: string;\n image?: HTMLImageElement | string | undefined;\n repetition?: number;\n shiftRed?: number;\n shiftBlue?: number;\n contour?: number;\n softness?: number;\n distortion?: number;\n angle?: number;\n shape?: LiquidMetalShape;\n}\n\nexport const LiquidMetalShapes = {\n none: 0,\n circle: 1,\n daisy: 2,\n diamond: 3,\n metaballs: 4,\n} as const;\n\nexport type LiquidMetalShape = keyof typeof LiquidMetalShapes;\n"], + "mappings": "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", + "names": [] +} diff --git a/public/vendor/paper-shaders/shaders/mesh-gradient.d.ts b/public/vendor/paper-shaders/shaders/mesh-gradient.d.ts new file mode 100644 index 0000000..bb51942 --- /dev/null +++ b/public/vendor/paper-shaders/shaders/mesh-gradient.d.ts @@ -0,0 +1,52 @@ +import type { vec4 } from '../types.js'; +import type { ShaderMotionParams } from '../shader-mount.js'; +import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js'; +export declare const meshGradientMeta: { + readonly maxColorCount: 10; +}; +/** + * A flowing composition of color spots, moving along distinct trajectories + * and transformed by organic distortion. + * + * Fragment shader uniforms: + * - u_time (float): Animation time + * - u_colors (vec4[]): Up to 10 color spots in RGBA + * - u_colorsCount (float): Number of active colors + * - u_distortion (float): Power of organic noise distortion (0 to 1) + * - u_swirl (float): Power of vortex distortion (0 to 1) + * - u_grainMixer (float): Strength of grain distortion applied to shape edges (0 to 1) + * - u_grainOverlay (float): Post-processing black/white grain overlay (0 to 1) + * + * Vertex shader outputs (used in fragment shader): + * - v_objectUV (vec2): Object box UV coordinates with global sizing (scale, rotation, offsets, etc) applied + * + * Vertex shader uniforms: + * - u_resolution (vec2): Canvas resolution in pixels + * - u_pixelRatio (float): Device pixel ratio + * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1) + * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1) + * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas + * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas + * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover) + * - u_scale (float): Overall zoom level of the graphics (0.01 to 4) + * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360) + * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1) + * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1) + * + */ +export declare const meshGradientFragmentShader: string; +export interface MeshGradientUniforms extends ShaderSizingUniforms { + u_colors: vec4[]; + u_colorsCount: number; + u_distortion: number; + u_swirl: number; + u_grainMixer: number; + u_grainOverlay: number; +} +export interface MeshGradientParams extends ShaderSizingParams, ShaderMotionParams { + colors?: string[]; + distortion?: number; + swirl?: number; + grainMixer?: number; + grainOverlay?: number; +} diff --git a/public/vendor/paper-shaders/shaders/mesh-gradient.js b/public/vendor/paper-shaders/shaders/mesh-gradient.js new file mode 100644 index 0000000..49b4f2b --- /dev/null +++ b/public/vendor/paper-shaders/shaders/mesh-gradient.js @@ -0,0 +1,127 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Paper Shaders * + * https://github.com/paper-design/shaders * + * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +import { +} from "../shader-sizing.js"; +import { declarePI, rotation2, proceduralHash21 } from "../shader-utils.js"; +const meshGradientMeta = { + maxColorCount: 10 +}; +const meshGradientFragmentShader = `#version 300 es +precision mediump float; + +uniform float u_time; + +uniform vec4 u_colors[${meshGradientMeta.maxColorCount}]; +uniform float u_colorsCount; + +uniform float u_distortion; +uniform float u_swirl; +uniform float u_grainMixer; +uniform float u_grainOverlay; + +in vec2 v_objectUV; +out vec4 fragColor; + +${declarePI} +${rotation2} +${proceduralHash21} + +float valueNoise(vec2 st) { + vec2 i = floor(st); + vec2 f = fract(st); + float a = hash21(i); + float b = hash21(i + vec2(1.0, 0.0)); + float c = hash21(i + vec2(0.0, 1.0)); + float d = hash21(i + vec2(1.0, 1.0)); + vec2 u = f * f * (3.0 - 2.0 * f); + float x1 = mix(a, b, u.x); + float x2 = mix(c, d, u.x); + return mix(x1, x2, u.y); +} + +float noise(vec2 n, vec2 seedOffset) { + return valueNoise(n + seedOffset); +} + +vec2 getPosition(int i, float t) { + float a = float(i) * .37; + float b = .6 + fract(float(i) / 3.) * .9; + float c = .8 + fract(float(i + 1) / 4.); + + float x = sin(t * b + a); + float y = cos(t * c + a * 1.5); + + return .5 + .5 * vec2(x, y); +} + +void main() { + vec2 uv = v_objectUV; + uv += .5; + vec2 grainUV = uv * 1000.; + + float grain = noise(grainUV, vec2(0.)); + float mixerGrain = .4 * u_grainMixer * (grain - .5); + + const float firstFrameOffset = 41.5; + float t = .5 * (u_time + firstFrameOffset); + + float radius = smoothstep(0., 1., length(uv - .5)); + float center = 1. - radius; + for (float i = 1.; i <= 2.; i++) { + uv.x += u_distortion * center / i * sin(t + i * .4 * smoothstep(.0, 1., uv.y)) * cos(.2 * t + i * 2.4 * smoothstep(.0, 1., uv.y)); + uv.y += u_distortion * center / i * cos(t + i * 2. * smoothstep(.0, 1., uv.x)); + } + + vec2 uvRotated = uv; + uvRotated -= vec2(.5); + float angle = 3. * u_swirl * radius; + uvRotated = rotate(uvRotated, -angle); + uvRotated += vec2(.5); + + vec3 color = vec3(0.); + float opacity = 0.; + float totalWeight = 0.; + + for (int i = 0; i < ${meshGradientMeta.maxColorCount}; i++) { + if (i >= int(u_colorsCount)) break; + + vec2 pos = getPosition(i, t) + mixerGrain; + vec3 colorFraction = u_colors[i].rgb * u_colors[i].a; + float opacityFraction = u_colors[i].a; + + float dist = length(uvRotated - pos); + + dist = pow(dist, 3.5); + float weight = 1. / (dist + 1e-3); + color += colorFraction * weight; + opacity += opacityFraction * weight; + totalWeight += weight; + } + + color /= max(1e-4, totalWeight); + opacity /= max(1e-4, totalWeight); + + float grainOverlay = valueNoise(rotate(grainUV, 1.) + vec2(3.)); + grainOverlay = mix(grainOverlay, valueNoise(rotate(grainUV, 2.) + vec2(-1.)), .5); + grainOverlay = pow(grainOverlay, 1.3); + + float grainOverlayV = grainOverlay * 2. - 1.; + vec3 grainOverlayColor = vec3(step(0., grainOverlayV)); + float grainOverlayStrength = u_grainOverlay * abs(grainOverlayV); + grainOverlayStrength = pow(grainOverlayStrength, .8); + color = mix(color, grainOverlayColor, .35 * grainOverlayStrength); + + opacity += .5 * grainOverlayStrength; + opacity = clamp(opacity, 0., 1.); + + fragColor = vec4(color, opacity); +} +`; +export { + meshGradientFragmentShader, + meshGradientMeta +}; +//# sourceMappingURL=mesh-gradient.js.map diff --git a/public/vendor/paper-shaders/shaders/mesh-gradient.js.map b/public/vendor/paper-shaders/shaders/mesh-gradient.js.map new file mode 100644 index 0000000..baf1522 --- /dev/null +++ b/public/vendor/paper-shaders/shaders/mesh-gradient.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../../src/shaders/mesh-gradient.ts"], + "sourcesContent": ["import type { vec4 } from '../types.js';\nimport type { ShaderMotionParams } from '../shader-mount.js';\nimport {\n type ShaderSizingParams,\n type ShaderSizingUniforms,\n} from '../shader-sizing.js';\nimport { declarePI, rotation2, proceduralHash21 } from '../shader-utils.js';\n\nexport const meshGradientMeta = {\n maxColorCount: 10,\n} as const;\n\n/**\n * A flowing composition of color spots, moving along distinct trajectories\n * and transformed by organic distortion.\n *\n * Fragment shader uniforms:\n * - u_time (float): Animation time\n * - u_colors (vec4[]): Up to 10 color spots in RGBA\n * - u_colorsCount (float): Number of active colors\n * - u_distortion (float): Power of organic noise distortion (0 to 1)\n * - u_swirl (float): Power of vortex distortion (0 to 1)\n * - u_grainMixer (float): Strength of grain distortion applied to shape edges (0 to 1)\n * - u_grainOverlay (float): Post-processing black/white grain overlay (0 to 1)\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_objectUV (vec2): Object box UV coordinates with global sizing (scale, rotation, offsets, etc) applied\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n *\n */\n\n// language=GLSL\nexport const meshGradientFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform float u_time;\n\nuniform vec4 u_colors[${meshGradientMeta.maxColorCount}];\nuniform float u_colorsCount;\n\nuniform float u_distortion;\nuniform float u_swirl;\nuniform float u_grainMixer;\nuniform float u_grainOverlay;\n\nin vec2 v_objectUV;\nout vec4 fragColor;\n\n${declarePI}\n${rotation2}\n${proceduralHash21}\n\nfloat valueNoise(vec2 st) {\n vec2 i = floor(st);\n vec2 f = fract(st);\n float a = hash21(i);\n float b = hash21(i + vec2(1.0, 0.0));\n float c = hash21(i + vec2(0.0, 1.0));\n float d = hash21(i + vec2(1.0, 1.0));\n vec2 u = f * f * (3.0 - 2.0 * f);\n float x1 = mix(a, b, u.x);\n float x2 = mix(c, d, u.x);\n return mix(x1, x2, u.y);\n}\n\nfloat noise(vec2 n, vec2 seedOffset) {\n return valueNoise(n + seedOffset);\n}\n\nvec2 getPosition(int i, float t) {\n float a = float(i) * .37;\n float b = .6 + fract(float(i) / 3.) * .9;\n float c = .8 + fract(float(i + 1) / 4.);\n\n float x = sin(t * b + a);\n float y = cos(t * c + a * 1.5);\n\n return .5 + .5 * vec2(x, y);\n}\n\nvoid main() {\n vec2 uv = v_objectUV;\n uv += .5;\n vec2 grainUV = uv * 1000.;\n\n float grain = noise(grainUV, vec2(0.));\n float mixerGrain = .4 * u_grainMixer * (grain - .5);\n\n const float firstFrameOffset = 41.5;\n float t = .5 * (u_time + firstFrameOffset);\n\n float radius = smoothstep(0., 1., length(uv - .5));\n float center = 1. - radius;\n for (float i = 1.; i <= 2.; i++) {\n uv.x += u_distortion * center / i * sin(t + i * .4 * smoothstep(.0, 1., uv.y)) * cos(.2 * t + i * 2.4 * smoothstep(.0, 1., uv.y));\n uv.y += u_distortion * center / i * cos(t + i * 2. * smoothstep(.0, 1., uv.x));\n }\n\n vec2 uvRotated = uv;\n uvRotated -= vec2(.5);\n float angle = 3. * u_swirl * radius;\n uvRotated = rotate(uvRotated, -angle);\n uvRotated += vec2(.5);\n\n vec3 color = vec3(0.);\n float opacity = 0.;\n float totalWeight = 0.;\n\n for (int i = 0; i < ${meshGradientMeta.maxColorCount}; i++) {\n if (i >= int(u_colorsCount)) break;\n\n vec2 pos = getPosition(i, t) + mixerGrain;\n vec3 colorFraction = u_colors[i].rgb * u_colors[i].a;\n float opacityFraction = u_colors[i].a;\n\n float dist = length(uvRotated - pos);\n\n dist = pow(dist, 3.5);\n float weight = 1. / (dist + 1e-3);\n color += colorFraction * weight;\n opacity += opacityFraction * weight;\n totalWeight += weight;\n }\n\n color /= max(1e-4, totalWeight);\n opacity /= max(1e-4, totalWeight);\n\n float grainOverlay = valueNoise(rotate(grainUV, 1.) + vec2(3.));\n grainOverlay = mix(grainOverlay, valueNoise(rotate(grainUV, 2.) + vec2(-1.)), .5);\n grainOverlay = pow(grainOverlay, 1.3);\n\n float grainOverlayV = grainOverlay * 2. - 1.;\n vec3 grainOverlayColor = vec3(step(0., grainOverlayV));\n float grainOverlayStrength = u_grainOverlay * abs(grainOverlayV);\n grainOverlayStrength = pow(grainOverlayStrength, .8);\n color = mix(color, grainOverlayColor, .35 * grainOverlayStrength);\n\n opacity += .5 * grainOverlayStrength;\n opacity = clamp(opacity, 0., 1.);\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface MeshGradientUniforms extends ShaderSizingUniforms {\n u_colors: vec4[];\n u_colorsCount: number;\n u_distortion: number;\n u_swirl: number;\n u_grainMixer: number;\n u_grainOverlay: number;\n}\n\nexport interface MeshGradientParams extends ShaderSizingParams, ShaderMotionParams {\n colors?: string[];\n distortion?: number;\n swirl?: number;\n grainMixer?: number;\n grainOverlay?: number;\n}\n"], + "mappings": ";;;;;AAEA;AAAA,OAGO;AACP,SAAS,WAAW,WAAW,wBAAwB;AAEhD,MAAM,mBAAmB;AAAA,EAC9B,eAAe;AACjB;AAkCO,MAAM,6BAAqC;AAAA;AAAA;AAAA;AAAA;AAAA,wBAK1B,iBAAiB,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWpD,SAAS;AAAA,EACT,SAAS;AAAA,EACT,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBA0DM,iBAAiB,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;", + "names": [] +} diff --git a/public/vendor/paper-shaders/shaders/metaballs.d.ts b/public/vendor/paper-shaders/shaders/metaballs.d.ts new file mode 100644 index 0000000..bf6cae2 --- /dev/null +++ b/public/vendor/paper-shaders/shaders/metaballs.d.ts @@ -0,0 +1,51 @@ +import type { vec4 } from '../types.js'; +import type { ShaderMotionParams } from '../shader-mount.js'; +import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js'; +export declare const metaballsMeta: { + readonly maxColorCount: 8; + readonly maxBallsCount: 20; +}; +/** + * Up to 20 colored gooey balls moving around the center and merging into smooth organic shapes. + * + * Fragment shader uniforms: + * - u_time (float): Animation time + * - u_colorBack (vec4): Background color in RGBA + * - u_colors (vec4[]): Up to 8 base colors in RGBA + * - u_colorsCount (float): Number of active colors + * - u_count (float): Number of balls (1 to 20) + * - u_size (float): Size of the balls (0 to 1) + * - u_noiseTexture (sampler2D): Pre-computed randomizer source texture + * + * Vertex shader outputs (used in fragment shader): + * - v_objectUV (vec2): Object box UV coordinates with global sizing (scale, rotation, offsets, etc) applied + * + * Vertex shader uniforms: + * - u_resolution (vec2): Canvas resolution in pixels + * - u_pixelRatio (float): Device pixel ratio + * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1) + * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1) + * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas + * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas + * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover) + * - u_scale (float): Overall zoom level of the graphics (0.01 to 4) + * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360) + * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1) + * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1) + * + */ +export declare const metaballsFragmentShader: string; +export interface MetaballsUniforms extends ShaderSizingUniforms { + u_colorBack: [number, number, number, number]; + u_colors: vec4[]; + u_colorsCount: number; + u_count: number; + u_size: number; + u_noiseTexture?: HTMLImageElement; +} +export interface MetaballsParams extends ShaderSizingParams, ShaderMotionParams { + colorBack?: string; + colors?: string[]; + count?: number; + size?: number; +} diff --git a/public/vendor/paper-shaders/shaders/metaballs.js b/public/vendor/paper-shaders/shaders/metaballs.js new file mode 100644 index 0000000..36fb85a --- /dev/null +++ b/public/vendor/paper-shaders/shaders/metaballs.js @@ -0,0 +1,112 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Paper Shaders * + * https://github.com/paper-design/shaders * + * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +import {} from "../shader-sizing.js"; +import { declarePI, textureRandomizerR, colorBandingFix } from "../shader-utils.js"; +const metaballsMeta = { + maxColorCount: 8, + maxBallsCount: 20 +}; +const metaballsFragmentShader = `#version 300 es +precision mediump float; + +uniform float u_time; + +uniform sampler2D u_noiseTexture; + +uniform vec4 u_colorBack; +uniform vec4 u_colors[${metaballsMeta.maxColorCount}]; +uniform float u_colorsCount; +uniform float u_size; +uniform float u_sizeRange; +uniform float u_count; + +in vec2 v_objectUV; + +out vec4 fragColor; + +${declarePI} +${textureRandomizerR} +float noise(float x) { + float i = floor(x); + float f = fract(x); + float u = f * f * (3.0 - 2.0 * f); + vec2 p0 = vec2(i, 0.0); + vec2 p1 = vec2(i + 1.0, 0.0); + return mix(randomR(p0), randomR(p1), u); +} + +float getBallShape(vec2 uv, vec2 c, float p) { + float s = .5 * length(uv - c); + s = 1. - clamp(s, 0., 1.); + s = pow(s, p); + return s; +} + +void main() { + vec2 shape_uv = v_objectUV; + + shape_uv += .5; + + const float firstFrameOffset = 2503.4; + float t = .2 * (u_time + firstFrameOffset); + + vec3 totalColor = vec3(0.); + float totalShape = 0.; + float totalOpacity = 0.; + + for (int i = 0; i < ${metaballsMeta.maxBallsCount}; i++) { + if (i >= int(ceil(u_count))) break; + + float idxFract = float(i) / float(${metaballsMeta.maxBallsCount}); + float angle = TWO_PI * idxFract; + + float speed = 1. - .2 * idxFract; + float noiseX = noise(angle * 10. + float(i) + t * speed); + float noiseY = noise(angle * 20. + float(i) - t * speed); + + vec2 pos = vec2(.5) + 1e-4 + .9 * (vec2(noiseX, noiseY) - .5); + + int safeIndex = i % int(u_colorsCount + 0.5); + vec4 ballColor = u_colors[safeIndex]; + ballColor.rgb *= ballColor.a; + + float sizeFrac = 1.; + if (float(i) > floor(u_count - 1.)) { + sizeFrac *= fract(u_count); + } + + float shape = getBallShape(shape_uv, pos, 45. - 30. * u_size * sizeFrac); + shape *= pow(u_size, .2); + shape = smoothstep(0., 1., shape); + + totalColor += ballColor.rgb * shape; + totalShape += shape; + totalOpacity += ballColor.a * shape; + } + + totalColor /= max(totalShape, 1e-4); + totalOpacity /= max(totalShape, 1e-4); + + float edge_width = fwidth(totalShape); + float finalShape = smoothstep(.4, .4 + edge_width, totalShape); + + vec3 color = totalColor * finalShape; + float opacity = totalOpacity * finalShape; + + vec3 bgColor = u_colorBack.rgb * u_colorBack.a; + color = color + bgColor * (1. - opacity); + opacity = opacity + u_colorBack.a * (1. - opacity); + + ${colorBandingFix} + + fragColor = vec4(color, opacity); +} +`; +export { + metaballsFragmentShader, + metaballsMeta +}; +//# sourceMappingURL=metaballs.js.map diff --git a/public/vendor/paper-shaders/shaders/metaballs.js.map b/public/vendor/paper-shaders/shaders/metaballs.js.map new file mode 100644 index 0000000..82beb34 --- /dev/null +++ b/public/vendor/paper-shaders/shaders/metaballs.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../../src/shaders/metaballs.ts"], + "sourcesContent": ["import type { vec4 } from '../types.js';\nimport type { ShaderMotionParams } from '../shader-mount.js';\nimport { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { declarePI, textureRandomizerR, colorBandingFix } from '../shader-utils.js';\n\nexport const metaballsMeta = {\n maxColorCount: 8,\n maxBallsCount: 20,\n} as const;\n\n/**\n * Up to 20 colored gooey balls moving around the center and merging into smooth organic shapes.\n *\n * Fragment shader uniforms:\n * - u_time (float): Animation time\n * - u_colorBack (vec4): Background color in RGBA\n * - u_colors (vec4[]): Up to 8 base colors in RGBA\n * - u_colorsCount (float): Number of active colors\n * - u_count (float): Number of balls (1 to 20)\n * - u_size (float): Size of the balls (0 to 1)\n * - u_noiseTexture (sampler2D): Pre-computed randomizer source texture\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_objectUV (vec2): Object box UV coordinates with global sizing (scale, rotation, offsets, etc) applied\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n *\n */\n\n// language=GLSL\nexport const metaballsFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform float u_time;\n\nuniform sampler2D u_noiseTexture;\n\nuniform vec4 u_colorBack;\nuniform vec4 u_colors[${ metaballsMeta.maxColorCount }];\nuniform float u_colorsCount;\nuniform float u_size;\nuniform float u_sizeRange;\nuniform float u_count;\n\nin vec2 v_objectUV;\n\nout vec4 fragColor;\n\n${ declarePI }\n${ textureRandomizerR }\nfloat noise(float x) {\n float i = floor(x);\n float f = fract(x);\n float u = f * f * (3.0 - 2.0 * f);\n vec2 p0 = vec2(i, 0.0);\n vec2 p1 = vec2(i + 1.0, 0.0);\n return mix(randomR(p0), randomR(p1), u);\n}\n\nfloat getBallShape(vec2 uv, vec2 c, float p) {\n float s = .5 * length(uv - c);\n s = 1. - clamp(s, 0., 1.);\n s = pow(s, p);\n return s;\n}\n\nvoid main() {\n vec2 shape_uv = v_objectUV;\n\n shape_uv += .5;\n\n const float firstFrameOffset = 2503.4;\n float t = .2 * (u_time + firstFrameOffset);\n\n vec3 totalColor = vec3(0.);\n float totalShape = 0.;\n float totalOpacity = 0.;\n\n for (int i = 0; i < ${ metaballsMeta.maxBallsCount }; i++) {\n if (i >= int(ceil(u_count))) break;\n\n float idxFract = float(i) / float(${ metaballsMeta.maxBallsCount });\n float angle = TWO_PI * idxFract;\n\n float speed = 1. - .2 * idxFract;\n float noiseX = noise(angle * 10. + float(i) + t * speed);\n float noiseY = noise(angle * 20. + float(i) - t * speed);\n\n vec2 pos = vec2(.5) + 1e-4 + .9 * (vec2(noiseX, noiseY) - .5);\n\n int safeIndex = i % int(u_colorsCount + 0.5);\n vec4 ballColor = u_colors[safeIndex];\n ballColor.rgb *= ballColor.a;\n\n float sizeFrac = 1.;\n if (float(i) > floor(u_count - 1.)) {\n sizeFrac *= fract(u_count);\n }\n\n float shape = getBallShape(shape_uv, pos, 45. - 30. * u_size * sizeFrac);\n shape *= pow(u_size, .2);\n shape = smoothstep(0., 1., shape);\n\n totalColor += ballColor.rgb * shape;\n totalShape += shape;\n totalOpacity += ballColor.a * shape;\n }\n\n totalColor /= max(totalShape, 1e-4);\n totalOpacity /= max(totalShape, 1e-4);\n\n float edge_width = fwidth(totalShape);\n float finalShape = smoothstep(.4, .4 + edge_width, totalShape);\n\n vec3 color = totalColor * finalShape;\n float opacity = totalOpacity * finalShape;\n\n vec3 bgColor = u_colorBack.rgb * u_colorBack.a;\n color = color + bgColor * (1. - opacity);\n opacity = opacity + u_colorBack.a * (1. - opacity);\n\n ${ colorBandingFix }\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface MetaballsUniforms extends ShaderSizingUniforms {\n u_colorBack: [number, number, number, number];\n u_colors: vec4[];\n u_colorsCount: number;\n u_count: number;\n u_size: number;\n u_noiseTexture?: HTMLImageElement;\n}\n\nexport interface MetaballsParams extends ShaderSizingParams, ShaderMotionParams {\n colorBack?: string;\n colors?: string[];\n count?: number;\n size?: number;\n}\n"], + "mappings": ";;;;;AAEA,eAAmE;AACnE,SAAS,WAAW,oBAAoB,uBAAuB;AAExD,MAAM,gBAAgB;AAAA,EAC3B,eAAe;AAAA,EACf,eAAe;AACjB;AAiCO,MAAM,0BAAkC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAQtB,cAAc,aAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUlD,SAAU;AAAA,EACV,kBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBA6BG,cAAc,aAAc;AAAA;AAAA;AAAA,wCAGZ,cAAc,aAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAwChE,eAAgB;AAAA;AAAA;AAAA;AAAA;", + "names": [] +} diff --git a/public/vendor/paper-shaders/shaders/neuro-noise.d.ts b/public/vendor/paper-shaders/shaders/neuro-noise.d.ts new file mode 100644 index 0000000..7ee1883 --- /dev/null +++ b/public/vendor/paper-shaders/shaders/neuro-noise.d.ts @@ -0,0 +1,49 @@ +import type { ShaderMotionParams } from '../shader-mount.js'; +import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js'; +/** + * A glowing, web-like structure of fluid lines and soft intersections. + * Great for creating atmospheric, organic-yet-futuristic visuals. + * + * Fragment shader uniforms: + * - u_time (float): Animation time + * - u_resolution (vec2): Canvas resolution in pixels + * - u_pixelRatio (float): Device pixel ratio + * - u_colorFront (vec4): Graphics highlight color in RGBA + * - u_colorMid (vec4): Graphics main color in RGBA + * - u_colorBack (vec4): Background color in RGBA + * - u_brightness (float): Luminosity of the crossing points (0 to 1) + * - u_contrast (float): Sharpness of the bright-dark transition (0 to 1) + * + * Vertex shader outputs (used in fragment shader): + * - v_patternUV (vec2): UV coordinates for pattern with global sizing (rotation, scale, offset, etc) applied + * + * Vertex shader uniforms: + * - u_resolution (vec2): Canvas resolution in pixels + * - u_pixelRatio (float): Device pixel ratio + * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1) + * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1) + * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas + * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas + * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover) + * - u_scale (float): Overall zoom level of the graphics (0.01 to 4) + * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360) + * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1) + * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1) + * + * Original algorithm: https://x.com/zozuar/status/1625182758745128981/ + */ +export declare const neuroNoiseFragmentShader: string; +export interface NeuroNoiseUniforms extends ShaderSizingUniforms { + u_colorFront: [number, number, number, number]; + u_colorMid: [number, number, number, number]; + u_colorBack: [number, number, number, number]; + u_brightness: number; + u_contrast: number; +} +export interface NeuroNoiseParams extends ShaderSizingParams, ShaderMotionParams { + colorFront?: string; + colorMid?: string; + colorBack?: string; + brightness?: number; + contrast?: number; +} diff --git a/public/vendor/paper-shaders/shaders/neuro-noise.js b/public/vendor/paper-shaders/shaders/neuro-noise.js new file mode 100644 index 0000000..29a5533 --- /dev/null +++ b/public/vendor/paper-shaders/shaders/neuro-noise.js @@ -0,0 +1,79 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Paper Shaders * + * https://github.com/paper-design/shaders * + * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +import {} from "../shader-sizing.js"; +import { rotation2, colorBandingFix } from "../shader-utils.js"; +const neuroNoiseFragmentShader = `#version 300 es +precision mediump float; + +uniform float u_time; +uniform vec2 u_resolution; +uniform float u_pixelRatio; + +uniform vec4 u_colorFront; +uniform vec4 u_colorMid; +uniform vec4 u_colorBack; +uniform float u_brightness; +uniform float u_contrast; + +in vec2 v_patternUV; + +out vec4 fragColor; + +${rotation2} + +float neuroShape(vec2 uv, float t) { + vec2 sine_acc = vec2(0.); + vec2 res = vec2(0.); + float scale = 8.; + + for (int j = 0; j < 15; j++) { + uv = rotate(uv, 1.); + sine_acc = rotate(sine_acc, 1.); + vec2 layer = uv * scale + float(j) + sine_acc - t; + sine_acc += sin(layer); + res += (.5 + .5 * cos(layer)) / scale; + scale *= (1.2); + } + return res.x + res.y; +} + +void main() { + vec2 shape_uv = v_patternUV; + shape_uv *= .13; + + float t = .5 * u_time; + + float noise = neuroShape(shape_uv, t); + + noise = (1. + u_brightness) * noise * noise; + noise = pow(noise, .7 + 6. * u_contrast); + noise = min(1.4, noise); + + float blend = smoothstep(0.7, 1.4, noise); + + vec4 frontC = u_colorFront; + frontC.rgb *= frontC.a; + vec4 midC = u_colorMid; + midC.rgb *= midC.a; + vec4 blendFront = mix(midC, frontC, blend); + + float safeNoise = max(noise, 0.0); + vec3 color = blendFront.rgb * safeNoise; + float opacity = clamp(blendFront.a * safeNoise, 0., 1.); + + vec3 bgColor = u_colorBack.rgb * u_colorBack.a; + color = color + bgColor * (1. - opacity); + opacity = opacity + u_colorBack.a * (1. - opacity); + + ${colorBandingFix} + + fragColor = vec4(color, opacity); +} +`; +export { + neuroNoiseFragmentShader +}; +//# sourceMappingURL=neuro-noise.js.map diff --git a/public/vendor/paper-shaders/shaders/neuro-noise.js.map b/public/vendor/paper-shaders/shaders/neuro-noise.js.map new file mode 100644 index 0000000..9280f31 --- /dev/null +++ b/public/vendor/paper-shaders/shaders/neuro-noise.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../../src/shaders/neuro-noise.ts"], + "sourcesContent": ["import type { ShaderMotionParams } from '../shader-mount.js';\nimport { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { rotation2, colorBandingFix } from '../shader-utils.js';\n\n/**\n * A glowing, web-like structure of fluid lines and soft intersections.\n * Great for creating atmospheric, organic-yet-futuristic visuals.\n *\n * Fragment shader uniforms:\n * - u_time (float): Animation time\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_colorFront (vec4): Graphics highlight color in RGBA\n * - u_colorMid (vec4): Graphics main color in RGBA\n * - u_colorBack (vec4): Background color in RGBA\n * - u_brightness (float): Luminosity of the crossing points (0 to 1)\n * - u_contrast (float): Sharpness of the bright-dark transition (0 to 1)\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_patternUV (vec2): UV coordinates for pattern with global sizing (rotation, scale, offset, etc) applied\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n *\n * Original algorithm: https://x.com/zozuar/status/1625182758745128981/\n */\n\n// language=GLSL\nexport const neuroNoiseFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform float u_time;\nuniform vec2 u_resolution;\nuniform float u_pixelRatio;\n\nuniform vec4 u_colorFront;\nuniform vec4 u_colorMid;\nuniform vec4 u_colorBack;\nuniform float u_brightness;\nuniform float u_contrast;\n\nin vec2 v_patternUV;\n\nout vec4 fragColor;\n\n${ rotation2 }\n\nfloat neuroShape(vec2 uv, float t) {\n vec2 sine_acc = vec2(0.);\n vec2 res = vec2(0.);\n float scale = 8.;\n\n for (int j = 0; j < 15; j++) {\n uv = rotate(uv, 1.);\n sine_acc = rotate(sine_acc, 1.);\n vec2 layer = uv * scale + float(j) + sine_acc - t;\n sine_acc += sin(layer);\n res += (.5 + .5 * cos(layer)) / scale;\n scale *= (1.2);\n }\n return res.x + res.y;\n}\n\nvoid main() {\n vec2 shape_uv = v_patternUV;\n shape_uv *= .13;\n\n float t = .5 * u_time;\n\n float noise = neuroShape(shape_uv, t);\n\n noise = (1. + u_brightness) * noise * noise;\n noise = pow(noise, .7 + 6. * u_contrast);\n noise = min(1.4, noise);\n\n float blend = smoothstep(0.7, 1.4, noise);\n\n vec4 frontC = u_colorFront;\n frontC.rgb *= frontC.a;\n vec4 midC = u_colorMid;\n midC.rgb *= midC.a;\n vec4 blendFront = mix(midC, frontC, blend);\n\n float safeNoise = max(noise, 0.0);\n vec3 color = blendFront.rgb * safeNoise;\n float opacity = clamp(blendFront.a * safeNoise, 0., 1.);\n\n vec3 bgColor = u_colorBack.rgb * u_colorBack.a;\n color = color + bgColor * (1. - opacity);\n opacity = opacity + u_colorBack.a * (1. - opacity);\n\n ${ colorBandingFix }\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface NeuroNoiseUniforms extends ShaderSizingUniforms {\n u_colorFront: [number, number, number, number];\n u_colorMid: [number, number, number, number];\n u_colorBack: [number, number, number, number];\n u_brightness: number;\n u_contrast: number;\n}\n\nexport interface NeuroNoiseParams extends ShaderSizingParams, ShaderMotionParams {\n colorFront?: string;\n colorMid?: string;\n colorBack?: string;\n brightness?: number;\n contrast?: number;\n}\n"], + "mappings": ";;;;;AACA,eAAmE;AACnE,SAAS,WAAW,uBAAuB;AAoCpC,MAAM,2BAAmC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiB7C,SAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA8CR,eAAgB;AAAA;AAAA;AAAA;AAAA;", + "names": [] +} diff --git a/public/vendor/paper-shaders/shaders/paper-texture.d.ts b/public/vendor/paper-shaders/shaders/paper-texture.d.ts new file mode 100644 index 0000000..9e8b324 --- /dev/null +++ b/public/vendor/paper-shaders/shaders/paper-texture.d.ts @@ -0,0 +1,78 @@ +import type { ShaderMotionParams } from '../shader-mount.js'; +import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js'; +/** + * A static texture built from multiple noise layers, usable for realistic paper and cardboard surfaces. + * Can be used as an image filter or as a standalone texture. + * + * Fragment shader uniforms: + * - u_resolution (vec2): Canvas resolution in pixels + * - u_pixelRatio (float): Device pixel ratio + * - u_image (sampler2D): Optional source image texture + * - u_imageAspectRatio (float): Aspect ratio of the source image + * - u_colorFront (vec4): Foreground color in RGBA + * - u_colorBack (vec4): Background color in RGBA + * - u_contrast (float): Blending behavior, sharper vs smoother color transitions (0 to 1) + * - u_roughness (float): Pixel noise, related to canvas and not scalable (0 to 1) + * - u_fiber (float): Curly-shaped noise intensity (0 to 1) + * - u_fiberSize (float): Curly-shaped noise scale (0 to 1) + * - u_crumples (float): Cell-based crumple pattern intensity (0 to 1) + * - u_crumpleSize (float): Cell-based crumple pattern scale (0 to 1) + * - u_folds (float): Depth of the folds (0 to 1) + * - u_foldCount (float): Number of folds (1 to 15) + * - u_fade (float): Big-scale noise mask applied to the pattern (0 to 1) + * - u_drops (float): Visibility of speckle pattern (0 to 1) + * - u_seed (float): Seed applied to folds, crumples and dots (0 to 1000) + * - u_noiseTexture (sampler2D): Pre-computed randomizer source texture + * + * Vertex shader outputs (used in fragment shader): + * - v_imageUV (vec2): UV coordinates for sampling the source image, with fit, scale, rotation, and offset applied + * + * Vertex shader uniforms: + * - u_resolution (vec2): Canvas resolution in pixels + * - u_pixelRatio (float): Device pixel ratio + * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1) + * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1) + * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas + * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas + * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover) + * - u_scale (float): Overall zoom level of the graphics (0.01 to 4) + * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360) + * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1) + * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1) + * - u_imageAspectRatio (float): Aspect ratio of the source image + * + */ +export declare const paperTextureFragmentShader: string; +export interface PaperTextureUniforms extends ShaderSizingUniforms { + u_image: HTMLImageElement | string | undefined; + u_noiseTexture?: HTMLImageElement; + u_colorFront: [number, number, number, number]; + u_colorBack: [number, number, number, number]; + u_contrast: number; + u_roughness: number; + u_fiber: number; + u_fiberSize: number; + u_crumples: number; + u_foldCount: number; + u_folds: number; + u_fade: number; + u_crumpleSize: number; + u_drops: number; + u_seed: number; +} +export interface PaperTextureParams extends ShaderSizingParams, ShaderMotionParams { + image?: HTMLImageElement | string; + colorFront?: string; + colorBack?: string; + contrast?: number; + roughness?: number; + fiber?: number; + fiberSize?: number; + crumples?: number; + foldCount?: number; + folds?: number; + fade?: number; + crumpleSize?: number; + drops?: number; + seed?: number; +} diff --git a/public/vendor/paper-shaders/shaders/paper-texture.js b/public/vendor/paper-shaders/shaders/paper-texture.js new file mode 100644 index 0000000..f926128 --- /dev/null +++ b/public/vendor/paper-shaders/shaders/paper-texture.js @@ -0,0 +1,248 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Paper Shaders * + * https://github.com/paper-design/shaders * + * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +import {} from "../shader-sizing.js"; +import { rotation2, declarePI, fiberNoise, textureRandomizerR } from "../shader-utils.js"; +const paperTextureFragmentShader = `#version 300 es +precision mediump float; + +uniform vec2 u_resolution; +uniform float u_pixelRatio; + +uniform vec4 u_colorFront; +uniform vec4 u_colorBack; + +uniform sampler2D u_image; +uniform float u_imageAspectRatio; + +uniform float u_contrast; +uniform float u_roughness; +uniform float u_fiber; +uniform float u_fiberSize; +uniform float u_crumples; +uniform float u_crumpleSize; +uniform float u_folds; +uniform float u_foldCount; +uniform float u_drops; +uniform float u_seed; +uniform float u_fade; + +uniform sampler2D u_noiseTexture; + +in vec2 v_imageUV; + +out vec4 fragColor; + +float getUvFrame(vec2 uv) { + float aax = 2. * fwidth(uv.x); + float aay = 2. * fwidth(uv.y); + + float left = smoothstep(0., aax, uv.x); + float right = 1. - smoothstep(1. - aax, 1., uv.x); + float bottom = smoothstep(0., aay, uv.y); + float top = 1. - smoothstep(1. - aay, 1., uv.y); + + return left * right * bottom * top; +} + +${declarePI} +${rotation2} +${textureRandomizerR} +float valueNoise(vec2 st) { + vec2 i = floor(st); + vec2 f = fract(st); + float a = randomR(i); + float b = randomR(i + vec2(1.0, 0.0)); + float c = randomR(i + vec2(0.0, 1.0)); + float d = randomR(i + vec2(1.0, 1.0)); + vec2 u = f * f * (3.0 - 2.0 * f); + float x1 = mix(a, b, u.x); + float x2 = mix(c, d, u.x); + return mix(x1, x2, u.y); +} +float fbm(vec2 n) { + float total = 0.0, amplitude = .4; + for (int i = 0; i < 3; i++) { + total += valueNoise(n) * amplitude; + n *= 1.99; + amplitude *= 0.65; + } + return total; +} + + +float randomG(vec2 p) { + vec2 uv = floor(p) / 50. + .5; + return texture(u_noiseTexture, fract(uv)).g; +} +float roughness(vec2 p) { + p *= .1; + float o = 0.; + for (float i = 0.; ++i < 4.; p *= 2.1) { + vec4 w = vec4(floor(p), ceil(p)); + vec2 f = fract(p); + o += mix( + mix(randomG(w.xy), randomG(w.xw), f.y), + mix(randomG(w.zy), randomG(w.zw), f.y), + f.x); + o += .2 / exp(2. * abs(sin(.2 * p.x + .5 * p.y))); + } + return o / 3.; +} + +${fiberNoise} + +vec2 randomGB(vec2 p) { + vec2 uv = floor(p) / 50. + .5; + return texture(u_noiseTexture, fract(uv)).gb; +} +float crumpledNoise(vec2 t, float pw) { + vec2 p = floor(t); + float wsum = 0.; + float cl = 0.; + for (int y = -1; y < 2; y += 1) { + for (int x = -1; x < 2; x += 1) { + vec2 b = vec2(float(x), float(y)); + vec2 q = b + p; + vec2 q2 = q - floor(q / 8.) * 8.; + vec2 c = q + randomGB(q2); + vec2 r = c - t; + float w = pow(smoothstep(0., 1., 1. - abs(r.x)), pw) * pow(smoothstep(0., 1., 1. - abs(r.y)), pw); + cl += (.5 + .5 * sin((q2.x + q2.y * 5.) * 8.)) * w; + wsum += w; + } + } + return pow(wsum != 0.0 ? cl / wsum : 0.0, .5) * 2.; +} +float crumplesShape(vec2 uv) { + return crumpledNoise(uv * .25, 16.) * crumpledNoise(uv * .5, 2.); +} + + +vec2 folds(vec2 uv) { + vec3 pp = vec3(0.); + float l = 9.; + for (float i = 0.; i < 15.; i++) { + if (i >= u_foldCount) break; + vec2 rand = randomGB(vec2(i, i * u_seed)); + float an = rand.x * TWO_PI; + vec2 p = vec2(cos(an), sin(an)) * rand.y; + float dist = distance(uv, p); + l = min(l, dist); + + if (l == dist) { + pp.xy = (uv - p.xy); + pp.z = dist; + } + } + return mix(pp.xy, vec2(0.), pow(pp.z, .25)); +} + +float drops(vec2 uv) { + vec2 iDropsUV = floor(uv); + vec2 fDropsUV = fract(uv); + float dropsMinDist = 1.; + for (int j = -1; j <= 1; j++) { + for (int i = -1; i <= 1; i++) { + vec2 neighbor = vec2(float(i), float(j)); + vec2 offset = randomGB(iDropsUV + neighbor); + offset = .5 + .5 * sin(10. * u_seed + TWO_PI * offset); + vec2 pos = neighbor + offset - fDropsUV; + float dist = length(pos); + dropsMinDist = min(dropsMinDist, dropsMinDist*dist); + } + } + return 1. - smoothstep(.05, .09, pow(dropsMinDist, .5)); +} + +float lst(float edge0, float edge1, float x) { + return clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0); +} + +void main() { + + vec2 imageUV = v_imageUV; + vec2 patternUV = v_imageUV - .5; + patternUV = 5. * (patternUV * vec2(u_imageAspectRatio, 1.)); + + vec2 roughnessUv = 1.5 * (gl_FragCoord.xy - .5 * u_resolution) / u_pixelRatio; + float roughness = roughness(roughnessUv + vec2(1., 0.)) - roughness(roughnessUv - vec2(1., 0.)); + + vec2 crumplesUV = fract(patternUV * .02 / u_crumpleSize - u_seed) * 32.; + float crumples = u_crumples * (crumplesShape(crumplesUV + vec2(.05, 0.)) - crumplesShape(crumplesUV)); + + vec2 fiberUV = 2. / u_fiberSize * patternUV; + float fiber = fiberNoise(fiberUV, vec2(0.)); + fiber = .5 * u_fiber * (fiber - 1.); + + vec2 normal = vec2(0.); + vec2 normalImage = vec2(0.); + + vec2 foldsUV = patternUV * .12; + foldsUV = rotate(foldsUV, 4. * u_seed); + vec2 w = folds(foldsUV); + foldsUV = rotate(foldsUV + .007 * cos(u_seed), .01 * sin(u_seed)); + vec2 w2 = folds(foldsUV); + + float drops = u_drops * drops(patternUV * 2.); + + float fade = u_fade * fbm(.17 * patternUV + 10. * u_seed); + fade = clamp(8. * fade * fade * fade, 0., 1.); + + w = mix(w, vec2(0.), fade); + w2 = mix(w2, vec2(0.), fade); + crumples = mix(crumples, 0., fade); + drops = mix(drops, 0., fade); + fiber *= mix(1., .5, fade); + roughness *= mix(1., .5, fade); + + normal.xy += u_folds * min(5. * u_contrast, 1.) * 4. * max(vec2(0.), w + w2); + normalImage.xy += u_folds * 2. * w; + + normal.xy += crumples; + normalImage.xy += 1.5 * crumples; + + normal.xy += 3. * drops; + normalImage.xy += .2 * drops; + + normal.xy += u_roughness * 1.5 * roughness; + normal.xy += fiber; + + normalImage += u_roughness * .75 * roughness; + normalImage += .2 * fiber; + + vec3 lightPos = vec3(1., 2., 1.); + float res = dot(normalize(vec3(normal, 9.5 - 9. * pow(u_contrast, .1))), normalize(lightPos)); + + vec3 fgColor = u_colorFront.rgb * u_colorFront.a; + float fgOpacity = u_colorFront.a; + vec3 bgColor = u_colorBack.rgb * u_colorBack.a; + float bgOpacity = u_colorBack.a; + + imageUV += .02 * normalImage; + float frame = getUvFrame(imageUV); + vec4 image = texture(u_image, imageUV); + image.rgb += .6 * pow(u_contrast, .4) * (res - .7); + + frame *= image.a; + + vec3 color = fgColor * res; + float opacity = fgOpacity * res; + + color += bgColor * (1. - opacity); + opacity += bgOpacity * (1. - opacity); + opacity = mix(opacity, 1., frame); + + color -= .007 * drops; + + color.rgb = mix(color, image.rgb, frame); + + fragColor = vec4(color, opacity); +} +`; +export { + paperTextureFragmentShader +}; +//# sourceMappingURL=paper-texture.js.map diff --git a/public/vendor/paper-shaders/shaders/paper-texture.js.map b/public/vendor/paper-shaders/shaders/paper-texture.js.map new file mode 100644 index 0000000..d189405 --- /dev/null +++ b/public/vendor/paper-shaders/shaders/paper-texture.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../../src/shaders/paper-texture.ts"], + "sourcesContent": ["import type { ShaderMotionParams } from '../shader-mount.js';\nimport { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { rotation2, declarePI, fiberNoise, textureRandomizerR } from '../shader-utils.js';\n\n/**\n * A static texture built from multiple noise layers, usable for realistic paper and cardboard surfaces.\n * Can be used as an image filter or as a standalone texture.\n *\n * Fragment shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_image (sampler2D): Optional source image texture\n * - u_imageAspectRatio (float): Aspect ratio of the source image\n * - u_colorFront (vec4): Foreground color in RGBA\n * - u_colorBack (vec4): Background color in RGBA\n * - u_contrast (float): Blending behavior, sharper vs smoother color transitions (0 to 1)\n * - u_roughness (float): Pixel noise, related to canvas and not scalable (0 to 1)\n * - u_fiber (float): Curly-shaped noise intensity (0 to 1)\n * - u_fiberSize (float): Curly-shaped noise scale (0 to 1)\n * - u_crumples (float): Cell-based crumple pattern intensity (0 to 1)\n * - u_crumpleSize (float): Cell-based crumple pattern scale (0 to 1)\n * - u_folds (float): Depth of the folds (0 to 1)\n * - u_foldCount (float): Number of folds (1 to 15)\n * - u_fade (float): Big-scale noise mask applied to the pattern (0 to 1)\n * - u_drops (float): Visibility of speckle pattern (0 to 1)\n * - u_seed (float): Seed applied to folds, crumples and dots (0 to 1000)\n * - u_noiseTexture (sampler2D): Pre-computed randomizer source texture\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_imageUV (vec2): UV coordinates for sampling the source image, with fit, scale, rotation, and offset applied\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n * - u_imageAspectRatio (float): Aspect ratio of the source image\n *\n */\n\n// language=GLSL\nexport const paperTextureFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform vec2 u_resolution;\nuniform float u_pixelRatio;\n\nuniform vec4 u_colorFront;\nuniform vec4 u_colorBack;\n\nuniform sampler2D u_image;\nuniform float u_imageAspectRatio;\n\nuniform float u_contrast;\nuniform float u_roughness;\nuniform float u_fiber;\nuniform float u_fiberSize;\nuniform float u_crumples;\nuniform float u_crumpleSize;\nuniform float u_folds;\nuniform float u_foldCount;\nuniform float u_drops;\nuniform float u_seed;\nuniform float u_fade;\n\nuniform sampler2D u_noiseTexture;\n\nin vec2 v_imageUV;\n\nout vec4 fragColor;\n\nfloat getUvFrame(vec2 uv) {\n float aax = 2. * fwidth(uv.x);\n float aay = 2. * fwidth(uv.y);\n\n float left = smoothstep(0., aax, uv.x);\n float right = 1. - smoothstep(1. - aax, 1., uv.x);\n float bottom = smoothstep(0., aay, uv.y);\n float top = 1. - smoothstep(1. - aay, 1., uv.y);\n\n return left * right * bottom * top;\n}\n\n${ declarePI }\n${ rotation2 }\n${ textureRandomizerR }\nfloat valueNoise(vec2 st) {\n vec2 i = floor(st);\n vec2 f = fract(st);\n float a = randomR(i);\n float b = randomR(i + vec2(1.0, 0.0));\n float c = randomR(i + vec2(0.0, 1.0));\n float d = randomR(i + vec2(1.0, 1.0));\n vec2 u = f * f * (3.0 - 2.0 * f);\n float x1 = mix(a, b, u.x);\n float x2 = mix(c, d, u.x);\n return mix(x1, x2, u.y);\n}\nfloat fbm(vec2 n) {\n float total = 0.0, amplitude = .4;\n for (int i = 0; i < 3; i++) {\n total += valueNoise(n) * amplitude;\n n *= 1.99;\n amplitude *= 0.65;\n }\n return total;\n}\n\n\nfloat randomG(vec2 p) {\n vec2 uv = floor(p) / 50. + .5;\n return texture(u_noiseTexture, fract(uv)).g;\n}\nfloat roughness(vec2 p) {\n p *= .1;\n float o = 0.;\n for (float i = 0.; ++i < 4.; p *= 2.1) {\n vec4 w = vec4(floor(p), ceil(p));\n vec2 f = fract(p);\n o += mix(\n mix(randomG(w.xy), randomG(w.xw), f.y),\n mix(randomG(w.zy), randomG(w.zw), f.y),\n f.x);\n o += .2 / exp(2. * abs(sin(.2 * p.x + .5 * p.y)));\n }\n return o / 3.;\n}\n\n${ fiberNoise }\n\nvec2 randomGB(vec2 p) {\n vec2 uv = floor(p) / 50. + .5;\n return texture(u_noiseTexture, fract(uv)).gb;\n}\nfloat crumpledNoise(vec2 t, float pw) {\n vec2 p = floor(t);\n float wsum = 0.;\n float cl = 0.;\n for (int y = -1; y < 2; y += 1) {\n for (int x = -1; x < 2; x += 1) {\n vec2 b = vec2(float(x), float(y));\n vec2 q = b + p;\n vec2 q2 = q - floor(q / 8.) * 8.;\n vec2 c = q + randomGB(q2);\n vec2 r = c - t;\n float w = pow(smoothstep(0., 1., 1. - abs(r.x)), pw) * pow(smoothstep(0., 1., 1. - abs(r.y)), pw);\n cl += (.5 + .5 * sin((q2.x + q2.y * 5.) * 8.)) * w;\n wsum += w;\n }\n }\n return pow(wsum != 0.0 ? cl / wsum : 0.0, .5) * 2.;\n}\nfloat crumplesShape(vec2 uv) {\n return crumpledNoise(uv * .25, 16.) * crumpledNoise(uv * .5, 2.);\n}\n\n\nvec2 folds(vec2 uv) {\n vec3 pp = vec3(0.);\n float l = 9.;\n for (float i = 0.; i < 15.; i++) {\n if (i >= u_foldCount) break;\n vec2 rand = randomGB(vec2(i, i * u_seed));\n float an = rand.x * TWO_PI;\n vec2 p = vec2(cos(an), sin(an)) * rand.y;\n float dist = distance(uv, p);\n l = min(l, dist);\n\n if (l == dist) {\n pp.xy = (uv - p.xy);\n pp.z = dist;\n }\n }\n return mix(pp.xy, vec2(0.), pow(pp.z, .25));\n}\n\nfloat drops(vec2 uv) {\n vec2 iDropsUV = floor(uv);\n vec2 fDropsUV = fract(uv);\n float dropsMinDist = 1.;\n for (int j = -1; j <= 1; j++) {\n for (int i = -1; i <= 1; i++) {\n vec2 neighbor = vec2(float(i), float(j));\n vec2 offset = randomGB(iDropsUV + neighbor);\n offset = .5 + .5 * sin(10. * u_seed + TWO_PI * offset);\n vec2 pos = neighbor + offset - fDropsUV;\n float dist = length(pos);\n dropsMinDist = min(dropsMinDist, dropsMinDist*dist);\n }\n }\n return 1. - smoothstep(.05, .09, pow(dropsMinDist, .5));\n}\n\nfloat lst(float edge0, float edge1, float x) {\n return clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);\n}\n\nvoid main() {\n\n vec2 imageUV = v_imageUV;\n vec2 patternUV = v_imageUV - .5;\n patternUV = 5. * (patternUV * vec2(u_imageAspectRatio, 1.));\n\n vec2 roughnessUv = 1.5 * (gl_FragCoord.xy - .5 * u_resolution) / u_pixelRatio;\n float roughness = roughness(roughnessUv + vec2(1., 0.)) - roughness(roughnessUv - vec2(1., 0.));\n\n vec2 crumplesUV = fract(patternUV * .02 / u_crumpleSize - u_seed) * 32.;\n float crumples = u_crumples * (crumplesShape(crumplesUV + vec2(.05, 0.)) - crumplesShape(crumplesUV));\n\n vec2 fiberUV = 2. / u_fiberSize * patternUV;\n float fiber = fiberNoise(fiberUV, vec2(0.));\n fiber = .5 * u_fiber * (fiber - 1.);\n\n vec2 normal = vec2(0.);\n vec2 normalImage = vec2(0.);\n\n vec2 foldsUV = patternUV * .12;\n foldsUV = rotate(foldsUV, 4. * u_seed);\n vec2 w = folds(foldsUV);\n foldsUV = rotate(foldsUV + .007 * cos(u_seed), .01 * sin(u_seed));\n vec2 w2 = folds(foldsUV);\n\n float drops = u_drops * drops(patternUV * 2.);\n\n float fade = u_fade * fbm(.17 * patternUV + 10. * u_seed);\n fade = clamp(8. * fade * fade * fade, 0., 1.);\n\n w = mix(w, vec2(0.), fade);\n w2 = mix(w2, vec2(0.), fade);\n crumples = mix(crumples, 0., fade);\n drops = mix(drops, 0., fade);\n fiber *= mix(1., .5, fade);\n roughness *= mix(1., .5, fade);\n\n normal.xy += u_folds * min(5. * u_contrast, 1.) * 4. * max(vec2(0.), w + w2);\n normalImage.xy += u_folds * 2. * w;\n\n normal.xy += crumples;\n normalImage.xy += 1.5 * crumples;\n\n normal.xy += 3. * drops;\n normalImage.xy += .2 * drops;\n\n normal.xy += u_roughness * 1.5 * roughness;\n normal.xy += fiber;\n\n normalImage += u_roughness * .75 * roughness;\n normalImage += .2 * fiber;\n\n vec3 lightPos = vec3(1., 2., 1.);\n float res = dot(normalize(vec3(normal, 9.5 - 9. * pow(u_contrast, .1))), normalize(lightPos));\n\n vec3 fgColor = u_colorFront.rgb * u_colorFront.a;\n float fgOpacity = u_colorFront.a;\n vec3 bgColor = u_colorBack.rgb * u_colorBack.a;\n float bgOpacity = u_colorBack.a;\n\n imageUV += .02 * normalImage;\n float frame = getUvFrame(imageUV);\n vec4 image = texture(u_image, imageUV);\n image.rgb += .6 * pow(u_contrast, .4) * (res - .7);\n\n frame *= image.a;\n\n vec3 color = fgColor * res;\n float opacity = fgOpacity * res;\n\n color += bgColor * (1. - opacity);\n opacity += bgOpacity * (1. - opacity);\n opacity = mix(opacity, 1., frame);\n\n color -= .007 * drops;\n\n color.rgb = mix(color, image.rgb, frame);\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface PaperTextureUniforms extends ShaderSizingUniforms {\n u_image: HTMLImageElement | string | undefined;\n u_noiseTexture?: HTMLImageElement;\n u_colorFront: [number, number, number, number];\n u_colorBack: [number, number, number, number];\n u_contrast: number;\n u_roughness: number;\n u_fiber: number;\n u_fiberSize: number;\n u_crumples: number;\n u_foldCount: number;\n u_folds: number;\n u_fade: number;\n u_crumpleSize: number;\n u_drops: number;\n u_seed: number;\n}\n\nexport interface PaperTextureParams extends ShaderSizingParams, ShaderMotionParams {\n image?: HTMLImageElement | string;\n colorFront?: string;\n colorBack?: string;\n contrast?: number;\n roughness?: number;\n fiber?: number;\n fiberSize?: number;\n crumples?: number;\n foldCount?: number;\n folds?: number;\n fade?: number;\n crumpleSize?: number;\n drops?: number;\n seed?: number;\n}\n"], + "mappings": ";;;;;AACA,eAAmE;AACnE,SAAS,WAAW,WAAW,YAAY,0BAA0B;AA8C9D,MAAM,6BAAqC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA0C/C,SAAU;AAAA,EACV,SAAU;AAAA,EACV,kBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA2CnB,UAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;", + "names": [] +} diff --git a/public/vendor/paper-shaders/shaders/perlin-noise.d.ts b/public/vendor/paper-shaders/shaders/perlin-noise.d.ts new file mode 100644 index 0000000..b7cf4aa --- /dev/null +++ b/public/vendor/paper-shaders/shaders/perlin-noise.d.ts @@ -0,0 +1,52 @@ +import type { ShaderMotionParams } from '../shader-mount.js'; +import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js'; +/** + * Classic animated 3D Perlin noise with exposed controls. + * Original algorithm: https://www.shadertoy.com/view/NlSGDz + * + * Fragment shader uniforms: + * - u_time (float): Animation time + * - u_colorFront (vec4): Foreground color in RGBA + * - u_colorBack (vec4): Background color in RGBA + * - u_proportion (float): Blend point between 2 colors, 0.5 = equal distribution (0 to 1) + * - u_softness (float): Color transition sharpness, 0 = hard edge, 1 = smooth gradient (0 to 1) + * - u_octaveCount (float): Perlin noise octaves number, more octaves for more detailed patterns (1 to 8) + * - u_persistence (float): Roughness, falloff between octaves (0.3 to 1) + * - u_lacunarity (float): Frequency step, defines how compressed the pattern is (1.5 to 10) + * + * Vertex shader outputs (used in fragment shader): + * - v_patternUV (vec2): UV coordinates for pattern with global sizing (rotation, scale, offset, etc) applied + * + * Vertex shader uniforms: + * - u_resolution (vec2): Canvas resolution in pixels + * - u_pixelRatio (float): Device pixel ratio + * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1) + * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1) + * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas + * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas + * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover) + * - u_scale (float): Overall zoom level of the graphics (0.01 to 4) + * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360) + * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1) + * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1) + * + */ +export declare const perlinNoiseFragmentShader: string; +export interface PerlinNoiseUniforms extends ShaderSizingUniforms { + u_colorFront: [number, number, number, number]; + u_colorBack: [number, number, number, number]; + u_proportion: number; + u_softness: number; + u_octaveCount: number; + u_persistence: number; + u_lacunarity: number; +} +export interface PerlinNoiseParams extends ShaderSizingParams, ShaderMotionParams { + colorFront?: string; + colorBack?: string; + proportion?: number; + softness?: number; + octaveCount?: number; + persistence?: number; + lacunarity?: number; +} diff --git a/public/vendor/paper-shaders/shaders/perlin-noise.js b/public/vendor/paper-shaders/shaders/perlin-noise.js new file mode 100644 index 0000000..941bff1 --- /dev/null +++ b/public/vendor/paper-shaders/shaders/perlin-noise.js @@ -0,0 +1,173 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Paper Shaders * + * https://github.com/paper-design/shaders * + * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +import {} from "../shader-sizing.js"; +import { declarePI, colorBandingFix, proceduralHash11, proceduralHash21 } from "../shader-utils.js"; +const perlinNoiseFragmentShader = `#version 300 es +precision mediump float; + +uniform float u_time; + +uniform vec4 u_colorFront; +uniform vec4 u_colorBack; +uniform float u_proportion; +uniform float u_softness; +uniform float u_octaveCount; +uniform float u_persistence; +uniform float u_lacunarity; + +in vec2 v_patternUV; + +out vec4 fragColor; + +${declarePI} +${proceduralHash11} +${proceduralHash21} + +float hash31(vec3 p) { + p = fract(p * 0.3183099) + 0.1; + p += dot(p, p.yzx + 19.19); + return fract(p.x * (p.y + p.z)); +} + +vec3 gradientPredefined(float hash) { + int idx = int(hash * 12.0) % 12; + + if (idx == 0) return vec3(1, 1, 0); + if (idx == 1) return vec3(-1, 1, 0); + if (idx == 2) return vec3(1, -1, 0); + if (idx == 3) return vec3(-1, -1, 0); + if (idx == 4) return vec3(1, 0, 1); + if (idx == 5) return vec3(-1, 0, 1); + if (idx == 6) return vec3(1, 0, -1); + if (idx == 7) return vec3(-1, 0, -1); + if (idx == 8) return vec3(0, 1, 1); + if (idx == 9) return vec3(0, -1, 1); + if (idx == 10) return vec3(0, 1, -1); + return vec3(0, -1, -1);// idx == 11 +} + +float interpolateSafe(float v000, float v001, float v010, float v011, +float v100, float v101, float v110, float v111, vec3 t) { + t = clamp(t, 0.0, 1.0); + + float v00 = mix(v000, v100, t.x); + float v01 = mix(v001, v101, t.x); + float v10 = mix(v010, v110, t.x); + float v11 = mix(v011, v111, t.x); + + float v0 = mix(v00, v10, t.y); + float v1 = mix(v01, v11, t.y); + + return mix(v0, v1, t.z); +} + +vec3 fade(vec3 t) { + return t * t * t * (t * (t * 6.0 - 15.0) + 10.0); +} + +float perlinNoise(vec3 position, float seed) { + position += vec3(seed * 127.1, seed * 311.7, seed * 74.7); + + vec3 i = floor(position); + vec3 f = fract(position); + float h000 = hash31(i); + float h001 = hash31(i + vec3(0, 0, 1)); + float h010 = hash31(i + vec3(0, 1, 0)); + float h011 = hash31(i + vec3(0, 1, 1)); + float h100 = hash31(i + vec3(1, 0, 0)); + float h101 = hash31(i + vec3(1, 0, 1)); + float h110 = hash31(i + vec3(1, 1, 0)); + float h111 = hash31(i + vec3(1, 1, 1)); + vec3 g000 = gradientPredefined(h000); + vec3 g001 = gradientPredefined(h001); + vec3 g010 = gradientPredefined(h010); + vec3 g011 = gradientPredefined(h011); + vec3 g100 = gradientPredefined(h100); + vec3 g101 = gradientPredefined(h101); + vec3 g110 = gradientPredefined(h110); + vec3 g111 = gradientPredefined(h111); + float v000 = dot(g000, f - vec3(0, 0, 0)); + float v001 = dot(g001, f - vec3(0, 0, 1)); + float v010 = dot(g010, f - vec3(0, 1, 0)); + float v011 = dot(g011, f - vec3(0, 1, 1)); + float v100 = dot(g100, f - vec3(1, 0, 0)); + float v101 = dot(g101, f - vec3(1, 0, 1)); + float v110 = dot(g110, f - vec3(1, 1, 0)); + float v111 = dot(g111, f - vec3(1, 1, 1)); + + vec3 u = fade(f); + return interpolateSafe(v000, v001, v010, v011, v100, v101, v110, v111, u); +} + +float p_noise(vec3 position, int octaveCount, float persistence, float lacunarity) { + float value = 0.0; + float amplitude = 1.0; + float frequency = 10.0; + float maxValue = 0.0; + octaveCount = clamp(octaveCount, 1, 8); + + for (int i = 0; i < octaveCount; i++) { + float seed = float(i) * 0.7319; + value += perlinNoise(position * frequency, seed) * amplitude; + maxValue += amplitude; + amplitude *= persistence; + frequency *= lacunarity; + } + return value; +} + +float get_max_amp(float persistence, float octaveCount) { + persistence = clamp(persistence * 0.999, 0.0, 0.999); + octaveCount = clamp(octaveCount, 1.0, 8.0); + + if (abs(persistence - 1.0) < 0.001) { + return octaveCount; + } + + return (1.0 - pow(persistence, octaveCount)) / max(1e-4, (1.0 - persistence)); +} + +void main() { + vec2 uv = v_patternUV; + uv *= .5; + + float t = .2 * u_time; + + vec3 p = vec3(uv, t); + + float octCount = floor(u_octaveCount); + float noise = p_noise(p, int(octCount), u_persistence, u_lacunarity); + + float max_amp = get_max_amp(u_persistence, octCount); + float noise_normalized = clamp((noise + max_amp) / max(1e-4, (2. * max_amp)) + (u_proportion - .5), 0.0, 1.0); + float sharpness = clamp(u_softness, 0., 1.); + float smooth_w = 0.5 * max(fwidth(noise_normalized), 0.001); + float res = smoothstep( + .5 - .5 * sharpness - smooth_w, + .5 + .5 * sharpness + smooth_w, + noise_normalized + ); + + vec3 fgColor = u_colorFront.rgb * u_colorFront.a; + float fgOpacity = u_colorFront.a; + vec3 bgColor = u_colorBack.rgb * u_colorBack.a; + float bgOpacity = u_colorBack.a; + + vec3 color = fgColor * res; + float opacity = fgOpacity * res; + + color += bgColor * (1. - opacity); + opacity += bgOpacity * (1. - opacity); + + ${colorBandingFix} + + fragColor = vec4(color, opacity); +} +`; +export { + perlinNoiseFragmentShader +}; +//# sourceMappingURL=perlin-noise.js.map diff --git a/public/vendor/paper-shaders/shaders/perlin-noise.js.map b/public/vendor/paper-shaders/shaders/perlin-noise.js.map new file mode 100644 index 0000000..500a8d6 --- /dev/null +++ b/public/vendor/paper-shaders/shaders/perlin-noise.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../../src/shaders/perlin-noise.ts"], + "sourcesContent": ["import type { ShaderMotionParams } from '../shader-mount.js';\nimport { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { declarePI, colorBandingFix, proceduralHash11, proceduralHash21 } from '../shader-utils.js';\n\n/**\n * Classic animated 3D Perlin noise with exposed controls.\n * Original algorithm: https://www.shadertoy.com/view/NlSGDz\n *\n * Fragment shader uniforms:\n * - u_time (float): Animation time\n * - u_colorFront (vec4): Foreground color in RGBA\n * - u_colorBack (vec4): Background color in RGBA\n * - u_proportion (float): Blend point between 2 colors, 0.5 = equal distribution (0 to 1)\n * - u_softness (float): Color transition sharpness, 0 = hard edge, 1 = smooth gradient (0 to 1)\n * - u_octaveCount (float): Perlin noise octaves number, more octaves for more detailed patterns (1 to 8)\n * - u_persistence (float): Roughness, falloff between octaves (0.3 to 1)\n * - u_lacunarity (float): Frequency step, defines how compressed the pattern is (1.5 to 10)\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_patternUV (vec2): UV coordinates for pattern with global sizing (rotation, scale, offset, etc) applied\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n *\n */\n\n// language=GLSL\nexport const perlinNoiseFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform float u_time;\n\nuniform vec4 u_colorFront;\nuniform vec4 u_colorBack;\nuniform float u_proportion;\nuniform float u_softness;\nuniform float u_octaveCount;\nuniform float u_persistence;\nuniform float u_lacunarity;\n\nin vec2 v_patternUV;\n\nout vec4 fragColor;\n\n${ declarePI }\n${ proceduralHash11 }\n${ proceduralHash21 }\n\nfloat hash31(vec3 p) {\n p = fract(p * 0.3183099) + 0.1;\n p += dot(p, p.yzx + 19.19);\n return fract(p.x * (p.y + p.z));\n}\n\nvec3 gradientPredefined(float hash) {\n int idx = int(hash * 12.0) % 12;\n\n if (idx == 0) return vec3(1, 1, 0);\n if (idx == 1) return vec3(-1, 1, 0);\n if (idx == 2) return vec3(1, -1, 0);\n if (idx == 3) return vec3(-1, -1, 0);\n if (idx == 4) return vec3(1, 0, 1);\n if (idx == 5) return vec3(-1, 0, 1);\n if (idx == 6) return vec3(1, 0, -1);\n if (idx == 7) return vec3(-1, 0, -1);\n if (idx == 8) return vec3(0, 1, 1);\n if (idx == 9) return vec3(0, -1, 1);\n if (idx == 10) return vec3(0, 1, -1);\n return vec3(0, -1, -1);// idx == 11\n}\n\nfloat interpolateSafe(float v000, float v001, float v010, float v011,\nfloat v100, float v101, float v110, float v111, vec3 t) {\n t = clamp(t, 0.0, 1.0);\n\n float v00 = mix(v000, v100, t.x);\n float v01 = mix(v001, v101, t.x);\n float v10 = mix(v010, v110, t.x);\n float v11 = mix(v011, v111, t.x);\n\n float v0 = mix(v00, v10, t.y);\n float v1 = mix(v01, v11, t.y);\n\n return mix(v0, v1, t.z);\n}\n\nvec3 fade(vec3 t) {\n return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);\n}\n\nfloat perlinNoise(vec3 position, float seed) {\n position += vec3(seed * 127.1, seed * 311.7, seed * 74.7);\n\n vec3 i = floor(position);\n vec3 f = fract(position);\n float h000 = hash31(i);\n float h001 = hash31(i + vec3(0, 0, 1));\n float h010 = hash31(i + vec3(0, 1, 0));\n float h011 = hash31(i + vec3(0, 1, 1));\n float h100 = hash31(i + vec3(1, 0, 0));\n float h101 = hash31(i + vec3(1, 0, 1));\n float h110 = hash31(i + vec3(1, 1, 0));\n float h111 = hash31(i + vec3(1, 1, 1));\n vec3 g000 = gradientPredefined(h000);\n vec3 g001 = gradientPredefined(h001);\n vec3 g010 = gradientPredefined(h010);\n vec3 g011 = gradientPredefined(h011);\n vec3 g100 = gradientPredefined(h100);\n vec3 g101 = gradientPredefined(h101);\n vec3 g110 = gradientPredefined(h110);\n vec3 g111 = gradientPredefined(h111);\n float v000 = dot(g000, f - vec3(0, 0, 0));\n float v001 = dot(g001, f - vec3(0, 0, 1));\n float v010 = dot(g010, f - vec3(0, 1, 0));\n float v011 = dot(g011, f - vec3(0, 1, 1));\n float v100 = dot(g100, f - vec3(1, 0, 0));\n float v101 = dot(g101, f - vec3(1, 0, 1));\n float v110 = dot(g110, f - vec3(1, 1, 0));\n float v111 = dot(g111, f - vec3(1, 1, 1));\n\n vec3 u = fade(f);\n return interpolateSafe(v000, v001, v010, v011, v100, v101, v110, v111, u);\n}\n\nfloat p_noise(vec3 position, int octaveCount, float persistence, float lacunarity) {\n float value = 0.0;\n float amplitude = 1.0;\n float frequency = 10.0;\n float maxValue = 0.0;\n octaveCount = clamp(octaveCount, 1, 8);\n\n for (int i = 0; i < octaveCount; i++) {\n float seed = float(i) * 0.7319;\n value += perlinNoise(position * frequency, seed) * amplitude;\n maxValue += amplitude;\n amplitude *= persistence;\n frequency *= lacunarity;\n }\n return value;\n}\n\nfloat get_max_amp(float persistence, float octaveCount) {\n persistence = clamp(persistence * 0.999, 0.0, 0.999);\n octaveCount = clamp(octaveCount, 1.0, 8.0);\n\n if (abs(persistence - 1.0) < 0.001) {\n return octaveCount;\n }\n\n return (1.0 - pow(persistence, octaveCount)) / max(1e-4, (1.0 - persistence));\n}\n\nvoid main() {\n vec2 uv = v_patternUV;\n uv *= .5;\n\n float t = .2 * u_time;\n\n vec3 p = vec3(uv, t);\n\n float octCount = floor(u_octaveCount);\n float noise = p_noise(p, int(octCount), u_persistence, u_lacunarity);\n\n float max_amp = get_max_amp(u_persistence, octCount);\n float noise_normalized = clamp((noise + max_amp) / max(1e-4, (2. * max_amp)) + (u_proportion - .5), 0.0, 1.0);\n float sharpness = clamp(u_softness, 0., 1.);\n float smooth_w = 0.5 * max(fwidth(noise_normalized), 0.001);\n float res = smoothstep(\n .5 - .5 * sharpness - smooth_w,\n .5 + .5 * sharpness + smooth_w,\n noise_normalized\n );\n\n vec3 fgColor = u_colorFront.rgb * u_colorFront.a;\n float fgOpacity = u_colorFront.a;\n vec3 bgColor = u_colorBack.rgb * u_colorBack.a;\n float bgOpacity = u_colorBack.a;\n\n vec3 color = fgColor * res;\n float opacity = fgOpacity * res;\n\n color += bgColor * (1. - opacity);\n opacity += bgOpacity * (1. - opacity);\n\n ${ colorBandingFix }\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface PerlinNoiseUniforms extends ShaderSizingUniforms {\n u_colorFront: [number, number, number, number];\n u_colorBack: [number, number, number, number];\n u_proportion: number;\n u_softness: number;\n u_octaveCount: number;\n u_persistence: number;\n u_lacunarity: number;\n}\n\nexport interface PerlinNoiseParams extends ShaderSizingParams, ShaderMotionParams {\n colorFront?: string;\n colorBack?: string;\n proportion?: number;\n softness?: number;\n octaveCount?: number;\n persistence?: number;\n lacunarity?: number;\n}\n"], + "mappings": ";;;;;AACA,eAAmE;AACnE,SAAS,WAAW,iBAAiB,kBAAkB,wBAAwB;AAmCxE,MAAM,4BAAoC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiB9C,SAAU;AAAA,EACV,gBAAiB;AAAA,EACjB,gBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA0If,eAAgB;AAAA;AAAA;AAAA;AAAA;", + "names": [] +} diff --git a/public/vendor/paper-shaders/shaders/pulsing-border.d.ts b/public/vendor/paper-shaders/shaders/pulsing-border.d.ts new file mode 100644 index 0000000..06dace6 --- /dev/null +++ b/public/vendor/paper-shaders/shaders/pulsing-border.d.ts @@ -0,0 +1,98 @@ +import type { vec4 } from '../types.js'; +import type { ShaderMotionParams } from '../shader-mount.js'; +import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js'; +export declare const pulsingBorderMeta: { + readonly maxColorCount: 5; + readonly maxSpots: 4; +}; +/** + * Luminous trails of color merging into a glowing gradient contour. + * + * Fragment shader uniforms: + * - u_time (float): Animation time + * - u_colorBack (vec4): Background color in RGBA + * - u_colors (vec4[]): Up to 5 spot colors in RGBA + * - u_colorsCount (float): Number of active colors + * - u_roundness (float): Border radius (0 to 1) + * - u_thickness (float): Border base width (0 to 1) + * - u_softness (float): Border edge sharpness, 0 = hard edge, 1 = smooth gradient (0 to 1) + * - u_marginLeft (float): Distance from the left edge to the effect (0 to 1) + * - u_marginRight (float): Distance from the right edge to the effect (0 to 1) + * - u_marginTop (float): Distance from the top edge to the effect (0 to 1) + * - u_marginBottom (float): Distance from the bottom edge to the effect (0 to 1) + * - u_aspectRatio (float): Aspect ratio mode (0 = auto, 1 = square) + * - u_intensity (float): Thickness of individual color spots (0 to 1) + * - u_bloom (float): Power of glow, 0 = normal blending, 1 = additive blending (0 to 1) + * - u_spots (float): Number of spots added for each color (1 to 20) + * - u_spotSize (float): Angular size of spots (0 to 1) + * - u_pulse (float): Optional pulsing animation intensity (0 to 1) + * - u_smoke (float): Optional noisy shape extending the border (0 to 1) + * - u_smokeSize (float): Size of the smoke effect (0 to 1) + * - u_noiseTexture (sampler2D): Pre-computed randomizer source texture + * + * Vertex shader outputs (used in fragment shader): + * - v_responsiveUV (vec2): Responsive UV coordinates that adapt to canvas aspect ratio + * - v_responsiveBoxGivenSize (vec2): Given size of the responsive bounding box + * - v_patternUV (vec2): UV coordinates for pattern with global sizing (rotation, scale, offset, etc) applied (used for smoke calculation) + * + * Vertex shader uniforms: + * - u_resolution (vec2): Canvas resolution in pixels + * - u_pixelRatio (float): Device pixel ratio + * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1) + * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1) + * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas + * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas + * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover) + * - u_scale (float): Overall zoom level of the graphics (0.01 to 4) + * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360) + * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1) + * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1) + * + */ +export declare const pulsingBorderFragmentShader: string; +export interface PulsingBorderUniforms extends ShaderSizingUniforms { + u_colorBack: [number, number, number, number]; + u_colors: vec4[]; + u_colorsCount: number; + u_roundness: number; + u_thickness: number; + u_marginLeft: number; + u_marginRight: number; + u_marginTop: number; + u_marginBottom: number; + u_aspectRatio: (typeof PulsingBorderAspectRatios)[PulsingBorderAspectRatio]; + u_softness: number; + u_intensity: number; + u_bloom: number; + u_spots: number; + u_spotSize: number; + u_pulse: number; + u_smoke: number; + u_smokeSize: number; + u_noiseTexture?: HTMLImageElement; +} +export interface PulsingBorderParams extends ShaderSizingParams, ShaderMotionParams { + colorBack?: string; + colors?: string[]; + roundness?: number; + thickness?: number; + margin?: number; + marginLeft?: number; + marginRight?: number; + marginTop?: number; + marginBottom?: number; + aspectRatio?: PulsingBorderAspectRatio; + softness?: number; + intensity?: number; + bloom?: number; + spots?: number; + spotSize?: number; + pulse?: number; + smoke?: number; + smokeSize?: number; +} +export declare const PulsingBorderAspectRatios: { + readonly auto: 0; + readonly square: 1; +}; +export type PulsingBorderAspectRatio = keyof typeof PulsingBorderAspectRatios; diff --git a/public/vendor/paper-shaders/shaders/pulsing-border.js b/public/vendor/paper-shaders/shaders/pulsing-border.js new file mode 100644 index 0000000..464e5f7 --- /dev/null +++ b/public/vendor/paper-shaders/shaders/pulsing-border.js @@ -0,0 +1,239 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Paper Shaders * + * https://github.com/paper-design/shaders * + * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +import {} from "../shader-sizing.js"; +import { declarePI, textureRandomizerGB, colorBandingFix } from "../shader-utils.js"; +const pulsingBorderMeta = { + maxColorCount: 5, + maxSpots: 4 +}; +const pulsingBorderFragmentShader = `#version 300 es +precision lowp float; + +uniform float u_time; + +uniform vec4 u_colorBack; +uniform vec4 u_colors[${pulsingBorderMeta.maxColorCount}]; +uniform float u_colorsCount; +uniform float u_roundness; +uniform float u_thickness; +uniform float u_marginLeft; +uniform float u_marginRight; +uniform float u_marginTop; +uniform float u_marginBottom; +uniform float u_aspectRatio; +uniform float u_softness; +uniform float u_intensity; +uniform float u_bloom; +uniform float u_spotSize; +uniform float u_spots; +uniform float u_pulse; +uniform float u_smoke; +uniform float u_smokeSize; + +uniform sampler2D u_noiseTexture; + +in vec2 v_responsiveUV; +in vec2 v_responsiveBoxGivenSize; +in vec2 v_patternUV; + +out vec4 fragColor; + +${declarePI} + +float beat(float time) { + float first = pow(abs(sin(time * TWO_PI)), 10.); + float second = pow(abs(sin((time - .15) * TWO_PI)), 10.); + + return clamp(first + 0.6 * second, 0.0, 1.0); +} + +float sst(float edge0, float edge1, float x) { + return smoothstep(edge0, edge1, x); +} + +float roundedBox(vec2 uv, vec2 halfSize, float distance, float cornerDistance, float thickness, float softness) { + float borderDistance = abs(distance); + float aa = 2. * fwidth(distance); + float border = 1. - sst(min(mix(thickness, -thickness, softness), thickness + aa), max(mix(thickness, -thickness, softness), thickness + aa), borderDistance); + float cornerFadeCircles = 0.; + cornerFadeCircles = mix(1., cornerFadeCircles, sst(0., 1., length((uv + halfSize) / thickness))); + cornerFadeCircles = mix(1., cornerFadeCircles, sst(0., 1., length((uv - vec2(-halfSize.x, halfSize.y)) / thickness))); + cornerFadeCircles = mix(1., cornerFadeCircles, sst(0., 1., length((uv - vec2(halfSize.x, -halfSize.y)) / thickness))); + cornerFadeCircles = mix(1., cornerFadeCircles, sst(0., 1., length((uv - halfSize) / thickness))); + aa = fwidth(cornerDistance); + float cornerFade = sst(0., mix(aa, thickness, softness), cornerDistance); + cornerFade *= cornerFadeCircles; + border += cornerFade; + return border; +} + +${textureRandomizerGB} + +float randomG(vec2 p) { + vec2 uv = floor(p) / 100. + .5; + return texture(u_noiseTexture, fract(uv)).g; +} +float valueNoise(vec2 st) { + vec2 i = floor(st); + vec2 f = fract(st); + float a = randomG(i); + float b = randomG(i + vec2(1.0, 0.0)); + float c = randomG(i + vec2(0.0, 1.0)); + float d = randomG(i + vec2(1.0, 1.0)); + vec2 u = f * f * (3.0 - 2.0 * f); + float x1 = mix(a, b, u.x); + float x2 = mix(c, d, u.x); + return mix(x1, x2, u.y); +} + +void main() { + const float firstFrameOffset = 109.; + float t = 1.2 * (u_time + firstFrameOffset); + + vec2 borderUV = v_responsiveUV; + float pulse = u_pulse * beat(.18 * u_time); + + float canvasRatio = v_responsiveBoxGivenSize.x / v_responsiveBoxGivenSize.y; + vec2 halfSize = vec2(.5); + borderUV.x *= max(canvasRatio, 1.); + borderUV.y /= min(canvasRatio, 1.); + halfSize.x *= max(canvasRatio, 1.); + halfSize.y /= min(canvasRatio, 1.); + + float mL = u_marginLeft; + float mR = u_marginRight; + float mT = u_marginTop; + float mB = u_marginBottom; + float mX = mL + mR; + float mY = mT + mB; + + if (u_aspectRatio > 0.) { + float shapeRatio = canvasRatio * (1. - mX) / max(1. - mY, 1e-6); + float freeX = shapeRatio > 1. ? (1. - mX) * (1. - 1. / max(abs(shapeRatio), 1e-6)) : 0.; + float freeY = shapeRatio < 1. ? (1. - mY) * (1. - shapeRatio) : 0.; + mL += freeX * 0.5; + mR += freeX * 0.5; + mT += freeY * 0.5; + mB += freeY * 0.5; + mX = mL + mR; + mY = mT + mB; + } + + float thickness = .5 * u_thickness * min(halfSize.x, halfSize.y); + + halfSize.x *= (1. - mX); + halfSize.y *= (1. - mY); + + vec2 centerShift = vec2( + (mL - mR) * max(canvasRatio, 1.) * 0.5, + (mB - mT) / min(canvasRatio, 1.) * 0.5 + ); + + borderUV -= centerShift; + halfSize -= mix(thickness, 0., u_softness); + + float radius = mix(0., min(halfSize.x, halfSize.y), u_roundness); + vec2 d = abs(borderUV) - halfSize + radius; + float outsideDistance = length(max(d, .0001)) - radius; + float insideDistance = min(max(d.x, d.y), .0001); + float cornerDistance = abs(min(max(d.x, d.y) - .45 * radius, .0)); + float distance = outsideDistance + insideDistance; + + float borderThickness = mix(thickness, 3. * thickness, u_softness); + float border = roundedBox(borderUV, halfSize, distance, cornerDistance, borderThickness, u_softness); + border = pow(border, 1. + u_softness); + + vec2 smokeUV = .3 * u_smokeSize * v_patternUV; + float smoke = clamp(3. * valueNoise(2.7 * smokeUV + .5 * t), 0., 1.); + smoke -= valueNoise(3.4 * smokeUV - .5 * t); + float smokeThickness = thickness + .2; + smokeThickness = min(.4, max(smokeThickness, .1)); + smoke *= roundedBox(borderUV, halfSize, distance, cornerDistance, smokeThickness, 1.); + smoke = 30. * smoke * smoke; + smoke *= mix(0., .5, pow(u_smoke, 2.)); + smoke *= mix(1., pulse, u_pulse); + smoke = clamp(smoke, 0., 1.); + border += smoke; + + border = clamp(border, 0., 1.); + + vec3 blendColor = vec3(0.); + float blendAlpha = 0.; + vec3 addColor = vec3(0.); + float addAlpha = 0.; + + float bloom = 4. * u_bloom; + float intensity = 1. + (1. + 4. * u_softness) * u_intensity; + + float angle = atan(borderUV.y, borderUV.x) / TWO_PI; + + for (int colorIdx = 0; colorIdx < ${pulsingBorderMeta.maxColorCount}; colorIdx++) { + if (colorIdx >= int(u_colorsCount)) break; + float colorIdxF = float(colorIdx); + + vec3 c = u_colors[colorIdx].rgb * u_colors[colorIdx].a; + float a = u_colors[colorIdx].a; + + for (int spotIdx = 0; spotIdx < ${pulsingBorderMeta.maxSpots}; spotIdx++) { + if (spotIdx >= int(u_spots)) break; + float spotIdxF = float(spotIdx); + + vec2 randVal = randomGB(vec2(spotIdxF * 10. + 2., 40. + colorIdxF)); + + float time = (.1 + .15 * abs(sin(spotIdxF * (2. + colorIdxF)) * cos(spotIdxF * (2. + 2.5 * colorIdxF)))) * t + randVal.x * 3.; + time *= mix(1., -1., step(.5, randVal.y)); + + float mask = .5 + .5 * mix( + sin(t + spotIdxF * (5. - 1.5 * colorIdxF)), + cos(t + spotIdxF * (3. + 1.3 * colorIdxF)), + step(mod(colorIdxF, 2.), .5) + ); + + float p = clamp(2. * u_pulse - randVal.x, 0., 1.); + mask = mix(mask, pulse, p); + + float atg1 = fract(angle + time); + float spotSize = .05 + .6 * pow(u_spotSize, 2.) + .05 * randVal.x; + spotSize = mix(spotSize, .1, p); + float sector = sst(.5 - spotSize, .5, atg1) * (1. - sst(.5, .5 + spotSize, atg1)); + + sector *= mask; + sector *= border; + sector *= intensity; + sector = clamp(sector, 0., 1.); + + vec3 srcColor = c * sector; + float srcAlpha = a * sector; + + blendColor += ((1. - blendAlpha) * srcColor); + blendAlpha = blendAlpha + (1. - blendAlpha) * srcAlpha; + addColor += srcColor; + addAlpha += srcAlpha; + } + } + + vec3 accumColor = mix(blendColor, addColor, bloom); + float accumAlpha = mix(blendAlpha, addAlpha, bloom); + accumAlpha = clamp(accumAlpha, 0., 1.); + + vec3 bgColor = u_colorBack.rgb * u_colorBack.a; + vec3 color = accumColor + (1. - accumAlpha) * bgColor; + float opacity = accumAlpha + (1. - accumAlpha) * u_colorBack.a; + + ${colorBandingFix} + + fragColor = vec4(color, opacity); +}`; +const PulsingBorderAspectRatios = { + auto: 0, + square: 1 +}; +export { + PulsingBorderAspectRatios, + pulsingBorderFragmentShader, + pulsingBorderMeta +}; +//# sourceMappingURL=pulsing-border.js.map diff --git a/public/vendor/paper-shaders/shaders/pulsing-border.js.map b/public/vendor/paper-shaders/shaders/pulsing-border.js.map new file mode 100644 index 0000000..7bef2aa --- /dev/null +++ b/public/vendor/paper-shaders/shaders/pulsing-border.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../../src/shaders/pulsing-border.ts"], + "sourcesContent": ["import type { vec4 } from '../types.js';\nimport type { ShaderMotionParams } from '../shader-mount.js';\nimport { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { declarePI, textureRandomizerGB, colorBandingFix } from '../shader-utils.js';\n\nexport const pulsingBorderMeta = {\n maxColorCount: 5,\n maxSpots: 4,\n} as const;\n\n/**\n * Luminous trails of color merging into a glowing gradient contour.\n *\n * Fragment shader uniforms:\n * - u_time (float): Animation time\n * - u_colorBack (vec4): Background color in RGBA\n * - u_colors (vec4[]): Up to 5 spot colors in RGBA\n * - u_colorsCount (float): Number of active colors\n * - u_roundness (float): Border radius (0 to 1)\n * - u_thickness (float): Border base width (0 to 1)\n * - u_softness (float): Border edge sharpness, 0 = hard edge, 1 = smooth gradient (0 to 1)\n * - u_marginLeft (float): Distance from the left edge to the effect (0 to 1)\n * - u_marginRight (float): Distance from the right edge to the effect (0 to 1)\n * - u_marginTop (float): Distance from the top edge to the effect (0 to 1)\n * - u_marginBottom (float): Distance from the bottom edge to the effect (0 to 1)\n * - u_aspectRatio (float): Aspect ratio mode (0 = auto, 1 = square)\n * - u_intensity (float): Thickness of individual color spots (0 to 1)\n * - u_bloom (float): Power of glow, 0 = normal blending, 1 = additive blending (0 to 1)\n * - u_spots (float): Number of spots added for each color (1 to 20)\n * - u_spotSize (float): Angular size of spots (0 to 1)\n * - u_pulse (float): Optional pulsing animation intensity (0 to 1)\n * - u_smoke (float): Optional noisy shape extending the border (0 to 1)\n * - u_smokeSize (float): Size of the smoke effect (0 to 1)\n * - u_noiseTexture (sampler2D): Pre-computed randomizer source texture\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_responsiveUV (vec2): Responsive UV coordinates that adapt to canvas aspect ratio\n * - v_responsiveBoxGivenSize (vec2): Given size of the responsive bounding box\n * - v_patternUV (vec2): UV coordinates for pattern with global sizing (rotation, scale, offset, etc) applied (used for smoke calculation)\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n *\n */\n\n// language=GLSL\nexport const pulsingBorderFragmentShader: string = `#version 300 es\nprecision lowp float;\n\nuniform float u_time;\n\nuniform vec4 u_colorBack;\nuniform vec4 u_colors[${ pulsingBorderMeta.maxColorCount }];\nuniform float u_colorsCount;\nuniform float u_roundness;\nuniform float u_thickness;\nuniform float u_marginLeft;\nuniform float u_marginRight;\nuniform float u_marginTop;\nuniform float u_marginBottom;\nuniform float u_aspectRatio;\nuniform float u_softness;\nuniform float u_intensity;\nuniform float u_bloom;\nuniform float u_spotSize;\nuniform float u_spots;\nuniform float u_pulse;\nuniform float u_smoke;\nuniform float u_smokeSize;\n\nuniform sampler2D u_noiseTexture;\n\nin vec2 v_responsiveUV;\nin vec2 v_responsiveBoxGivenSize;\nin vec2 v_patternUV;\n\nout vec4 fragColor;\n\n${ declarePI }\n\nfloat beat(float time) {\n float first = pow(abs(sin(time * TWO_PI)), 10.);\n float second = pow(abs(sin((time - .15) * TWO_PI)), 10.);\n\n return clamp(first + 0.6 * second, 0.0, 1.0);\n}\n\nfloat sst(float edge0, float edge1, float x) {\n return smoothstep(edge0, edge1, x);\n}\n\nfloat roundedBox(vec2 uv, vec2 halfSize, float distance, float cornerDistance, float thickness, float softness) {\n float borderDistance = abs(distance);\n float aa = 2. * fwidth(distance);\n float border = 1. - sst(min(mix(thickness, -thickness, softness), thickness + aa), max(mix(thickness, -thickness, softness), thickness + aa), borderDistance);\n float cornerFadeCircles = 0.;\n cornerFadeCircles = mix(1., cornerFadeCircles, sst(0., 1., length((uv + halfSize) / thickness)));\n cornerFadeCircles = mix(1., cornerFadeCircles, sst(0., 1., length((uv - vec2(-halfSize.x, halfSize.y)) / thickness)));\n cornerFadeCircles = mix(1., cornerFadeCircles, sst(0., 1., length((uv - vec2(halfSize.x, -halfSize.y)) / thickness)));\n cornerFadeCircles = mix(1., cornerFadeCircles, sst(0., 1., length((uv - halfSize) / thickness)));\n aa = fwidth(cornerDistance);\n float cornerFade = sst(0., mix(aa, thickness, softness), cornerDistance);\n cornerFade *= cornerFadeCircles;\n border += cornerFade;\n return border;\n}\n\n${ textureRandomizerGB }\n\nfloat randomG(vec2 p) {\n vec2 uv = floor(p) / 100. + .5;\n return texture(u_noiseTexture, fract(uv)).g;\n}\nfloat valueNoise(vec2 st) {\n vec2 i = floor(st);\n vec2 f = fract(st);\n float a = randomG(i);\n float b = randomG(i + vec2(1.0, 0.0));\n float c = randomG(i + vec2(0.0, 1.0));\n float d = randomG(i + vec2(1.0, 1.0));\n vec2 u = f * f * (3.0 - 2.0 * f);\n float x1 = mix(a, b, u.x);\n float x2 = mix(c, d, u.x);\n return mix(x1, x2, u.y);\n}\n\nvoid main() {\n const float firstFrameOffset = 109.;\n float t = 1.2 * (u_time + firstFrameOffset);\n\n vec2 borderUV = v_responsiveUV;\n float pulse = u_pulse * beat(.18 * u_time);\n\n float canvasRatio = v_responsiveBoxGivenSize.x / v_responsiveBoxGivenSize.y;\n vec2 halfSize = vec2(.5);\n borderUV.x *= max(canvasRatio, 1.);\n borderUV.y /= min(canvasRatio, 1.);\n halfSize.x *= max(canvasRatio, 1.);\n halfSize.y /= min(canvasRatio, 1.);\n\n float mL = u_marginLeft;\n float mR = u_marginRight;\n float mT = u_marginTop;\n float mB = u_marginBottom;\n float mX = mL + mR;\n float mY = mT + mB;\n\n if (u_aspectRatio > 0.) {\n float shapeRatio = canvasRatio * (1. - mX) / max(1. - mY, 1e-6);\n float freeX = shapeRatio > 1. ? (1. - mX) * (1. - 1. / max(abs(shapeRatio), 1e-6)) : 0.;\n float freeY = shapeRatio < 1. ? (1. - mY) * (1. - shapeRatio) : 0.;\n mL += freeX * 0.5;\n mR += freeX * 0.5;\n mT += freeY * 0.5;\n mB += freeY * 0.5;\n mX = mL + mR;\n mY = mT + mB;\n }\n\n float thickness = .5 * u_thickness * min(halfSize.x, halfSize.y);\n\n halfSize.x *= (1. - mX);\n halfSize.y *= (1. - mY);\n\n vec2 centerShift = vec2(\n (mL - mR) * max(canvasRatio, 1.) * 0.5,\n (mB - mT) / min(canvasRatio, 1.) * 0.5\n );\n\n borderUV -= centerShift;\n halfSize -= mix(thickness, 0., u_softness);\n\n float radius = mix(0., min(halfSize.x, halfSize.y), u_roundness);\n vec2 d = abs(borderUV) - halfSize + radius;\n float outsideDistance = length(max(d, .0001)) - radius;\n float insideDistance = min(max(d.x, d.y), .0001);\n float cornerDistance = abs(min(max(d.x, d.y) - .45 * radius, .0));\n float distance = outsideDistance + insideDistance;\n\n float borderThickness = mix(thickness, 3. * thickness, u_softness);\n float border = roundedBox(borderUV, halfSize, distance, cornerDistance, borderThickness, u_softness);\n border = pow(border, 1. + u_softness);\n\n vec2 smokeUV = .3 * u_smokeSize * v_patternUV;\n float smoke = clamp(3. * valueNoise(2.7 * smokeUV + .5 * t), 0., 1.);\n smoke -= valueNoise(3.4 * smokeUV - .5 * t);\n float smokeThickness = thickness + .2;\n smokeThickness = min(.4, max(smokeThickness, .1));\n smoke *= roundedBox(borderUV, halfSize, distance, cornerDistance, smokeThickness, 1.);\n smoke = 30. * smoke * smoke;\n smoke *= mix(0., .5, pow(u_smoke, 2.));\n smoke *= mix(1., pulse, u_pulse);\n smoke = clamp(smoke, 0., 1.);\n border += smoke;\n\n border = clamp(border, 0., 1.);\n\n vec3 blendColor = vec3(0.);\n float blendAlpha = 0.;\n vec3 addColor = vec3(0.);\n float addAlpha = 0.;\n\n float bloom = 4. * u_bloom;\n float intensity = 1. + (1. + 4. * u_softness) * u_intensity;\n\n float angle = atan(borderUV.y, borderUV.x) / TWO_PI;\n\n for (int colorIdx = 0; colorIdx < ${ pulsingBorderMeta.maxColorCount }; colorIdx++) {\n if (colorIdx >= int(u_colorsCount)) break;\n float colorIdxF = float(colorIdx);\n\n vec3 c = u_colors[colorIdx].rgb * u_colors[colorIdx].a;\n float a = u_colors[colorIdx].a;\n\n for (int spotIdx = 0; spotIdx < ${ pulsingBorderMeta.maxSpots }; spotIdx++) {\n if (spotIdx >= int(u_spots)) break;\n float spotIdxF = float(spotIdx);\n\n vec2 randVal = randomGB(vec2(spotIdxF * 10. + 2., 40. + colorIdxF));\n\n float time = (.1 + .15 * abs(sin(spotIdxF * (2. + colorIdxF)) * cos(spotIdxF * (2. + 2.5 * colorIdxF)))) * t + randVal.x * 3.;\n time *= mix(1., -1., step(.5, randVal.y));\n\n float mask = .5 + .5 * mix(\n sin(t + spotIdxF * (5. - 1.5 * colorIdxF)),\n cos(t + spotIdxF * (3. + 1.3 * colorIdxF)),\n step(mod(colorIdxF, 2.), .5)\n );\n\n float p = clamp(2. * u_pulse - randVal.x, 0., 1.);\n mask = mix(mask, pulse, p);\n\n float atg1 = fract(angle + time);\n float spotSize = .05 + .6 * pow(u_spotSize, 2.) + .05 * randVal.x;\n spotSize = mix(spotSize, .1, p);\n float sector = sst(.5 - spotSize, .5, atg1) * (1. - sst(.5, .5 + spotSize, atg1));\n\n sector *= mask;\n sector *= border;\n sector *= intensity;\n sector = clamp(sector, 0., 1.);\n\n vec3 srcColor = c * sector;\n float srcAlpha = a * sector;\n\n blendColor += ((1. - blendAlpha) * srcColor);\n blendAlpha = blendAlpha + (1. - blendAlpha) * srcAlpha;\n addColor += srcColor;\n addAlpha += srcAlpha;\n }\n }\n\n vec3 accumColor = mix(blendColor, addColor, bloom);\n float accumAlpha = mix(blendAlpha, addAlpha, bloom);\n accumAlpha = clamp(accumAlpha, 0., 1.);\n\n vec3 bgColor = u_colorBack.rgb * u_colorBack.a;\n vec3 color = accumColor + (1. - accumAlpha) * bgColor;\n float opacity = accumAlpha + (1. - accumAlpha) * u_colorBack.a;\n\n ${ colorBandingFix }\n\n fragColor = vec4(color, opacity);\n}`;\n\nexport interface PulsingBorderUniforms extends ShaderSizingUniforms {\n u_colorBack: [number, number, number, number];\n u_colors: vec4[];\n u_colorsCount: number;\n u_roundness: number;\n u_thickness: number;\n u_marginLeft: number;\n u_marginRight: number;\n u_marginTop: number;\n u_marginBottom: number;\n u_aspectRatio: (typeof PulsingBorderAspectRatios)[PulsingBorderAspectRatio];\n u_softness: number;\n u_intensity: number;\n u_bloom: number;\n u_spots: number;\n u_spotSize: number;\n u_pulse: number;\n u_smoke: number;\n u_smokeSize: number;\n u_noiseTexture?: HTMLImageElement;\n}\n\nexport interface PulsingBorderParams extends ShaderSizingParams, ShaderMotionParams {\n colorBack?: string;\n colors?: string[];\n roundness?: number;\n thickness?: number;\n margin?: number;\n marginLeft?: number;\n marginRight?: number;\n marginTop?: number;\n marginBottom?: number;\n aspectRatio?: PulsingBorderAspectRatio;\n softness?: number;\n intensity?: number;\n bloom?: number;\n spots?: number;\n spotSize?: number;\n pulse?: number;\n smoke?: number;\n smokeSize?: number;\n}\n\nexport const PulsingBorderAspectRatios = {\n auto: 0,\n square: 1,\n} as const;\n\nexport type PulsingBorderAspectRatio = keyof typeof PulsingBorderAspectRatios;\n"], + "mappings": ";;;;;AAEA,eAAmE;AACnE,SAAS,WAAW,qBAAqB,uBAAuB;AAEzD,MAAM,oBAAoB;AAAA,EAC/B,eAAe;AAAA,EACf,UAAU;AACZ;AAgDO,MAAM,8BAAsC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAM1B,kBAAkB,aAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA0BtD,SAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA6BV,mBAAoB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sCAoGgB,kBAAkB,aAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sCAOhC,kBAAkB,QAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA8C7D,eAAgB;AAAA;AAAA;AAAA;AAgDd,MAAM,4BAA4B;AAAA,EACvC,MAAM;AAAA,EACN,QAAQ;AACV;", + "names": [] +} diff --git a/public/vendor/paper-shaders/shaders/simplex-noise.d.ts b/public/vendor/paper-shaders/shaders/simplex-noise.d.ts new file mode 100644 index 0000000..3d409a4 --- /dev/null +++ b/public/vendor/paper-shaders/shaders/simplex-noise.d.ts @@ -0,0 +1,46 @@ +import type { vec4 } from '../types.js'; +import type { ShaderMotionParams } from '../shader-mount.js'; +import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js'; +export declare const simplexNoiseMeta: { + readonly maxColorCount: 10; +}; +/** + * A multi-color gradient mapped into smooth, animated curves built as a combination of 2 Simplex noises. + * + * Fragment shader uniforms: + * - u_time (float): Animation time + * - u_scale (float): Overall zoom level, used for anti-aliasing calculations + * - u_colors (vec4[]): Up to 10 base colors in RGBA + * - u_colorsCount (float): Number of active colors + * - u_stepsPerColor (float): Number of extra colors between base colors, 1 = N colors, 2 = 2×N, etc. (1 to 10) + * - u_softness (float): Color transition sharpness, 0 = hard edge, 1 = smooth gradient (0 to 1) + * + * Vertex shader outputs (used in fragment shader): + * - v_patternUV (vec2): UV coordinates for pattern with global sizing (rotation, scale, offset, etc) applied + * + * Vertex shader uniforms: + * - u_resolution (vec2): Canvas resolution in pixels + * - u_pixelRatio (float): Device pixel ratio + * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1) + * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1) + * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas + * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas + * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover) + * - u_scale (float): Overall zoom level of the graphics (0.01 to 4) + * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360) + * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1) + * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1) + * + */ +export declare const simplexNoiseFragmentShader: string; +export interface SimplexNoiseUniforms extends ShaderSizingUniforms { + u_colors: vec4[]; + u_colorsCount: number; + u_stepsPerColor: number; + u_softness: number; +} +export interface SimplexNoiseParams extends ShaderSizingParams, ShaderMotionParams { + colors?: string[]; + stepsPerColor?: number; + softness?: number; +} diff --git a/public/vendor/paper-shaders/shaders/simplex-noise.js b/public/vendor/paper-shaders/shaders/simplex-noise.js new file mode 100644 index 0000000..5ececb0 --- /dev/null +++ b/public/vendor/paper-shaders/shaders/simplex-noise.js @@ -0,0 +1,100 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Paper Shaders * + * https://github.com/paper-design/shaders * + * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +import {} from "../shader-sizing.js"; +import { simplexNoise, colorBandingFix } from "../shader-utils.js"; +const simplexNoiseMeta = { + maxColorCount: 10 +}; +const simplexNoiseFragmentShader = `#version 300 es +precision mediump float; + +uniform float u_time; +uniform float u_scale; + +uniform vec4 u_colors[${simplexNoiseMeta.maxColorCount}]; +uniform float u_colorsCount; +uniform float u_stepsPerColor; +uniform float u_softness; + +in vec2 v_patternUV; + +out vec4 fragColor; + +${simplexNoise} + +float getNoise(vec2 uv, float t) { + float noise = .5 * snoise(uv - vec2(0., .3 * t)); + noise += .5 * snoise(2. * uv + vec2(0., .32 * t)); + + return noise; +} + +float steppedSmooth(float m, float steps, float softness) { + float stepT = floor(m * steps) / steps; + float f = m * steps - floor(m * steps); + float fw = steps * fwidth(m); + float smoothed = smoothstep(.5 - softness, min(1., .5 + softness + fw), f); + return stepT + smoothed / steps; +} + +void main() { + vec2 shape_uv = v_patternUV; + shape_uv *= .1; + + float t = .2 * u_time; + + float shape = .5 + .5 * getNoise(shape_uv, t); + + bool u_extraSides = true; + + float mixer = shape * (u_colorsCount - 1.); + if (u_extraSides == true) { + mixer = (shape - .5 / u_colorsCount) * u_colorsCount; + } + + float steps = max(1., u_stepsPerColor); + + vec4 gradient = u_colors[0]; + gradient.rgb *= gradient.a; + for (int i = 1; i < ${simplexNoiseMeta.maxColorCount}; i++) { + if (i >= int(u_colorsCount)) break; + + float localM = clamp(mixer - float(i - 1), 0., 1.); + localM = steppedSmooth(localM, steps, .5 * u_softness); + + vec4 c = u_colors[i]; + c.rgb *= c.a; + gradient = mix(gradient, c, localM); + } + + if (u_extraSides == true) { + if ((mixer < 0.) || (mixer > (u_colorsCount - 1.))) { + float localM = mixer + 1.; + if (mixer > (u_colorsCount - 1.)) { + localM = mixer - (u_colorsCount - 1.); + } + localM = steppedSmooth(localM, steps, .5 * u_softness); + vec4 cFst = u_colors[0]; + cFst.rgb *= cFst.a; + vec4 cLast = u_colors[int(u_colorsCount - 1.)]; + cLast.rgb *= cLast.a; + gradient = mix(cLast, cFst, localM); + } + } + + vec3 color = gradient.rgb; + float opacity = gradient.a; + + ${colorBandingFix} + + fragColor = vec4(color, opacity); +} +`; +export { + simplexNoiseFragmentShader, + simplexNoiseMeta +}; +//# sourceMappingURL=simplex-noise.js.map diff --git a/public/vendor/paper-shaders/shaders/simplex-noise.js.map b/public/vendor/paper-shaders/shaders/simplex-noise.js.map new file mode 100644 index 0000000..b1febb3 --- /dev/null +++ b/public/vendor/paper-shaders/shaders/simplex-noise.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../../src/shaders/simplex-noise.ts"], + "sourcesContent": ["import type { vec4 } from '../types.js';\nimport type { ShaderMotionParams } from '../shader-mount.js';\nimport { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { simplexNoise, colorBandingFix } from '../shader-utils.js';\n\nexport const simplexNoiseMeta = {\n maxColorCount: 10,\n} as const;\n\n/**\n * A multi-color gradient mapped into smooth, animated curves built as a combination of 2 Simplex noises.\n *\n * Fragment shader uniforms:\n * - u_time (float): Animation time\n * - u_scale (float): Overall zoom level, used for anti-aliasing calculations\n * - u_colors (vec4[]): Up to 10 base colors in RGBA\n * - u_colorsCount (float): Number of active colors\n * - u_stepsPerColor (float): Number of extra colors between base colors, 1 = N colors, 2 = 2\u00D7N, etc. (1 to 10)\n * - u_softness (float): Color transition sharpness, 0 = hard edge, 1 = smooth gradient (0 to 1)\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_patternUV (vec2): UV coordinates for pattern with global sizing (rotation, scale, offset, etc) applied\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n *\n */\n\n// language=GLSL\nexport const simplexNoiseFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform float u_time;\nuniform float u_scale;\n\nuniform vec4 u_colors[${ simplexNoiseMeta.maxColorCount }];\nuniform float u_colorsCount;\nuniform float u_stepsPerColor;\nuniform float u_softness;\n\nin vec2 v_patternUV;\n\nout vec4 fragColor;\n\n${ simplexNoise }\n\nfloat getNoise(vec2 uv, float t) {\n float noise = .5 * snoise(uv - vec2(0., .3 * t));\n noise += .5 * snoise(2. * uv + vec2(0., .32 * t));\n\n return noise;\n}\n\nfloat steppedSmooth(float m, float steps, float softness) {\n float stepT = floor(m * steps) / steps;\n float f = m * steps - floor(m * steps);\n float fw = steps * fwidth(m);\n float smoothed = smoothstep(.5 - softness, min(1., .5 + softness + fw), f);\n return stepT + smoothed / steps;\n}\n\nvoid main() {\n vec2 shape_uv = v_patternUV;\n shape_uv *= .1;\n\n float t = .2 * u_time;\n\n float shape = .5 + .5 * getNoise(shape_uv, t);\n\n bool u_extraSides = true;\n\n float mixer = shape * (u_colorsCount - 1.);\n if (u_extraSides == true) {\n mixer = (shape - .5 / u_colorsCount) * u_colorsCount;\n }\n\n float steps = max(1., u_stepsPerColor);\n\n vec4 gradient = u_colors[0];\n gradient.rgb *= gradient.a;\n for (int i = 1; i < ${ simplexNoiseMeta.maxColorCount }; i++) {\n if (i >= int(u_colorsCount)) break;\n\n float localM = clamp(mixer - float(i - 1), 0., 1.);\n localM = steppedSmooth(localM, steps, .5 * u_softness);\n\n vec4 c = u_colors[i];\n c.rgb *= c.a;\n gradient = mix(gradient, c, localM);\n }\n\n if (u_extraSides == true) {\n if ((mixer < 0.) || (mixer > (u_colorsCount - 1.))) {\n float localM = mixer + 1.;\n if (mixer > (u_colorsCount - 1.)) {\n localM = mixer - (u_colorsCount - 1.);\n }\n localM = steppedSmooth(localM, steps, .5 * u_softness);\n vec4 cFst = u_colors[0];\n cFst.rgb *= cFst.a;\n vec4 cLast = u_colors[int(u_colorsCount - 1.)];\n cLast.rgb *= cLast.a;\n gradient = mix(cLast, cFst, localM);\n }\n }\n\n vec3 color = gradient.rgb;\n float opacity = gradient.a;\n\n ${ colorBandingFix }\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface SimplexNoiseUniforms extends ShaderSizingUniforms {\n u_colors: vec4[];\n u_colorsCount: number;\n u_stepsPerColor: number;\n u_softness: number;\n}\n\nexport interface SimplexNoiseParams extends ShaderSizingParams, ShaderMotionParams {\n colors?: string[];\n stepsPerColor?: number;\n softness?: number;\n}\n"], + "mappings": ";;;;;AAEA,eAAmE;AACnE,SAAS,cAAc,uBAAuB;AAEvC,MAAM,mBAAmB;AAAA,EAC9B,eAAe;AACjB;AAgCO,MAAM,6BAAqC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAMzB,iBAAiB,aAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASrD,YAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAoCS,iBAAiB,aAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA6BnD,eAAgB;AAAA;AAAA;AAAA;AAAA;", + "names": [] +} diff --git a/public/vendor/paper-shaders/shaders/smoke-ring.d.ts b/public/vendor/paper-shaders/shaders/smoke-ring.d.ts new file mode 100644 index 0000000..07bd17e --- /dev/null +++ b/public/vendor/paper-shaders/shaders/smoke-ring.d.ts @@ -0,0 +1,61 @@ +import type { vec4 } from '../types.js'; +import type { ShaderMotionParams } from '../shader-mount.js'; +import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js'; +export declare const smokeRingMeta: { + readonly maxColorCount: 10; + readonly maxNoiseIterations: 8; +}; +/** + * Radial multi-colored gradient shaped with layered noise for a natural, smoky aesthetic. + * + * + * Fragment shader uniforms: + * - u_time (float): Animation time + * - u_colorBack (vec4): Background color in RGBA + * - u_colors (vec4[]): Up to 10 gradient colors in RGBA + * - u_colorsCount (float): Number of active colors + * - u_thickness (float): Thickness of the ring shape (0.01 to 1) + * - u_radius (float): Radius of the ring shape (0 to 1) + * - u_innerShape (float): Ring inner fill amount (0 to 4) + * - u_noiseIterations (float): Number of noise layers, more layers gives more details (1 to 8) + * - u_noiseScale (float): Noise frequency (0.01 to 5) + * - u_noiseTexture (sampler2D): Pre-computed randomizer source texture + * + * Vertex shader outputs (used in fragment shader): + * - v_objectUV (vec2): Object box UV coordinates with global sizing (scale, rotation, offsets, etc) applied + * + * Vertex shader uniforms: + * - u_resolution (vec2): Canvas resolution in pixels + * - u_pixelRatio (float): Device pixel ratio + * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1) + * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1) + * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas + * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas + * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover) + * - u_scale (float): Overall zoom level of the graphics (0.01 to 4) + * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360) + * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1) + * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1) + * + */ +export declare const smokeRingFragmentShader: string; +export interface SmokeRingUniforms extends ShaderSizingUniforms { + u_colorBack: [number, number, number, number]; + u_colors: vec4[]; + u_colorsCount: number; + u_noiseScale: number; + u_thickness: number; + u_radius: number; + u_innerShape: number; + u_noiseIterations: number; + u_noiseTexture?: HTMLImageElement; +} +export interface SmokeRingParams extends ShaderSizingParams, ShaderMotionParams { + colorBack?: string; + colors?: string[]; + noiseScale?: number; + thickness?: number; + radius?: number; + innerShape?: number; + noiseIterations?: number; +} diff --git a/public/vendor/paper-shaders/shaders/smoke-ring.js b/public/vendor/paper-shaders/shaders/smoke-ring.js new file mode 100644 index 0000000..aa6f126 --- /dev/null +++ b/public/vendor/paper-shaders/shaders/smoke-ring.js @@ -0,0 +1,133 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Paper Shaders * + * https://github.com/paper-design/shaders * + * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +import {} from "../shader-sizing.js"; +import { declarePI, textureRandomizerR, colorBandingFix } from "../shader-utils.js"; +const smokeRingMeta = { + maxColorCount: 10, + maxNoiseIterations: 8 +}; +const smokeRingFragmentShader = `#version 300 es +precision mediump float; + +uniform float u_time; + +uniform sampler2D u_noiseTexture; + +uniform vec4 u_colorBack; +uniform vec4 u_colors[${smokeRingMeta.maxColorCount}]; +uniform float u_colorsCount; + +uniform float u_thickness; +uniform float u_radius; +uniform float u_innerShape; +uniform float u_noiseScale; +uniform float u_noiseIterations; + +in vec2 v_objectUV; + +out vec4 fragColor; + +${declarePI} +${textureRandomizerR} +float valueNoise(vec2 st) { + vec2 i = floor(st); + vec2 f = fract(st); + float a = randomR(i); + float b = randomR(i + vec2(1.0, 0.0)); + float c = randomR(i + vec2(0.0, 1.0)); + float d = randomR(i + vec2(1.0, 1.0)); + vec2 u = f * f * (3.0 - 2.0 * f); + float x1 = mix(a, b, u.x); + float x2 = mix(c, d, u.x); + return mix(x1, x2, u.y); +} +vec2 fbm(vec2 n0, vec2 n1) { + vec2 total = vec2(0.0); + float amplitude = .4; + for (int i = 0; i < ${smokeRingMeta.maxNoiseIterations}; i++) { + if (i >= int(u_noiseIterations)) break; + total.x += valueNoise(n0) * amplitude; + total.y += valueNoise(n1) * amplitude; + n0 *= 1.99; + n1 *= 1.99; + amplitude *= 0.65; + } + return total; +} + +float getNoise(vec2 uv, vec2 pUv, float t) { + vec2 pUvLeft = pUv + .03 * t; + float period = max(abs(u_noiseScale * TWO_PI), 1e-6); + vec2 pUvRight = vec2(fract(pUv.x / period) * period, pUv.y) + .03 * t; + vec2 noise = fbm(pUvLeft, pUvRight); + return mix(noise.y, noise.x, smoothstep(-.25, .25, uv.x)); +} + +float getRingShape(vec2 uv) { + float radius = u_radius; + float thickness = u_thickness; + + float distance = length(uv); + float ringValue = 1. - smoothstep(radius, radius + thickness, distance); + ringValue *= smoothstep(radius - pow(u_innerShape, 3.) * thickness, radius, distance); + + return ringValue; +} + +void main() { + vec2 shape_uv = v_objectUV; + + float t = u_time; + + float cycleDuration = 3.; + float period2 = 2.0 * cycleDuration; + float localTime1 = fract((0.1 * t + cycleDuration) / period2) * period2; + float localTime2 = fract((0.1 * t) / period2) * period2; + float timeBlend = .5 + .5 * sin(.1 * t * PI / cycleDuration - .5 * PI); + + float atg = atan(shape_uv.y, shape_uv.x) + .001; + float l = length(shape_uv); + float radialOffset = .5 * l - inversesqrt(max(1e-4, l)); + vec2 polar_uv1 = vec2(atg, localTime1 - radialOffset) * u_noiseScale; + vec2 polar_uv2 = vec2(atg, localTime2 - radialOffset) * u_noiseScale; + + float noise1 = getNoise(shape_uv, polar_uv1, t); + float noise2 = getNoise(shape_uv, polar_uv2, t); + + float noise = mix(noise1, noise2, timeBlend); + + shape_uv *= (.8 + 1.2 * noise); + + float ringShape = getRingShape(shape_uv); + + float mixer = ringShape * ringShape * (u_colorsCount - 1.); + int idxLast = int(u_colorsCount) - 1; + vec4 gradient = u_colors[idxLast]; + gradient.rgb *= gradient.a; + for (int i = ${smokeRingMeta.maxColorCount} - 2; i >= 0; i--) { + float localT = clamp(mixer - float(idxLast - i - 1), 0., 1.); + vec4 c = u_colors[i]; + c.rgb *= c.a; + gradient = mix(gradient, c, localT); + } + + vec3 color = gradient.rgb * ringShape; + float opacity = gradient.a * ringShape; + + vec3 bgColor = u_colorBack.rgb * u_colorBack.a; + color = color + bgColor * (1. - opacity); + opacity = opacity + u_colorBack.a * (1. - opacity); + + ${colorBandingFix} + + fragColor = vec4(color, opacity); +} +`; +export { + smokeRingFragmentShader, + smokeRingMeta +}; +//# sourceMappingURL=smoke-ring.js.map diff --git a/public/vendor/paper-shaders/shaders/smoke-ring.js.map b/public/vendor/paper-shaders/shaders/smoke-ring.js.map new file mode 100644 index 0000000..0923f68 --- /dev/null +++ b/public/vendor/paper-shaders/shaders/smoke-ring.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../../src/shaders/smoke-ring.ts"], + "sourcesContent": ["import type { vec4 } from '../types.js';\nimport type { ShaderMotionParams } from '../shader-mount.js';\nimport { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { declarePI, textureRandomizerR, colorBandingFix } from '../shader-utils.js';\n\nexport const smokeRingMeta = {\n maxColorCount: 10,\n maxNoiseIterations: 8,\n} as const;\n\n/**\n * Radial multi-colored gradient shaped with layered noise for a natural, smoky aesthetic.\n *\n *\n * Fragment shader uniforms:\n * - u_time (float): Animation time\n * - u_colorBack (vec4): Background color in RGBA\n * - u_colors (vec4[]): Up to 10 gradient colors in RGBA\n * - u_colorsCount (float): Number of active colors\n * - u_thickness (float): Thickness of the ring shape (0.01 to 1)\n * - u_radius (float): Radius of the ring shape (0 to 1)\n * - u_innerShape (float): Ring inner fill amount (0 to 4)\n * - u_noiseIterations (float): Number of noise layers, more layers gives more details (1 to 8)\n * - u_noiseScale (float): Noise frequency (0.01 to 5)\n * - u_noiseTexture (sampler2D): Pre-computed randomizer source texture\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_objectUV (vec2): Object box UV coordinates with global sizing (scale, rotation, offsets, etc) applied\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n *\n */\n\n// language=GLSL\nexport const smokeRingFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform float u_time;\n\nuniform sampler2D u_noiseTexture;\n\nuniform vec4 u_colorBack;\nuniform vec4 u_colors[${ smokeRingMeta.maxColorCount }];\nuniform float u_colorsCount;\n\nuniform float u_thickness;\nuniform float u_radius;\nuniform float u_innerShape;\nuniform float u_noiseScale;\nuniform float u_noiseIterations;\n\nin vec2 v_objectUV;\n\nout vec4 fragColor;\n\n${ declarePI }\n${ textureRandomizerR }\nfloat valueNoise(vec2 st) {\n vec2 i = floor(st);\n vec2 f = fract(st);\n float a = randomR(i);\n float b = randomR(i + vec2(1.0, 0.0));\n float c = randomR(i + vec2(0.0, 1.0));\n float d = randomR(i + vec2(1.0, 1.0));\n vec2 u = f * f * (3.0 - 2.0 * f);\n float x1 = mix(a, b, u.x);\n float x2 = mix(c, d, u.x);\n return mix(x1, x2, u.y);\n}\nvec2 fbm(vec2 n0, vec2 n1) {\n vec2 total = vec2(0.0);\n float amplitude = .4;\n for (int i = 0; i < ${ smokeRingMeta.maxNoiseIterations }; i++) {\n if (i >= int(u_noiseIterations)) break;\n total.x += valueNoise(n0) * amplitude;\n total.y += valueNoise(n1) * amplitude;\n n0 *= 1.99;\n n1 *= 1.99;\n amplitude *= 0.65;\n }\n return total;\n}\n\nfloat getNoise(vec2 uv, vec2 pUv, float t) {\n vec2 pUvLeft = pUv + .03 * t;\n float period = max(abs(u_noiseScale * TWO_PI), 1e-6);\n vec2 pUvRight = vec2(fract(pUv.x / period) * period, pUv.y) + .03 * t;\n vec2 noise = fbm(pUvLeft, pUvRight);\n return mix(noise.y, noise.x, smoothstep(-.25, .25, uv.x));\n}\n\nfloat getRingShape(vec2 uv) {\n float radius = u_radius;\n float thickness = u_thickness;\n\n float distance = length(uv);\n float ringValue = 1. - smoothstep(radius, radius + thickness, distance);\n ringValue *= smoothstep(radius - pow(u_innerShape, 3.) * thickness, radius, distance);\n\n return ringValue;\n}\n\nvoid main() {\n vec2 shape_uv = v_objectUV;\n\n float t = u_time;\n\n float cycleDuration = 3.;\n float period2 = 2.0 * cycleDuration;\n float localTime1 = fract((0.1 * t + cycleDuration) / period2) * period2;\n float localTime2 = fract((0.1 * t) / period2) * period2;\n float timeBlend = .5 + .5 * sin(.1 * t * PI / cycleDuration - .5 * PI);\n\n float atg = atan(shape_uv.y, shape_uv.x) + .001;\n float l = length(shape_uv);\n float radialOffset = .5 * l - inversesqrt(max(1e-4, l));\n vec2 polar_uv1 = vec2(atg, localTime1 - radialOffset) * u_noiseScale;\n vec2 polar_uv2 = vec2(atg, localTime2 - radialOffset) * u_noiseScale;\n \n float noise1 = getNoise(shape_uv, polar_uv1, t);\n float noise2 = getNoise(shape_uv, polar_uv2, t);\n\n float noise = mix(noise1, noise2, timeBlend);\n\n shape_uv *= (.8 + 1.2 * noise);\n\n float ringShape = getRingShape(shape_uv);\n\n float mixer = ringShape * ringShape * (u_colorsCount - 1.);\n int idxLast = int(u_colorsCount) - 1;\n vec4 gradient = u_colors[idxLast];\n gradient.rgb *= gradient.a;\n for (int i = ${ smokeRingMeta.maxColorCount } - 2; i >= 0; i--) {\n float localT = clamp(mixer - float(idxLast - i - 1), 0., 1.);\n vec4 c = u_colors[i];\n c.rgb *= c.a;\n gradient = mix(gradient, c, localT);\n }\n\n vec3 color = gradient.rgb * ringShape;\n float opacity = gradient.a * ringShape;\n\n vec3 bgColor = u_colorBack.rgb * u_colorBack.a;\n color = color + bgColor * (1. - opacity);\n opacity = opacity + u_colorBack.a * (1. - opacity);\n\n ${ colorBandingFix }\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface SmokeRingUniforms extends ShaderSizingUniforms {\n u_colorBack: [number, number, number, number];\n u_colors: vec4[];\n u_colorsCount: number;\n u_noiseScale: number;\n u_thickness: number;\n u_radius: number;\n u_innerShape: number;\n u_noiseIterations: number;\n u_noiseTexture?: HTMLImageElement;\n}\n\nexport interface SmokeRingParams extends ShaderSizingParams, ShaderMotionParams {\n colorBack?: string;\n colors?: string[];\n noiseScale?: number;\n thickness?: number;\n radius?: number;\n innerShape?: number;\n noiseIterations?: number;\n}\n"], + "mappings": ";;;;;AAEA,eAAmE;AACnE,SAAS,WAAW,oBAAoB,uBAAuB;AAExD,MAAM,gBAAgB;AAAA,EAC3B,eAAe;AAAA,EACf,oBAAoB;AACtB;AAqCO,MAAM,0BAAkC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAQtB,cAAc,aAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAalD,SAAU;AAAA,EACV,kBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAgBG,cAAc,kBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBA4DxC,cAAc,aAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAczC,eAAgB;AAAA;AAAA;AAAA;AAAA;", + "names": [] +} diff --git a/public/vendor/paper-shaders/shaders/spiral.d.ts b/public/vendor/paper-shaders/shaders/spiral.d.ts new file mode 100644 index 0000000..ff53cef --- /dev/null +++ b/public/vendor/paper-shaders/shaders/spiral.d.ts @@ -0,0 +1,61 @@ +import type { ShaderMotionParams } from '../shader-mount.js'; +import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js'; +/** + * A single-colored animated spiral that morphs across a wide range of shapes - + * from crisp, thin-lined geometry to flowing whirlpool forms and wavy, abstract rings. + * + * Vertex shader uniforms: + * - u_resolution (vec2): Canvas resolution in pixels + * - u_pixelRatio (float): Device pixel ratio + * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1) + * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1) + * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas + * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas + * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover) + * - u_scale (float): Overall zoom level of the graphics (0.01 to 4) + * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360) + * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1) + * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1) + * + * Vertex shader outputs (used in fragment shader): + * - v_patternUV (vec2): UV coordinates in pixels (scaled by 0.01 for precision), with rotation and offset applied + * + * Fragment shader uniforms: + * - u_time (float): Animation time + * - u_colorBack (vec4): Background color in RGBA + * - u_colorFront (vec4): Foreground (ink) color in RGBA + * - u_density (float): Spacing falloff simulating perspective, 0 = flat spiral (0 to 1) + * - u_distortion (float): Power of shape distortion applied along the spiral (0 to 1) + * - u_strokeWidth (float): Thickness of spiral curve (0 to 1) + * - u_strokeTaper (float): How much stroke loses width away from center, 0 = full visibility (0 to 1) + * - u_strokeCap (float): Extra stroke width at the center, no effect with strokeWidth = 0.5 (0 to 1) + * - u_noise (float): Noise distortion applied over the canvas, no effect with noiseFrequency = 0 (0 to 1) + * - u_noiseFrequency (float): Noise frequency, no effect with noise = 0 (0 to 1) + * - u_softness (float): Color transition sharpness, 0 = hard edge, 1 = smooth gradient (0 to 1) + * + */ +export declare const spiralFragmentShader: string; +export interface SpiralUniforms extends ShaderSizingUniforms { + u_colorBack: [number, number, number, number]; + u_colorFront: [number, number, number, number]; + u_density: number; + u_distortion: number; + u_strokeWidth: number; + u_strokeTaper: number; + u_strokeCap: number; + u_noise: number; + u_noiseFrequency: number; + u_softness: number; +} +export interface SpiralParams extends ShaderSizingParams, ShaderMotionParams { + colorBack?: string; + colorFront?: string; + density?: number; + distortion?: number; + strokeWidth?: number; + strokeTaper?: number; + strokeCap?: number; + noise?: number; + noiseFrequency?: number; + softness?: number; +} diff --git a/public/vendor/paper-shaders/shaders/spiral.js b/public/vendor/paper-shaders/shaders/spiral.js new file mode 100644 index 0000000..76152d9 --- /dev/null +++ b/public/vendor/paper-shaders/shaders/spiral.js @@ -0,0 +1,81 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Paper Shaders * + * https://github.com/paper-design/shaders * + * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +import {} from "../shader-sizing.js"; +import { simplexNoise, declarePI, colorBandingFix } from "../shader-utils.js"; +const spiralFragmentShader = `#version 300 es +precision mediump float; + +uniform float u_time; + +uniform vec4 u_colorBack; +uniform vec4 u_colorFront; +uniform float u_density; +uniform float u_distortion; +uniform float u_strokeWidth; +uniform float u_strokeCap; +uniform float u_strokeTaper; +uniform float u_noise; +uniform float u_noiseFrequency; +uniform float u_softness; + +in vec2 v_patternUV; + +out vec4 fragColor; + +${declarePI} +${simplexNoise} + +void main() { + vec2 uv = 2. * v_patternUV; + + float t = u_time; + float l = length(uv); + float density = clamp(u_density, 0., 1.); + l = pow(max(l, 1e-6), density); + float angle = atan(uv.y, uv.x) - t; + float angleNormalised = angle / TWO_PI; + + angleNormalised += .125 * u_noise * snoise(16. * pow(u_noiseFrequency, 3.) * uv); + + float offset = l + angleNormalised; + offset -= u_distortion * (sin(4. * l - .5 * t) * cos(PI + l + .5 * t)); + float stripe = fract(offset); + + float shape = 2. * abs(stripe - .5); + float width = 1. - clamp(u_strokeWidth, .005 * u_strokeTaper, 1.); + + + float wCap = mix(width, (1. - stripe) * (1. - step(.5, stripe)), (1. - clamp(l, 0., 1.))); + width = mix(width, wCap, u_strokeCap); + width *= (1. - clamp(u_strokeTaper, 0., 1.) * l); + + float fw = fwidth(offset); + float fwMult = 4. - 3. * (smoothstep(.05, .4, 2. * u_strokeWidth) * smoothstep(.05, .4, 2. * (1. - u_strokeWidth))); + float pixelSize = mix(fwMult * fw, fwidth(shape), clamp(fw, 0., 1.)); + pixelSize = mix(pixelSize, .002, u_strokeCap * (1. - clamp(l, 0., 1.))); + + float res = smoothstep(width - pixelSize - u_softness, width + pixelSize + u_softness, shape); + + vec3 fgColor = u_colorFront.rgb * u_colorFront.a; + float fgOpacity = u_colorFront.a; + vec3 bgColor = u_colorBack.rgb * u_colorBack.a; + float bgOpacity = u_colorBack.a; + + vec3 color = fgColor * res; + float opacity = fgOpacity * res; + + color += bgColor * (1. - opacity); + opacity += bgOpacity * (1. - opacity); + + ${colorBandingFix} + + fragColor = vec4(color, opacity); +} +`; +export { + spiralFragmentShader +}; +//# sourceMappingURL=spiral.js.map diff --git a/public/vendor/paper-shaders/shaders/spiral.js.map b/public/vendor/paper-shaders/shaders/spiral.js.map new file mode 100644 index 0000000..9b1d972 --- /dev/null +++ b/public/vendor/paper-shaders/shaders/spiral.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../../src/shaders/spiral.ts"], + "sourcesContent": ["import type { ShaderMotionParams } from '../shader-mount.js';\nimport { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { simplexNoise, declarePI, colorBandingFix } from '../shader-utils.js';\n\n/**\n * A single-colored animated spiral that morphs across a wide range of shapes -\n * from crisp, thin-lined geometry to flowing whirlpool forms and wavy, abstract rings.\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_patternUV (vec2): UV coordinates in pixels (scaled by 0.01 for precision), with rotation and offset applied\n *\n * Fragment shader uniforms:\n * - u_time (float): Animation time\n * - u_colorBack (vec4): Background color in RGBA\n * - u_colorFront (vec4): Foreground (ink) color in RGBA\n * - u_density (float): Spacing falloff simulating perspective, 0 = flat spiral (0 to 1)\n * - u_distortion (float): Power of shape distortion applied along the spiral (0 to 1)\n * - u_strokeWidth (float): Thickness of spiral curve (0 to 1)\n * - u_strokeTaper (float): How much stroke loses width away from center, 0 = full visibility (0 to 1)\n * - u_strokeCap (float): Extra stroke width at the center, no effect with strokeWidth = 0.5 (0 to 1)\n * - u_noise (float): Noise distortion applied over the canvas, no effect with noiseFrequency = 0 (0 to 1)\n * - u_noiseFrequency (float): Noise frequency, no effect with noise = 0 (0 to 1)\n * - u_softness (float): Color transition sharpness, 0 = hard edge, 1 = smooth gradient (0 to 1)\n *\n */\n\n// language=GLSL\nexport const spiralFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform float u_time;\n\nuniform vec4 u_colorBack;\nuniform vec4 u_colorFront;\nuniform float u_density;\nuniform float u_distortion;\nuniform float u_strokeWidth;\nuniform float u_strokeCap;\nuniform float u_strokeTaper;\nuniform float u_noise;\nuniform float u_noiseFrequency;\nuniform float u_softness;\n\nin vec2 v_patternUV;\n\nout vec4 fragColor;\n\n${ declarePI }\n${ simplexNoise }\n\nvoid main() {\n vec2 uv = 2. * v_patternUV;\n\n float t = u_time;\n float l = length(uv);\n float density = clamp(u_density, 0., 1.);\n l = pow(max(l, 1e-6), density);\n float angle = atan(uv.y, uv.x) - t;\n float angleNormalised = angle / TWO_PI;\n\n angleNormalised += .125 * u_noise * snoise(16. * pow(u_noiseFrequency, 3.) * uv);\n\n float offset = l + angleNormalised;\n offset -= u_distortion * (sin(4. * l - .5 * t) * cos(PI + l + .5 * t));\n float stripe = fract(offset);\n\n float shape = 2. * abs(stripe - .5);\n float width = 1. - clamp(u_strokeWidth, .005 * u_strokeTaper, 1.);\n\n\n float wCap = mix(width, (1. - stripe) * (1. - step(.5, stripe)), (1. - clamp(l, 0., 1.)));\n width = mix(width, wCap, u_strokeCap);\n width *= (1. - clamp(u_strokeTaper, 0., 1.) * l);\n\n float fw = fwidth(offset);\n float fwMult = 4. - 3. * (smoothstep(.05, .4, 2. * u_strokeWidth) * smoothstep(.05, .4, 2. * (1. - u_strokeWidth)));\n float pixelSize = mix(fwMult * fw, fwidth(shape), clamp(fw, 0., 1.));\n pixelSize = mix(pixelSize, .002, u_strokeCap * (1. - clamp(l, 0., 1.)));\n\n float res = smoothstep(width - pixelSize - u_softness, width + pixelSize + u_softness, shape);\n\n vec3 fgColor = u_colorFront.rgb * u_colorFront.a;\n float fgOpacity = u_colorFront.a;\n vec3 bgColor = u_colorBack.rgb * u_colorBack.a;\n float bgOpacity = u_colorBack.a;\n\n vec3 color = fgColor * res;\n float opacity = fgOpacity * res;\n\n color += bgColor * (1. - opacity);\n opacity += bgOpacity * (1. - opacity);\n\n ${ colorBandingFix }\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface SpiralUniforms extends ShaderSizingUniforms {\n u_colorBack: [number, number, number, number];\n u_colorFront: [number, number, number, number];\n u_density: number;\n u_distortion: number;\n u_strokeWidth: number;\n u_strokeTaper: number;\n u_strokeCap: number;\n u_noise: number;\n u_noiseFrequency: number;\n u_softness: number;\n}\n\nexport interface SpiralParams extends ShaderSizingParams, ShaderMotionParams {\n colorBack?: string;\n colorFront?: string;\n density?: number;\n distortion?: number;\n strokeWidth?: number;\n strokeTaper?: number;\n strokeCap?: number;\n noise?: number;\n noiseFrequency?: number;\n softness?: number;\n}\n"], + "mappings": ";;;;;AACA,eAAmE;AACnE,SAAS,cAAc,WAAW,uBAAuB;AAsClD,MAAM,uBAA+B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAoBzC,SAAU;AAAA,EACV,YAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA4CX,eAAgB;AAAA;AAAA;AAAA;AAAA;", + "names": [] +} diff --git a/public/vendor/paper-shaders/shaders/static-mesh-gradient.d.ts b/public/vendor/paper-shaders/shaders/static-mesh-gradient.d.ts new file mode 100644 index 0000000..aa8ff75 --- /dev/null +++ b/public/vendor/paper-shaders/shaders/static-mesh-gradient.d.ts @@ -0,0 +1,63 @@ +import type { vec4 } from '../types.js'; +import type { ShaderMotionParams } from '../shader-mount.js'; +import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js'; +export declare const staticMeshGradientMeta: { + readonly maxColorCount: 10; +}; +/** + * Multi-point mesh gradient with up to 10 color spots, enhanced by two-direction warping, + * adjustable blend sharpness, and grain controls. + * + * Fragment shader uniforms: + * - u_colors (vec4[]): Up to 10 gradient colors in RGBA + * - u_colorsCount (float): Number of active colors + * - u_positions (float): Color spots placement seed (0 to 100) + * - u_waveX (float): Strength of sine wave distortion along X axis (0 to 1) + * - u_waveXShift (float): Phase offset applied to the X-axis wave (0 to 1) + * - u_waveY (float): Strength of sine wave distortion along Y axis (0 to 1) + * - u_waveYShift (float): Phase offset applied to the Y-axis wave (0 to 1) + * - u_mixing (float): Blending behavior, 0 = hard stripes, 0.5 = smooth, 1 = gradual blend (0 to 1) + * - u_grainMixer (float): Strength of grain distortion applied to shape edges (0 to 1) + * - u_grainOverlay (float): Post-processing black/white grain overlay (0 to 1) + * + * Vertex shader outputs (used in fragment shader): + * - v_objectUV (vec2): Object box UV coordinates with global sizing (scale, rotation, offsets, etc) applied + * + * Vertex shader uniforms: + * - u_resolution (vec2): Canvas resolution in pixels + * - u_pixelRatio (float): Device pixel ratio + * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1) + * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1) + * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas + * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas + * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover) + * - u_scale (float): Overall zoom level of the graphics (0.01 to 4) + * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360) + * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1) + * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1) + * + */ +export declare const staticMeshGradientFragmentShader: string; +export interface StaticMeshGradientUniforms extends ShaderSizingUniforms { + u_colors: vec4[]; + u_colorsCount: number; + u_positions: number; + u_waveX: number; + u_waveXShift: number; + u_waveY: number; + u_waveYShift: number; + u_mixing: number; + u_grainMixer: number; + u_grainOverlay: number; +} +export interface StaticMeshGradientParams extends ShaderSizingParams, ShaderMotionParams { + colors?: string[]; + positions?: number; + waveX?: number; + waveXShift?: number; + waveY?: number; + waveYShift?: number; + mixing?: number; + grainMixer?: number; + grainOverlay?: number; +} diff --git a/public/vendor/paper-shaders/shaders/static-mesh-gradient.js b/public/vendor/paper-shaders/shaders/static-mesh-gradient.js new file mode 100644 index 0000000..32701a8 --- /dev/null +++ b/public/vendor/paper-shaders/shaders/static-mesh-gradient.js @@ -0,0 +1,128 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Paper Shaders * + * https://github.com/paper-design/shaders * + * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +import { +} from "../shader-sizing.js"; +import { declarePI, rotation2, proceduralHash21 } from "../shader-utils.js"; +const staticMeshGradientMeta = { + maxColorCount: 10 +}; +const staticMeshGradientFragmentShader = `#version 300 es +precision mediump float; + +uniform vec4 u_colors[${staticMeshGradientMeta.maxColorCount}]; +uniform float u_colorsCount; + +uniform float u_positions; +uniform float u_waveX; +uniform float u_waveXShift; +uniform float u_waveY; +uniform float u_waveYShift; +uniform float u_mixing; +uniform float u_grainMixer; +uniform float u_grainOverlay; + +in vec2 v_objectUV; +out vec4 fragColor; + +${declarePI} +${rotation2} +${proceduralHash21} + +float valueNoise(vec2 st) { + vec2 i = floor(st); + vec2 f = fract(st); + float a = hash21(i); + float b = hash21(i + vec2(1.0, 0.0)); + float c = hash21(i + vec2(0.0, 1.0)); + float d = hash21(i + vec2(1.0, 1.0)); + vec2 u = f * f * (3.0 - 2.0 * f); + float x1 = mix(a, b, u.x); + float x2 = mix(c, d, u.x); + return mix(x1, x2, u.y); +} + +float noise(vec2 n, vec2 seedOffset) { + return valueNoise(n + seedOffset); +} + +vec2 getPosition(int i, float t) { + float a = float(i) * .37; + float b = .6 + mod(float(i), 3.) * .3; + float c = .8 + mod(float(i + 1), 4.) * 0.25; + + float x = sin(t * b + a); + float y = cos(t * c + a * 1.5); + + return .5 + .5 * vec2(x, y); +} + +void main() { + vec2 uv = v_objectUV; + uv += .5; + vec2 grainUV = uv * 1000.; + + float grain = noise(grainUV, vec2(0.)); + float mixerGrain = .4 * u_grainMixer * (grain - .5); + + float radius = smoothstep(0., 1., length(uv - .5)); + float center = 1. - radius; + for (float i = 1.; i <= 2.; i++) { + uv.x += u_waveX * center / i * cos(TWO_PI * u_waveXShift + i * 2. * smoothstep(.0, 1., uv.y)); + uv.y += u_waveY * center / i * cos(TWO_PI * u_waveYShift + i * 2. * smoothstep(.0, 1., uv.x)); + } + + vec3 color = vec3(0.); + float opacity = 0.; + float totalWeight = 0.; + float positionSeed = 25. + .33 * u_positions; + + for (int i = 0; i < ${staticMeshGradientMeta.maxColorCount}; i++) { + if (i >= int(u_colorsCount)) break; + + vec2 pos = getPosition(i, positionSeed) + mixerGrain; + float dist = length(uv - pos); + dist = length(uv - pos); + + vec3 colorFraction = u_colors[i].rgb * u_colors[i].a; + float opacityFraction = u_colors[i].a; + + float mixing = pow(u_mixing, .7); + float power = mix(2., 1., mixing); + dist = pow(dist, power); + + float w = 1. / (dist + 1e-3); + float baseSharpness = mix(.0, 8., clamp(w, 0., 1.)); + float sharpness = mix(baseSharpness, 1., mixing); + w = pow(w, sharpness); + color += colorFraction * w; + opacity += opacityFraction * w; + totalWeight += w; + } + + color /= max(1e-4, totalWeight); + opacity /= max(1e-4, totalWeight); + + float grainOverlay = valueNoise(rotate(grainUV, 1.) + vec2(3.)); + grainOverlay = mix(grainOverlay, valueNoise(rotate(grainUV, 2.) + vec2(-1.)), .5); + grainOverlay = pow(grainOverlay, 1.3); + + float grainOverlayV = grainOverlay * 2. - 1.; + vec3 grainOverlayColor = vec3(step(0., grainOverlayV)); + float grainOverlayStrength = u_grainOverlay * abs(grainOverlayV); + grainOverlayStrength = pow(grainOverlayStrength, .8); + color = mix(color, grainOverlayColor, .35 * grainOverlayStrength); + + opacity += .5 * grainOverlayStrength; + opacity = clamp(opacity, 0., 1.); + + fragColor = vec4(color, opacity); +} +`; +export { + staticMeshGradientFragmentShader, + staticMeshGradientMeta +}; +//# sourceMappingURL=static-mesh-gradient.js.map diff --git a/public/vendor/paper-shaders/shaders/static-mesh-gradient.js.map b/public/vendor/paper-shaders/shaders/static-mesh-gradient.js.map new file mode 100644 index 0000000..cee90ec --- /dev/null +++ b/public/vendor/paper-shaders/shaders/static-mesh-gradient.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../../src/shaders/static-mesh-gradient.ts"], + "sourcesContent": ["import type { vec4 } from '../types.js';\nimport type { ShaderMotionParams } from '../shader-mount.js';\nimport {\n type ShaderSizingParams,\n type ShaderSizingUniforms,\n} from '../shader-sizing.js';\nimport { declarePI, rotation2, proceduralHash21 } from '../shader-utils.js';\n\nexport const staticMeshGradientMeta = {\n maxColorCount: 10,\n} as const;\n\n/**\n * Multi-point mesh gradient with up to 10 color spots, enhanced by two-direction warping,\n * adjustable blend sharpness, and grain controls.\n *\n * Fragment shader uniforms:\n * - u_colors (vec4[]): Up to 10 gradient colors in RGBA\n * - u_colorsCount (float): Number of active colors\n * - u_positions (float): Color spots placement seed (0 to 100)\n * - u_waveX (float): Strength of sine wave distortion along X axis (0 to 1)\n * - u_waveXShift (float): Phase offset applied to the X-axis wave (0 to 1)\n * - u_waveY (float): Strength of sine wave distortion along Y axis (0 to 1)\n * - u_waveYShift (float): Phase offset applied to the Y-axis wave (0 to 1)\n * - u_mixing (float): Blending behavior, 0 = hard stripes, 0.5 = smooth, 1 = gradual blend (0 to 1)\n * - u_grainMixer (float): Strength of grain distortion applied to shape edges (0 to 1)\n * - u_grainOverlay (float): Post-processing black/white grain overlay (0 to 1)\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_objectUV (vec2): Object box UV coordinates with global sizing (scale, rotation, offsets, etc) applied\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n *\n */\n\n// language=GLSL\nexport const staticMeshGradientFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform vec4 u_colors[${ staticMeshGradientMeta.maxColorCount }];\nuniform float u_colorsCount;\n\nuniform float u_positions;\nuniform float u_waveX;\nuniform float u_waveXShift;\nuniform float u_waveY;\nuniform float u_waveYShift;\nuniform float u_mixing;\nuniform float u_grainMixer;\nuniform float u_grainOverlay;\n\nin vec2 v_objectUV;\nout vec4 fragColor;\n\n${ declarePI }\n${ rotation2 }\n${ proceduralHash21 }\n\nfloat valueNoise(vec2 st) {\n vec2 i = floor(st);\n vec2 f = fract(st);\n float a = hash21(i);\n float b = hash21(i + vec2(1.0, 0.0));\n float c = hash21(i + vec2(0.0, 1.0));\n float d = hash21(i + vec2(1.0, 1.0));\n vec2 u = f * f * (3.0 - 2.0 * f);\n float x1 = mix(a, b, u.x);\n float x2 = mix(c, d, u.x);\n return mix(x1, x2, u.y);\n}\n\nfloat noise(vec2 n, vec2 seedOffset) {\n return valueNoise(n + seedOffset);\n}\n\nvec2 getPosition(int i, float t) {\n float a = float(i) * .37;\n float b = .6 + mod(float(i), 3.) * .3;\n float c = .8 + mod(float(i + 1), 4.) * 0.25;\n\n float x = sin(t * b + a);\n float y = cos(t * c + a * 1.5);\n\n return .5 + .5 * vec2(x, y);\n}\n\nvoid main() {\n vec2 uv = v_objectUV;\n uv += .5;\n vec2 grainUV = uv * 1000.;\n\n float grain = noise(grainUV, vec2(0.));\n float mixerGrain = .4 * u_grainMixer * (grain - .5);\n\n float radius = smoothstep(0., 1., length(uv - .5));\n float center = 1. - radius;\n for (float i = 1.; i <= 2.; i++) {\n uv.x += u_waveX * center / i * cos(TWO_PI * u_waveXShift + i * 2. * smoothstep(.0, 1., uv.y));\n uv.y += u_waveY * center / i * cos(TWO_PI * u_waveYShift + i * 2. * smoothstep(.0, 1., uv.x));\n }\n\n vec3 color = vec3(0.);\n float opacity = 0.;\n float totalWeight = 0.;\n float positionSeed = 25. + .33 * u_positions;\n\n for (int i = 0; i < ${ staticMeshGradientMeta.maxColorCount }; i++) {\n if (i >= int(u_colorsCount)) break;\n\n vec2 pos = getPosition(i, positionSeed) + mixerGrain;\n float dist = length(uv - pos);\n dist = length(uv - pos);\n\n vec3 colorFraction = u_colors[i].rgb * u_colors[i].a;\n float opacityFraction = u_colors[i].a;\n\n float mixing = pow(u_mixing, .7);\n float power = mix(2., 1., mixing);\n dist = pow(dist, power);\n\n float w = 1. / (dist + 1e-3);\n float baseSharpness = mix(.0, 8., clamp(w, 0., 1.));\n float sharpness = mix(baseSharpness, 1., mixing);\n w = pow(w, sharpness);\n color += colorFraction * w;\n opacity += opacityFraction * w;\n totalWeight += w;\n }\n\n color /= max(1e-4, totalWeight);\n opacity /= max(1e-4, totalWeight);\n\n float grainOverlay = valueNoise(rotate(grainUV, 1.) + vec2(3.));\n grainOverlay = mix(grainOverlay, valueNoise(rotate(grainUV, 2.) + vec2(-1.)), .5);\n grainOverlay = pow(grainOverlay, 1.3);\n\n float grainOverlayV = grainOverlay * 2. - 1.;\n vec3 grainOverlayColor = vec3(step(0., grainOverlayV));\n float grainOverlayStrength = u_grainOverlay * abs(grainOverlayV);\n grainOverlayStrength = pow(grainOverlayStrength, .8);\n color = mix(color, grainOverlayColor, .35 * grainOverlayStrength);\n\n opacity += .5 * grainOverlayStrength;\n opacity = clamp(opacity, 0., 1.);\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface StaticMeshGradientUniforms extends ShaderSizingUniforms {\n u_colors: vec4[];\n u_colorsCount: number;\n u_positions: number;\n u_waveX: number;\n u_waveXShift: number;\n u_waveY: number;\n u_waveYShift: number;\n u_mixing: number;\n u_grainMixer: number;\n u_grainOverlay: number;\n}\n\nexport interface StaticMeshGradientParams extends ShaderSizingParams, ShaderMotionParams {\n colors?: string[];\n positions?: number;\n waveX?: number;\n waveXShift?: number;\n waveY?: number;\n waveYShift?: number;\n mixing?: number;\n grainMixer?: number;\n grainOverlay?: number;\n}\n"], + "mappings": ";;;;;AAEA;AAAA,OAGO;AACP,SAAS,WAAW,WAAW,wBAAwB;AAEhD,MAAM,yBAAyB;AAAA,EACpC,eAAe;AACjB;AAqCO,MAAM,mCAA2C;AAAA;AAAA;AAAA,wBAG/B,uBAAuB,aAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAe3D,SAAU;AAAA,EACV,SAAU;AAAA,EACV,gBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAkDK,uBAAuB,aAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;", + "names": [] +} diff --git a/public/vendor/paper-shaders/shaders/static-radial-gradient.d.ts b/public/vendor/paper-shaders/shaders/static-radial-gradient.d.ts new file mode 100644 index 0000000..6c0cd5b --- /dev/null +++ b/public/vendor/paper-shaders/shaders/static-radial-gradient.d.ts @@ -0,0 +1,72 @@ +import type { vec4 } from '../types.js'; +import type { ShaderMotionParams } from '../shader-mount.js'; +import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js'; +export declare const staticRadialGradientMeta: { + readonly maxColorCount: 10; +}; +/** + * Radial gradient with up to 10 blended colors, featuring advanced mixing modes, focal point controls, + * shape distortion, and grain effects. + * + * Fragment shader uniforms: + * - u_colorBack (vec4): Background color in RGBA + * - u_colors (vec4[]): Up to 10 gradient colors in RGBA + * - u_colorsCount (float): Number of active colors + * - u_radius (float): Size of the shape (0 to 3) + * - u_focalDistance (float): Distance of the focal point from center (0 to 3) + * - u_focalAngle (float): Angle of the focal point in degrees, effective with focalDistance > 0 (0 to 360) + * - u_falloff (float): Gradient decay, 0 = linear gradient (-1 to 1) + * - u_mixing (float): Blending behavior, 0 = hard stripes, 1 = smooth gradient (0 to 1) + * - u_distortion (float): Strength of radial distortion (0 to 1) + * - u_distortionShift (float): Radial distortion offset, effective with distortion > 0 (-1 to 1) + * - u_distortionFreq (float): Radial distortion frequency, effective with distortion > 0 (0 to 20) + * - u_grainMixer (float): Strength of grain distortion applied to shape edges (0 to 1) + * - u_grainOverlay (float): Post-processing black/white grain overlay (0 to 1) + * + * Vertex shader outputs (used in fragment shader): + * - v_objectUV (vec2): Object box UV coordinates with global sizing (scale, rotation, offsets, etc) applied + * + * Vertex shader uniforms: + * - u_resolution (vec2): Canvas resolution in pixels + * - u_pixelRatio (float): Device pixel ratio + * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1) + * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1) + * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas + * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas + * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover) + * - u_scale (float): Overall zoom level of the graphics (0.01 to 4) + * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360) + * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1) + * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1) + * + */ +export declare const staticRadialGradientFragmentShader: string; +export interface StaticRadialGradientUniforms extends ShaderSizingUniforms { + u_colorBack: [number, number, number, number]; + u_colors: vec4[]; + u_colorsCount: number; + u_radius: number; + u_focalDistance: number; + u_focalAngle: number; + u_falloff: number; + u_mixing: number; + u_distortion: number; + u_distortionShift: number; + u_distortionFreq: number; + u_grainMixer: number; + u_grainOverlay: number; +} +export interface StaticRadialGradientParams extends ShaderSizingParams, ShaderMotionParams { + colorBack?: string; + colors?: string[]; + radius?: number; + focalDistance?: number; + focalAngle?: number; + falloff?: number; + mixing?: number; + distortion?: number; + distortionShift?: number; + distortionFreq?: number; + grainMixer?: number; + grainOverlay?: number; +} diff --git a/public/vendor/paper-shaders/shaders/static-radial-gradient.js b/public/vendor/paper-shaders/shaders/static-radial-gradient.js new file mode 100644 index 0000000..b52ae09 --- /dev/null +++ b/public/vendor/paper-shaders/shaders/static-radial-gradient.js @@ -0,0 +1,184 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Paper Shaders * + * https://github.com/paper-design/shaders * + * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +import { +} from "../shader-sizing.js"; +import { declarePI, rotation2, proceduralHash21 } from "../shader-utils.js"; +const staticRadialGradientMeta = { + maxColorCount: 10 +}; +const staticRadialGradientFragmentShader = `#version 300 es +precision mediump float; + +uniform vec4 u_colorBack; +uniform vec4 u_colors[${staticRadialGradientMeta.maxColorCount}]; +uniform float u_colorsCount; + +uniform float u_radius; +uniform float u_focalDistance; +uniform float u_focalAngle; +uniform float u_falloff; +uniform float u_mixing; +uniform float u_distortion; +uniform float u_distortionShift; +uniform float u_distortionFreq; +uniform float u_grainMixer; +uniform float u_grainOverlay; + +in vec2 v_objectUV; +out vec4 fragColor; + +${declarePI} +${rotation2} +${proceduralHash21} + +float valueNoise(vec2 st) { + vec2 i = floor(st); + vec2 f = fract(st); + float a = hash21(i); + float b = hash21(i + vec2(1.0, 0.0)); + float c = hash21(i + vec2(0.0, 1.0)); + float d = hash21(i + vec2(1.0, 1.0)); + vec2 u = f * f * (3.0 - 2.0 * f); + float x1 = mix(a, b, u.x); + float x2 = mix(c, d, u.x); + return mix(x1, x2, u.y); +} + +float noise(vec2 n, vec2 seedOffset) { + return valueNoise(n + seedOffset); +} + +vec2 getPosition(int i, float t) { + float a = float(i) * .37; + float b = .6 + mod(float(i), 3.) * .3; + float c = .8 + mod(float(i + 1), 4.) * 0.25; + + float x = sin(t * b + a); + float y = cos(t * c + a * 1.5); + + return .5 + .5 * vec2(x, y); +} + +void main() { + vec2 uv = 2. * v_objectUV; + vec2 grainUV = uv * 1000.; + + vec2 center = vec2(0.); + float angleRad = -radians(u_focalAngle + 90.); + vec2 focalPoint = vec2(cos(angleRad), sin(angleRad)) * u_focalDistance; + float radius = u_radius; + + vec2 c_to_uv = uv - center; + vec2 f_to_uv = uv - focalPoint; + vec2 f_to_c = center - focalPoint; + float r = length(c_to_uv); + + float fragAngle = atan(c_to_uv.y, c_to_uv.x); + float angleDiff = fract((fragAngle - angleRad + PI) / TWO_PI) * TWO_PI - PI; + + float halfAngle = acos(clamp(radius / max(u_focalDistance, 1e-4), 0.0, 1.0)); + float e0 = 0.6 * PI, e1 = halfAngle; + float lo = min(e0, e1), hi = max(e0, e1); + float s = smoothstep(lo, hi, abs(angleDiff)); + float isInSector = (e1 >= e0) ? (1.0 - s) : s; + + float a = dot(f_to_uv, f_to_uv); + float b = -2.0 * dot(f_to_uv, f_to_c); + float c = dot(f_to_c, f_to_c) - radius * radius; + + float discriminant = b * b - 4.0 * a * c; + float t = 1.0; + + if (discriminant >= 0.0) { + float sqrtD = sqrt(discriminant); + float div = max(1e-4, 2.0 * a); + float t0 = (-b - sqrtD) / div; + float t1 = (-b + sqrtD) / div; + t = max(t0, t1); + if (t < 0.0) t = 0.0; + } + + float dist = length(f_to_uv); + float normalized = dist / max(1e-4, length(f_to_uv * t)); + float shape = clamp(normalized, 0.0, 1.0); + + float falloffMapped = mix(.2 + .8 * max(0., u_falloff + 1.), mix(1., 15., u_falloff * u_falloff), step(.0, u_falloff)); + + float falloffExp = mix(falloffMapped, 1., shape); + shape = pow(shape, falloffExp); + shape = 1. - clamp(shape, 0., 1.); + + + float outerMask = .002; + float outer = 1.0 - smoothstep(radius - outerMask, radius + outerMask, r); + outer = mix(outer, 1., isInSector); + + shape = mix(0., shape, outer); + shape *= 1. - smoothstep(radius - .01, radius, r); + + float angle = atan(f_to_uv.y, f_to_uv.x); + shape -= pow(u_distortion, 2.) * shape * pow(abs(sin(PI * clamp(length(f_to_uv) - 0.2 + u_distortionShift, 0.0, 1.0))), 4.0) * (sin(u_distortionFreq * angle) + cos(floor(0.65 * u_distortionFreq) * angle)); + + float grain = noise(grainUV, vec2(0.)); + float mixerGrain = .4 * u_grainMixer * (grain - .5); + + float mixer = shape * u_colorsCount + mixerGrain; + vec4 gradient = u_colors[0]; + gradient.rgb *= gradient.a; + + float outerShape = 0.; + for (int i = 1; i < ${staticRadialGradientMeta.maxColorCount + 1}; i++) { + if (i > int(u_colorsCount)) break; + float mLinear = clamp(mixer - float(i - 1), 0.0, 1.0); + + float aa = fwidth(mLinear); + float width = min(u_mixing, 0.5); + float t = clamp((mLinear - (0.5 - width - aa)) / (2. * width + 2. * aa), 0., 1.); + float p = mix(2., 1., clamp((u_mixing - 0.5) * 2., 0., 1.)); + float m = t < 0.5 + ? 0.5 * pow(2. * t, p) + : 1. - 0.5 * pow(2. * (1. - t), p); + + float quadBlend = clamp((u_mixing - 0.5) * 2., 0., 1.); + m = mix(m, m * m, 0.5 * quadBlend); + + if (i == 1) { + outerShape = m; + } + + vec4 c = u_colors[i - 1]; + c.rgb *= c.a; + gradient = mix(gradient, c, m); + } + + vec3 color = gradient.rgb * outerShape; + float opacity = gradient.a * outerShape; + + vec3 bgColor = u_colorBack.rgb * u_colorBack.a; + color = color + bgColor * (1.0 - opacity); + opacity = opacity + u_colorBack.a * (1.0 - opacity); + + float grainOverlay = valueNoise(rotate(grainUV, 1.) + vec2(3.)); + grainOverlay = mix(grainOverlay, valueNoise(rotate(grainUV, 2.) + vec2(-1.)), .5); + grainOverlay = pow(grainOverlay, 1.3); + + float grainOverlayV = grainOverlay * 2. - 1.; + vec3 grainOverlayColor = vec3(step(0., grainOverlayV)); + float grainOverlayStrength = u_grainOverlay * abs(grainOverlayV); + grainOverlayStrength = pow(grainOverlayStrength, .8); + color = mix(color, grainOverlayColor, .35 * grainOverlayStrength); + + opacity += .5 * grainOverlayStrength; + opacity = clamp(opacity, 0., 1.); + + fragColor = vec4(color, opacity); +} +`; +export { + staticRadialGradientFragmentShader, + staticRadialGradientMeta +}; +//# sourceMappingURL=static-radial-gradient.js.map diff --git a/public/vendor/paper-shaders/shaders/static-radial-gradient.js.map b/public/vendor/paper-shaders/shaders/static-radial-gradient.js.map new file mode 100644 index 0000000..c27e009 --- /dev/null +++ b/public/vendor/paper-shaders/shaders/static-radial-gradient.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../../src/shaders/static-radial-gradient.ts"], + "sourcesContent": ["import type { vec4 } from '../types.js';\nimport type { ShaderMotionParams } from '../shader-mount.js';\nimport {\n type ShaderSizingParams,\n type ShaderSizingUniforms,\n} from '../shader-sizing.js';\nimport { declarePI, rotation2, proceduralHash21 } from '../shader-utils.js';\n\nexport const staticRadialGradientMeta = {\n maxColorCount: 10,\n} as const;\n\n/**\n * Radial gradient with up to 10 blended colors, featuring advanced mixing modes, focal point controls,\n * shape distortion, and grain effects.\n *\n * Fragment shader uniforms:\n * - u_colorBack (vec4): Background color in RGBA\n * - u_colors (vec4[]): Up to 10 gradient colors in RGBA\n * - u_colorsCount (float): Number of active colors\n * - u_radius (float): Size of the shape (0 to 3)\n * - u_focalDistance (float): Distance of the focal point from center (0 to 3)\n * - u_focalAngle (float): Angle of the focal point in degrees, effective with focalDistance > 0 (0 to 360)\n * - u_falloff (float): Gradient decay, 0 = linear gradient (-1 to 1)\n * - u_mixing (float): Blending behavior, 0 = hard stripes, 1 = smooth gradient (0 to 1)\n * - u_distortion (float): Strength of radial distortion (0 to 1)\n * - u_distortionShift (float): Radial distortion offset, effective with distortion > 0 (-1 to 1)\n * - u_distortionFreq (float): Radial distortion frequency, effective with distortion > 0 (0 to 20)\n * - u_grainMixer (float): Strength of grain distortion applied to shape edges (0 to 1)\n * - u_grainOverlay (float): Post-processing black/white grain overlay (0 to 1)\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_objectUV (vec2): Object box UV coordinates with global sizing (scale, rotation, offsets, etc) applied\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n *\n */\n\n// language=GLSL\nexport const staticRadialGradientFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform vec4 u_colorBack;\nuniform vec4 u_colors[${ staticRadialGradientMeta.maxColorCount }];\nuniform float u_colorsCount;\n\nuniform float u_radius;\nuniform float u_focalDistance;\nuniform float u_focalAngle;\nuniform float u_falloff;\nuniform float u_mixing;\nuniform float u_distortion;\nuniform float u_distortionShift;\nuniform float u_distortionFreq;\nuniform float u_grainMixer;\nuniform float u_grainOverlay;\n\nin vec2 v_objectUV;\nout vec4 fragColor;\n\n${ declarePI }\n${ rotation2 }\n${ proceduralHash21 }\n\nfloat valueNoise(vec2 st) {\n vec2 i = floor(st);\n vec2 f = fract(st);\n float a = hash21(i);\n float b = hash21(i + vec2(1.0, 0.0));\n float c = hash21(i + vec2(0.0, 1.0));\n float d = hash21(i + vec2(1.0, 1.0));\n vec2 u = f * f * (3.0 - 2.0 * f);\n float x1 = mix(a, b, u.x);\n float x2 = mix(c, d, u.x);\n return mix(x1, x2, u.y);\n}\n\nfloat noise(vec2 n, vec2 seedOffset) {\n return valueNoise(n + seedOffset);\n}\n\nvec2 getPosition(int i, float t) {\n float a = float(i) * .37;\n float b = .6 + mod(float(i), 3.) * .3;\n float c = .8 + mod(float(i + 1), 4.) * 0.25;\n\n float x = sin(t * b + a);\n float y = cos(t * c + a * 1.5);\n\n return .5 + .5 * vec2(x, y);\n}\n\nvoid main() {\n vec2 uv = 2. * v_objectUV;\n vec2 grainUV = uv * 1000.;\n\n vec2 center = vec2(0.);\n float angleRad = -radians(u_focalAngle + 90.);\n vec2 focalPoint = vec2(cos(angleRad), sin(angleRad)) * u_focalDistance;\n float radius = u_radius;\n\n vec2 c_to_uv = uv - center;\n vec2 f_to_uv = uv - focalPoint;\n vec2 f_to_c = center - focalPoint;\n float r = length(c_to_uv);\n\n float fragAngle = atan(c_to_uv.y, c_to_uv.x);\n float angleDiff = fract((fragAngle - angleRad + PI) / TWO_PI) * TWO_PI - PI;\n\n float halfAngle = acos(clamp(radius / max(u_focalDistance, 1e-4), 0.0, 1.0));\n float e0 = 0.6 * PI, e1 = halfAngle;\n float lo = min(e0, e1), hi = max(e0, e1);\n float s = smoothstep(lo, hi, abs(angleDiff));\n float isInSector = (e1 >= e0) ? (1.0 - s) : s;\n\n float a = dot(f_to_uv, f_to_uv);\n float b = -2.0 * dot(f_to_uv, f_to_c);\n float c = dot(f_to_c, f_to_c) - radius * radius;\n\n float discriminant = b * b - 4.0 * a * c;\n float t = 1.0;\n\n if (discriminant >= 0.0) {\n float sqrtD = sqrt(discriminant);\n float div = max(1e-4, 2.0 * a);\n float t0 = (-b - sqrtD) / div;\n float t1 = (-b + sqrtD) / div;\n t = max(t0, t1);\n if (t < 0.0) t = 0.0;\n }\n\n float dist = length(f_to_uv);\n float normalized = dist / max(1e-4, length(f_to_uv * t));\n float shape = clamp(normalized, 0.0, 1.0);\n\n float falloffMapped = mix(.2 + .8 * max(0., u_falloff + 1.), mix(1., 15., u_falloff * u_falloff), step(.0, u_falloff));\n\n float falloffExp = mix(falloffMapped, 1., shape);\n shape = pow(shape, falloffExp);\n shape = 1. - clamp(shape, 0., 1.);\n\n\n float outerMask = .002;\n float outer = 1.0 - smoothstep(radius - outerMask, radius + outerMask, r);\n outer = mix(outer, 1., isInSector);\n\n shape = mix(0., shape, outer);\n shape *= 1. - smoothstep(radius - .01, radius, r);\n\n float angle = atan(f_to_uv.y, f_to_uv.x);\n shape -= pow(u_distortion, 2.) * shape * pow(abs(sin(PI * clamp(length(f_to_uv) - 0.2 + u_distortionShift, 0.0, 1.0))), 4.0) * (sin(u_distortionFreq * angle) + cos(floor(0.65 * u_distortionFreq) * angle));\n\n float grain = noise(grainUV, vec2(0.));\n float mixerGrain = .4 * u_grainMixer * (grain - .5);\n\n float mixer = shape * u_colorsCount + mixerGrain;\n vec4 gradient = u_colors[0];\n gradient.rgb *= gradient.a;\n\n float outerShape = 0.;\n for (int i = 1; i < ${ staticRadialGradientMeta.maxColorCount + 1 }; i++) {\n if (i > int(u_colorsCount)) break;\n float mLinear = clamp(mixer - float(i - 1), 0.0, 1.0);\n\n float aa = fwidth(mLinear);\n float width = min(u_mixing, 0.5);\n float t = clamp((mLinear - (0.5 - width - aa)) / (2. * width + 2. * aa), 0., 1.);\n float p = mix(2., 1., clamp((u_mixing - 0.5) * 2., 0., 1.));\n float m = t < 0.5\n ? 0.5 * pow(2. * t, p)\n : 1. - 0.5 * pow(2. * (1. - t), p);\n\n float quadBlend = clamp((u_mixing - 0.5) * 2., 0., 1.);\n m = mix(m, m * m, 0.5 * quadBlend);\n \n if (i == 1) {\n outerShape = m;\n }\n\n vec4 c = u_colors[i - 1];\n c.rgb *= c.a;\n gradient = mix(gradient, c, m);\n }\n\n vec3 color = gradient.rgb * outerShape;\n float opacity = gradient.a * outerShape;\n\n vec3 bgColor = u_colorBack.rgb * u_colorBack.a;\n color = color + bgColor * (1.0 - opacity);\n opacity = opacity + u_colorBack.a * (1.0 - opacity);\n\n float grainOverlay = valueNoise(rotate(grainUV, 1.) + vec2(3.));\n grainOverlay = mix(grainOverlay, valueNoise(rotate(grainUV, 2.) + vec2(-1.)), .5);\n grainOverlay = pow(grainOverlay, 1.3);\n\n float grainOverlayV = grainOverlay * 2. - 1.;\n vec3 grainOverlayColor = vec3(step(0., grainOverlayV));\n float grainOverlayStrength = u_grainOverlay * abs(grainOverlayV);\n grainOverlayStrength = pow(grainOverlayStrength, .8);\n color = mix(color, grainOverlayColor, .35 * grainOverlayStrength);\n\n opacity += .5 * grainOverlayStrength;\n opacity = clamp(opacity, 0., 1.);\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface StaticRadialGradientUniforms extends ShaderSizingUniforms {\n u_colorBack: [number, number, number, number];\n u_colors: vec4[];\n u_colorsCount: number;\n u_radius: number;\n u_focalDistance: number;\n u_focalAngle: number;\n u_falloff: number;\n u_mixing: number;\n u_distortion: number;\n u_distortionShift: number;\n u_distortionFreq: number;\n u_grainMixer: number;\n u_grainOverlay: number;\n}\n\nexport interface StaticRadialGradientParams extends ShaderSizingParams, ShaderMotionParams {\n colorBack?: string;\n colors?: string[];\n radius?: number;\n focalDistance?: number;\n focalAngle?: number;\n falloff?: number;\n mixing?: number;\n distortion?: number;\n distortionShift?: number;\n distortionFreq?: number;\n grainMixer?: number;\n grainOverlay?: number;\n}\n"], + "mappings": ";;;;;AAEA;AAAA,OAGO;AACP,SAAS,WAAW,WAAW,wBAAwB;AAEhD,MAAM,2BAA2B;AAAA,EACtC,eAAe;AACjB;AAwCO,MAAM,qCAA6C;AAAA;AAAA;AAAA;AAAA,wBAIjC,yBAAyB,aAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiB7D,SAAU;AAAA,EACV,SAAU;AAAA,EACV,gBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAkGK,yBAAyB,gBAAgB,CAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;", + "names": [] +} diff --git a/public/vendor/paper-shaders/shaders/swirl.d.ts b/public/vendor/paper-shaders/shaders/swirl.d.ts new file mode 100644 index 0000000..9d8845f --- /dev/null +++ b/public/vendor/paper-shaders/shaders/swirl.d.ts @@ -0,0 +1,63 @@ +import type { vec4 } from '../types.js'; +import type { ShaderMotionParams } from '../shader-mount.js'; +import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js'; +export declare const swirlMeta: { + readonly maxColorCount: 10; +}; +/** + * Animated bands of color twisting and bending, producing spirals, arcs, and flowing circular patterns. + * + * Fragment shader uniforms: + * - u_time (float): Animation time + * - u_colorBack (vec4): Background color in RGBA + * - u_colors (vec4[]): Up to 10 stripe colors in RGBA + * - u_colorsCount (float): Number of active colors + * - u_bandCount (float): Number of color bands, 0 = concentric ripples (0 to 15) + * - u_twist (float): Vortex power, 0 = straight sectoral shapes (0 to 1) + * - u_center (float): How far from the center the swirl colors begin to appear (0 to 1) + * - u_proportion (float): Blend point between colors, 0.5 = equal distribution (0 to 1) + * - u_softness (float): Color transition sharpness, 0 = hard edge, 1 = smooth gradient (0 to 1) + * - u_noise (float): Strength of noise distortion, no effect with noiseFrequency = 0 (0 to 1) + * - u_noiseFrequency (float): Noise frequency, no effect with noise = 0 (0 to 1) + * + * Vertex shader outputs (used in fragment shader): + * - v_objectUV (vec2): Object box UV coordinates with global sizing (scale, rotation, offsets, etc) applied + * + * Vertex shader uniforms: + * - u_resolution (vec2): Canvas resolution in pixels + * - u_pixelRatio (float): Device pixel ratio + * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1) + * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1) + * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas + * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas + * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover) + * - u_scale (float): Overall zoom level of the graphics (0.01 to 4) + * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360) + * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1) + * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1) + * + */ +export declare const swirlFragmentShader: string; +export interface SwirlUniforms extends ShaderSizingUniforms { + u_colorBack: [number, number, number, number]; + u_colors: vec4[]; + u_colorsCount: number; + u_bandCount: number; + u_twist: number; + u_center: number; + u_proportion: number; + u_softness: number; + u_noiseFrequency: number; + u_noise: number; +} +export interface SwirlParams extends ShaderSizingParams, ShaderMotionParams { + colorBack?: string; + colors?: string[]; + bandCount?: number; + twist?: number; + center?: number; + proportion?: number; + softness?: number; + noiseFrequency?: number; + noise?: number; +} diff --git a/public/vendor/paper-shaders/shaders/swirl.js b/public/vendor/paper-shaders/shaders/swirl.js new file mode 100644 index 0000000..ed7d21e --- /dev/null +++ b/public/vendor/paper-shaders/shaders/swirl.js @@ -0,0 +1,102 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Paper Shaders * + * https://github.com/paper-design/shaders * + * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +import {} from "../shader-sizing.js"; +import { simplexNoise, declarePI, rotation2, colorBandingFix } from "../shader-utils.js"; +const swirlMeta = { + maxColorCount: 10 +}; +const swirlFragmentShader = `#version 300 es +precision mediump float; + +uniform float u_time; + +uniform vec4 u_colorBack; +uniform vec4 u_colors[${swirlMeta.maxColorCount}]; +uniform float u_colorsCount; +uniform float u_bandCount; +uniform float u_twist; +uniform float u_center; +uniform float u_proportion; +uniform float u_softness; +uniform float u_noise; +uniform float u_noiseFrequency; + +in vec2 v_objectUV; + +out vec4 fragColor; + +${declarePI} +${simplexNoise} +${rotation2} + +void main() { + vec2 shape_uv = v_objectUV; + + float l = length(shape_uv); + l = max(1e-4, l); + + float t = u_time; + + float angle = ceil(u_bandCount) * atan(shape_uv.y, shape_uv.x) + t; + float angle_norm = angle / TWO_PI; + + float twist = 3. * clamp(u_twist, 0., 1.); + float offset = pow(l, -twist) + angle_norm; + + float shape = fract(offset); + shape = 1. - abs(2. * shape - 1.); + shape += u_noise * snoise(15. * pow(u_noiseFrequency, 2.) * shape_uv); + + float mid = smoothstep(.2, .2 + .8 * u_center, pow(l, twist)); + shape = mix(0., shape, mid); + + float proportion = clamp(u_proportion, 0., 1.); + float exponent = mix(.25, 1., proportion * 2.); + exponent = mix(exponent, 10., max(0., proportion * 2. - 1.)); + shape = pow(shape, exponent); + + float mixer = shape * u_colorsCount; + vec4 gradient = u_colors[0]; + gradient.rgb *= gradient.a; + + float outerShape = 0.; + for (int i = 1; i < ${swirlMeta.maxColorCount + 1}; i++) { + if (i > int(u_colorsCount)) break; + + float m = clamp(mixer - float(i - 1), 0., 1.); + float aa = fwidth(m); + m = smoothstep(.5 - .5 * u_softness - aa, .5 + .5 * u_softness + aa, m); + + if (i == 1) { + outerShape = m; + } + + vec4 c = u_colors[i - 1]; + c.rgb *= c.a; + gradient = mix(gradient, c, m); + } + + float midAA = .1 * fwidth(pow(l, -twist)); + float outerMid = smoothstep(.2, .2 + midAA, pow(l, twist)); + outerShape = mix(0., outerShape, outerMid); + + vec3 color = gradient.rgb * outerShape; + float opacity = gradient.a * outerShape; + + vec3 bgColor = u_colorBack.rgb * u_colorBack.a; + color = color + bgColor * (1.0 - opacity); + opacity = opacity + u_colorBack.a * (1.0 - opacity); + + ${colorBandingFix} + + fragColor = vec4(color, opacity); +} +`; +export { + swirlFragmentShader, + swirlMeta +}; +//# sourceMappingURL=swirl.js.map diff --git a/public/vendor/paper-shaders/shaders/swirl.js.map b/public/vendor/paper-shaders/shaders/swirl.js.map new file mode 100644 index 0000000..7a8b2fa --- /dev/null +++ b/public/vendor/paper-shaders/shaders/swirl.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../../src/shaders/swirl.ts"], + "sourcesContent": ["import type { vec4 } from '../types.js';\nimport type { ShaderMotionParams } from '../shader-mount.js';\nimport { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { simplexNoise, declarePI, rotation2, colorBandingFix } from '../shader-utils.js';\n\nexport const swirlMeta = {\n maxColorCount: 10,\n} as const;\n\n/**\n * Animated bands of color twisting and bending, producing spirals, arcs, and flowing circular patterns.\n *\n * Fragment shader uniforms:\n * - u_time (float): Animation time\n * - u_colorBack (vec4): Background color in RGBA\n * - u_colors (vec4[]): Up to 10 stripe colors in RGBA\n * - u_colorsCount (float): Number of active colors\n * - u_bandCount (float): Number of color bands, 0 = concentric ripples (0 to 15)\n * - u_twist (float): Vortex power, 0 = straight sectoral shapes (0 to 1)\n * - u_center (float): How far from the center the swirl colors begin to appear (0 to 1)\n * - u_proportion (float): Blend point between colors, 0.5 = equal distribution (0 to 1)\n * - u_softness (float): Color transition sharpness, 0 = hard edge, 1 = smooth gradient (0 to 1)\n * - u_noise (float): Strength of noise distortion, no effect with noiseFrequency = 0 (0 to 1)\n * - u_noiseFrequency (float): Noise frequency, no effect with noise = 0 (0 to 1)\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_objectUV (vec2): Object box UV coordinates with global sizing (scale, rotation, offsets, etc) applied\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n *\n */\n\n// language=GLSL\nexport const swirlFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform float u_time;\n\nuniform vec4 u_colorBack;\nuniform vec4 u_colors[${ swirlMeta.maxColorCount }];\nuniform float u_colorsCount;\nuniform float u_bandCount;\nuniform float u_twist;\nuniform float u_center;\nuniform float u_proportion;\nuniform float u_softness;\nuniform float u_noise;\nuniform float u_noiseFrequency;\n\nin vec2 v_objectUV;\n\nout vec4 fragColor;\n\n${ declarePI }\n${ simplexNoise }\n${ rotation2 }\n\nvoid main() {\n vec2 shape_uv = v_objectUV;\n\n float l = length(shape_uv);\n l = max(1e-4, l);\n\n float t = u_time;\n\n float angle = ceil(u_bandCount) * atan(shape_uv.y, shape_uv.x) + t;\n float angle_norm = angle / TWO_PI;\n\n float twist = 3. * clamp(u_twist, 0., 1.);\n float offset = pow(l, -twist) + angle_norm;\n\n float shape = fract(offset);\n shape = 1. - abs(2. * shape - 1.);\n shape += u_noise * snoise(15. * pow(u_noiseFrequency, 2.) * shape_uv);\n\n float mid = smoothstep(.2, .2 + .8 * u_center, pow(l, twist));\n shape = mix(0., shape, mid);\n\n float proportion = clamp(u_proportion, 0., 1.);\n float exponent = mix(.25, 1., proportion * 2.);\n exponent = mix(exponent, 10., max(0., proportion * 2. - 1.));\n shape = pow(shape, exponent);\n\n float mixer = shape * u_colorsCount;\n vec4 gradient = u_colors[0];\n gradient.rgb *= gradient.a;\n\n float outerShape = 0.;\n for (int i = 1; i < ${ swirlMeta.maxColorCount + 1 }; i++) {\n if (i > int(u_colorsCount)) break;\n\n float m = clamp(mixer - float(i - 1), 0., 1.);\n float aa = fwidth(m);\n m = smoothstep(.5 - .5 * u_softness - aa, .5 + .5 * u_softness + aa, m);\n\n if (i == 1) {\n outerShape = m;\n }\n\n vec4 c = u_colors[i - 1];\n c.rgb *= c.a;\n gradient = mix(gradient, c, m);\n }\n\n float midAA = .1 * fwidth(pow(l, -twist));\n float outerMid = smoothstep(.2, .2 + midAA, pow(l, twist));\n outerShape = mix(0., outerShape, outerMid);\n\n vec3 color = gradient.rgb * outerShape;\n float opacity = gradient.a * outerShape;\n\n vec3 bgColor = u_colorBack.rgb * u_colorBack.a;\n color = color + bgColor * (1.0 - opacity);\n opacity = opacity + u_colorBack.a * (1.0 - opacity);\n\n ${ colorBandingFix }\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface SwirlUniforms extends ShaderSizingUniforms {\n u_colorBack: [number, number, number, number];\n u_colors: vec4[];\n u_colorsCount: number;\n u_bandCount: number;\n u_twist: number;\n u_center: number;\n u_proportion: number;\n u_softness: number;\n u_noiseFrequency: number;\n u_noise: number;\n}\n\nexport interface SwirlParams extends ShaderSizingParams, ShaderMotionParams {\n colorBack?: string;\n colors?: string[];\n bandCount?: number;\n twist?: number;\n center?: number;\n proportion?: number;\n softness?: number;\n noiseFrequency?: number;\n noise?: number;\n}\n"], + "mappings": ";;;;;AAEA,eAAmE;AACnE,SAAS,cAAc,WAAW,WAAW,uBAAuB;AAE7D,MAAM,YAAY;AAAA,EACvB,eAAe;AACjB;AAqCO,MAAM,sBAA8B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAMlB,UAAU,aAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAc9C,SAAU;AAAA,EACV,YAAa;AAAA,EACb,SAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAiCY,UAAU,gBAAgB,CAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA2BhD,eAAgB;AAAA;AAAA;AAAA;AAAA;", + "names": [] +} diff --git a/public/vendor/paper-shaders/shaders/voronoi.d.ts b/public/vendor/paper-shaders/shaders/voronoi.d.ts new file mode 100644 index 0000000..8d6bc6e --- /dev/null +++ b/public/vendor/paper-shaders/shaders/voronoi.d.ts @@ -0,0 +1,65 @@ +import type { vec4 } from '../types.js'; +import type { ShaderMotionParams } from '../shader-mount.js'; +import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js'; +export declare const voronoiMeta: { + readonly maxColorCount: 5; +}; +/** + * Anti-aliased animated Voronoi pattern with smooth and customizable edges. + * + * Double-pass Voronoi pattern cell edges. + * Original algorithm: https://www.shadertoy.com/view/ldl3W8 + * + * Note: gaps can't be removed completely due to natural artifacts of Voronoi cells borders + * + * Fragment shader uniforms: + * - u_time (float): Animation time + * - u_scale (float): Overall zoom level, used for anti-aliasing calculations + * - u_colors (vec4[]): Up to 5 base cell colors in RGBA + * - u_colorsCount (float): Number of active colors + * - u_stepsPerColor (float): Number of extra colors between base colors, 1 = N colors, 2 = 2×N, etc. (1 to 3) + * - u_colorGlow (vec4): Color tint for radial inner shadow inside cells in RGBA, effective with glow > 0 + * - u_colorGap (vec4): Color used for cell borders/gaps in RGBA + * - u_distortion (float): Strength of noise-driven displacement of cell centers (0 to 0.5) + * - u_gap (float): Width of the border/gap between cells (0 to 0.1) + * - u_glow (float): Strength of the radial inner shadow inside cells (0 to 1) + * - u_noiseTexture (sampler2D): Pre-computed randomizer source texture + * + * Vertex shader outputs (used in fragment shader): + * - v_patternUV (vec2): UV coordinates for pattern with global sizing (rotation, scale, offset, etc) applied + * + * Vertex shader uniforms: + * - u_resolution (vec2): Canvas resolution in pixels + * - u_pixelRatio (float): Device pixel ratio + * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1) + * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1) + * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas + * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas + * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover) + * - u_scale (float): Overall zoom level of the graphics (0.01 to 4) + * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360) + * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1) + * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1) + * + */ +export declare const voronoiFragmentShader: string; +export interface VoronoiUniforms extends ShaderSizingUniforms { + u_colors: vec4[]; + u_colorsCount: number; + u_stepsPerColor: number; + u_colorGap: [number, number, number, number]; + u_colorGlow: [number, number, number, number]; + u_distortion: number; + u_gap: number; + u_glow: number; + u_noiseTexture?: HTMLImageElement; +} +export interface VoronoiParams extends ShaderSizingParams, ShaderMotionParams { + colors?: string[]; + stepsPerColor?: number; + colorGap?: string; + colorGlow?: string; + distortion?: number; + gap?: number; + glow?: number; +} diff --git a/public/vendor/paper-shaders/shaders/voronoi.js b/public/vendor/paper-shaders/shaders/voronoi.js new file mode 100644 index 0000000..82dcc9d --- /dev/null +++ b/public/vendor/paper-shaders/shaders/voronoi.js @@ -0,0 +1,139 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Paper Shaders * + * https://github.com/paper-design/shaders * + * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +import {} from "../shader-sizing.js"; +import { declarePI, textureRandomizerGB } from "../shader-utils.js"; +const voronoiMeta = { + maxColorCount: 5 +}; +const voronoiFragmentShader = `#version 300 es +precision mediump float; + +uniform float u_time; + +uniform float u_scale; + +uniform sampler2D u_noiseTexture; + +uniform vec4 u_colors[${voronoiMeta.maxColorCount}]; +uniform float u_colorsCount; + +uniform float u_stepsPerColor; +uniform vec4 u_colorGlow; +uniform vec4 u_colorGap; +uniform float u_distortion; +uniform float u_gap; +uniform float u_glow; + +in vec2 v_patternUV; + +out vec4 fragColor; + +${declarePI} +${textureRandomizerGB} + +vec4 voronoi(vec2 x, float t) { + vec2 ip = floor(x); + vec2 fp = fract(x); + + vec2 mg, mr; + float md = 8.; + float rand = 0.; + + for (int j = -1; j <= 1; j++) { + for (int i = -1; i <= 1; i++) { + vec2 g = vec2(float(i), float(j)); + vec2 o = randomGB(ip + g); + float raw_hash = o.x; + o = .5 + u_distortion * sin(t + TWO_PI * o); + vec2 r = g + o - fp; + float d = dot(r, r); + + if (d < md) { + md = d; + mr = r; + mg = g; + rand = raw_hash; + } + } + } + + md = 8.; + for (int j = -2; j <= 2; j++) { + for (int i = -2; i <= 2; i++) { + vec2 g = mg + vec2(float(i), float(j)); + vec2 o = randomGB(ip + g); + o = .5 + u_distortion * sin(t + TWO_PI * o); + vec2 r = g + o - fp; + if (dot(mr - r, mr - r) > .00001) { + md = min(md, dot(.5 * (mr + r), normalize(r - mr))); + } + } + } + + return vec4(md, mr, rand); +} + +void main() { + vec2 shape_uv = v_patternUV; + shape_uv *= 1.25; + + float t = u_time; + + vec4 voronoiRes = voronoi(shape_uv, t); + + float shape = clamp(voronoiRes.w, 0., 1.); + float mixer = shape * (u_colorsCount - 1.); + mixer = (shape - .5 / u_colorsCount) * u_colorsCount; + float steps = max(1., u_stepsPerColor); + + vec4 gradient = u_colors[0]; + gradient.rgb *= gradient.a; + for (int i = 1; i < ${voronoiMeta.maxColorCount}; i++) { + if (i >= int(u_colorsCount)) break; + float localT = clamp(mixer - float(i - 1), 0.0, 1.0); + localT = round(localT * steps) / steps; + vec4 c = u_colors[i]; + c.rgb *= c.a; + gradient = mix(gradient, c, localT); + } + + if ((mixer < 0.) || (mixer > (u_colorsCount - 1.))) { + float localT = mixer + 1.; + if (mixer > (u_colorsCount - 1.)) { + localT = mixer - (u_colorsCount - 1.); + } + localT = round(localT * steps) / steps; + vec4 cFst = u_colors[0]; + cFst.rgb *= cFst.a; + vec4 cLast = u_colors[int(u_colorsCount - 1.)]; + cLast.rgb *= cLast.a; + gradient = mix(cLast, cFst, localT); + } + + vec3 cellColor = gradient.rgb; + float cellOpacity = gradient.a; + + float glows = length(voronoiRes.yz * u_glow); + glows = pow(glows, 1.5); + + vec3 color = mix(cellColor, u_colorGlow.rgb * u_colorGlow.a, u_colorGlow.a * glows); + float opacity = cellOpacity + u_colorGlow.a * glows; + + float edge = voronoiRes.x; + float smoothEdge = .02 / (2. * u_scale) * (1. + .5 * u_gap); + edge = smoothstep(u_gap - smoothEdge, u_gap + smoothEdge, edge); + + color = mix(u_colorGap.rgb * u_colorGap.a, color, edge); + opacity = mix(u_colorGap.a, opacity, edge); + + fragColor = vec4(color, opacity); +} +`; +export { + voronoiFragmentShader, + voronoiMeta +}; +//# sourceMappingURL=voronoi.js.map diff --git a/public/vendor/paper-shaders/shaders/voronoi.js.map b/public/vendor/paper-shaders/shaders/voronoi.js.map new file mode 100644 index 0000000..8f90cb7 --- /dev/null +++ b/public/vendor/paper-shaders/shaders/voronoi.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../../src/shaders/voronoi.ts"], + "sourcesContent": ["import type { vec4 } from '../types.js';\nimport type { ShaderMotionParams } from '../shader-mount.js';\nimport { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { declarePI, textureRandomizerGB } from '../shader-utils.js';\n\nexport const voronoiMeta = {\n maxColorCount: 5,\n} as const;\n\n/**\n * Anti-aliased animated Voronoi pattern with smooth and customizable edges.\n *\n * Double-pass Voronoi pattern cell edges.\n * Original algorithm: https://www.shadertoy.com/view/ldl3W8\n *\n * Note: gaps can't be removed completely due to natural artifacts of Voronoi cells borders\n *\n * Fragment shader uniforms:\n * - u_time (float): Animation time\n * - u_scale (float): Overall zoom level, used for anti-aliasing calculations\n * - u_colors (vec4[]): Up to 5 base cell colors in RGBA\n * - u_colorsCount (float): Number of active colors\n * - u_stepsPerColor (float): Number of extra colors between base colors, 1 = N colors, 2 = 2\u00D7N, etc. (1 to 3)\n * - u_colorGlow (vec4): Color tint for radial inner shadow inside cells in RGBA, effective with glow > 0\n * - u_colorGap (vec4): Color used for cell borders/gaps in RGBA\n * - u_distortion (float): Strength of noise-driven displacement of cell centers (0 to 0.5)\n * - u_gap (float): Width of the border/gap between cells (0 to 0.1)\n * - u_glow (float): Strength of the radial inner shadow inside cells (0 to 1)\n * - u_noiseTexture (sampler2D): Pre-computed randomizer source texture\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_patternUV (vec2): UV coordinates for pattern with global sizing (rotation, scale, offset, etc) applied\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n *\n */\n\n// language=GLSL\nexport const voronoiFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform float u_time;\n\nuniform float u_scale;\n\nuniform sampler2D u_noiseTexture;\n\nuniform vec4 u_colors[${ voronoiMeta.maxColorCount }];\nuniform float u_colorsCount;\n\nuniform float u_stepsPerColor;\nuniform vec4 u_colorGlow;\nuniform vec4 u_colorGap;\nuniform float u_distortion;\nuniform float u_gap;\nuniform float u_glow;\n\nin vec2 v_patternUV;\n\nout vec4 fragColor;\n\n${ declarePI }\n${ textureRandomizerGB }\n\nvec4 voronoi(vec2 x, float t) {\n vec2 ip = floor(x);\n vec2 fp = fract(x);\n\n vec2 mg, mr;\n float md = 8.;\n float rand = 0.;\n\n for (int j = -1; j <= 1; j++) {\n for (int i = -1; i <= 1; i++) {\n vec2 g = vec2(float(i), float(j));\n vec2 o = randomGB(ip + g);\n float raw_hash = o.x;\n o = .5 + u_distortion * sin(t + TWO_PI * o);\n vec2 r = g + o - fp;\n float d = dot(r, r);\n\n if (d < md) {\n md = d;\n mr = r;\n mg = g;\n rand = raw_hash;\n }\n }\n }\n\n md = 8.;\n for (int j = -2; j <= 2; j++) {\n for (int i = -2; i <= 2; i++) {\n vec2 g = mg + vec2(float(i), float(j));\n vec2 o = randomGB(ip + g);\n o = .5 + u_distortion * sin(t + TWO_PI * o);\n vec2 r = g + o - fp;\n if (dot(mr - r, mr - r) > .00001) {\n md = min(md, dot(.5 * (mr + r), normalize(r - mr)));\n }\n }\n }\n\n return vec4(md, mr, rand);\n}\n\nvoid main() {\n vec2 shape_uv = v_patternUV;\n shape_uv *= 1.25;\n\n float t = u_time;\n\n vec4 voronoiRes = voronoi(shape_uv, t);\n\n float shape = clamp(voronoiRes.w, 0., 1.);\n float mixer = shape * (u_colorsCount - 1.);\n mixer = (shape - .5 / u_colorsCount) * u_colorsCount;\n float steps = max(1., u_stepsPerColor);\n\n vec4 gradient = u_colors[0];\n gradient.rgb *= gradient.a;\n for (int i = 1; i < ${ voronoiMeta.maxColorCount }; i++) {\n if (i >= int(u_colorsCount)) break;\n float localT = clamp(mixer - float(i - 1), 0.0, 1.0);\n localT = round(localT * steps) / steps;\n vec4 c = u_colors[i];\n c.rgb *= c.a;\n gradient = mix(gradient, c, localT);\n }\n\n if ((mixer < 0.) || (mixer > (u_colorsCount - 1.))) {\n float localT = mixer + 1.;\n if (mixer > (u_colorsCount - 1.)) {\n localT = mixer - (u_colorsCount - 1.);\n }\n localT = round(localT * steps) / steps;\n vec4 cFst = u_colors[0];\n cFst.rgb *= cFst.a;\n vec4 cLast = u_colors[int(u_colorsCount - 1.)];\n cLast.rgb *= cLast.a;\n gradient = mix(cLast, cFst, localT);\n }\n\n vec3 cellColor = gradient.rgb;\n float cellOpacity = gradient.a;\n\n float glows = length(voronoiRes.yz * u_glow);\n glows = pow(glows, 1.5);\n\n vec3 color = mix(cellColor, u_colorGlow.rgb * u_colorGlow.a, u_colorGlow.a * glows);\n float opacity = cellOpacity + u_colorGlow.a * glows;\n\n float edge = voronoiRes.x;\n float smoothEdge = .02 / (2. * u_scale) * (1. + .5 * u_gap);\n edge = smoothstep(u_gap - smoothEdge, u_gap + smoothEdge, edge);\n\n color = mix(u_colorGap.rgb * u_colorGap.a, color, edge);\n opacity = mix(u_colorGap.a, opacity, edge);\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface VoronoiUniforms extends ShaderSizingUniforms {\n u_colors: vec4[];\n u_colorsCount: number;\n u_stepsPerColor: number;\n u_colorGap: [number, number, number, number];\n u_colorGlow: [number, number, number, number];\n u_distortion: number;\n u_gap: number;\n u_glow: number;\n u_noiseTexture?: HTMLImageElement;\n}\n\nexport interface VoronoiParams extends ShaderSizingParams, ShaderMotionParams {\n colors?: string[];\n stepsPerColor?: number;\n colorGap?: string;\n colorGlow?: string;\n distortion?: number;\n gap?: number;\n glow?: number;\n}\n"], + "mappings": ";;;;;AAEA,eAAmE;AACnE,SAAS,WAAW,2BAA2B;AAExC,MAAM,cAAc;AAAA,EACzB,eAAe;AACjB;AA0CO,MAAM,wBAAgC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBASpB,YAAY,aAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAchD,SAAU;AAAA,EACV,mBAAoB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBA2DE,YAAY,aAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;", + "names": [] +} diff --git a/public/vendor/paper-shaders/shaders/warp.d.ts b/public/vendor/paper-shaders/shaders/warp.d.ts new file mode 100644 index 0000000..e70d457 --- /dev/null +++ b/public/vendor/paper-shaders/shaders/warp.d.ts @@ -0,0 +1,72 @@ +import type { vec4 } from '../types.js'; +import type { ShaderMotionParams } from '../shader-mount.js'; +import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js'; +export declare const warpMeta: { + readonly maxColorCount: 10; +}; +/** + * Animated color fields warped by noise and swirls, applied over base patterns + * (checks, stripes, or split edge). Blends up to 10 colors with adjustable distribution, + * softness, distortion, and swirl. Great for fluid, smoky, or marbled effects. + * + * Fragment shader uniforms: + * - u_time (float): Animation time + * - u_scale (float): Overall zoom level, used for anti-aliasing calculations + * - u_colors (vec4[]): Up to 10 gradient colors in RGBA + * - u_colorsCount (float): Number of active colors + * - u_proportion (float): Blend point between colors, 0.5 = equal distribution (0 to 1) + * - u_softness (float): Color transition sharpness, 0 = hard edge, 1 = smooth gradient (0 to 1) + * - u_shape (float): Base pattern type (0 = checks, 1 = stripes, 2 = edge) + * - u_shapeScale (float): Zoom level of the base pattern (0 to 1) + * - u_distortion (float): Strength of noise-based distortion (0 to 1) + * - u_swirl (float): Strength of the swirl distortion (0 to 1) + * - u_swirlIterations (float): Number of layered swirl passes, effective with swirl > 0 (0 to 20) + * - u_noiseTexture (sampler2D): Pre-computed randomizer source texture + * + * Vertex shader outputs (used in fragment shader): + * - v_patternUV (vec2): UV coordinates for pattern with global sizing (rotation, scale, offset, etc) applied + * + * Vertex shader uniforms: + * - u_resolution (vec2): Canvas resolution in pixels + * - u_pixelRatio (float): Device pixel ratio + * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1) + * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1) + * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas + * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas + * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover) + * - u_scale (float): Overall zoom level of the graphics (0.01 to 4) + * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360) + * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1) + * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1) + * + */ +export declare const warpFragmentShader: string; +export interface WarpUniforms extends ShaderSizingUniforms { + u_colors: vec4[]; + u_colorsCount: number; + u_proportion: number; + u_softness: number; + u_shape: (typeof WarpPatterns)[WarpPattern]; + u_shapeScale: number; + u_distortion: number; + u_swirl: number; + u_swirlIterations: number; + u_noiseTexture?: HTMLImageElement; +} +export interface WarpParams extends ShaderSizingParams, ShaderMotionParams { + colors?: string[]; + rotation?: number; + proportion?: number; + softness?: number; + shape?: WarpPattern; + shapeScale?: number; + distortion?: number; + swirl?: number; + swirlIterations?: number; +} +export declare const WarpPatterns: { + readonly checks: 0; + readonly stripes: 1; + readonly edge: 2; +}; +export type WarpPattern = keyof typeof WarpPatterns; diff --git a/public/vendor/paper-shaders/shaders/warp.js b/public/vendor/paper-shaders/shaders/warp.js new file mode 100644 index 0000000..2da4d50 --- /dev/null +++ b/public/vendor/paper-shaders/shaders/warp.js @@ -0,0 +1,132 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Paper Shaders * + * https://github.com/paper-design/shaders * + * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +import {} from "../shader-sizing.js"; +import { declarePI, rotation2, colorBandingFix } from "../shader-utils.js"; +const warpMeta = { + maxColorCount: 10 +}; +const warpFragmentShader = `#version 300 es +precision mediump float; + +uniform float u_time; +uniform float u_scale; + +uniform sampler2D u_noiseTexture; + +uniform vec4 u_colors[${warpMeta.maxColorCount}]; +uniform float u_colorsCount; +uniform float u_proportion; +uniform float u_softness; +uniform float u_shape; +uniform float u_shapeScale; +uniform float u_distortion; +uniform float u_swirl; +uniform float u_swirlIterations; + +in vec2 v_patternUV; + +out vec4 fragColor; + +${declarePI} +${rotation2} +float randomG(vec2 p) { + vec2 uv = floor(p) / 100. + .5; + return texture(u_noiseTexture, fract(uv)).g; +} +float valueNoise(vec2 st) { + vec2 i = floor(st); + vec2 f = fract(st); + float a = randomG(i); + float b = randomG(i + vec2(1.0, 0.0)); + float c = randomG(i + vec2(0.0, 1.0)); + float d = randomG(i + vec2(1.0, 1.0)); + vec2 u = f * f * (3.0 - 2.0 * f); + float x1 = mix(a, b, u.x); + float x2 = mix(c, d, u.x); + return mix(x1, x2, u.y); +} + + +void main() { + vec2 uv = v_patternUV; + uv *= .5; + + const float firstFrameOffset = 118.; + float t = 0.0625 * (u_time + firstFrameOffset); + + float n1 = valueNoise(uv * 1. + t); + float n2 = valueNoise(uv * 2. - t); + float angle = n1 * TWO_PI; + uv.x += 4. * u_distortion * n2 * cos(angle); + uv.y += 4. * u_distortion * n2 * sin(angle); + + float swirl = u_swirl; + for (int i = 1; i <= 20; i++) { + if (i >= int(u_swirlIterations)) break; + float iFloat = float(i); + // swirl *= (1. - smoothstep(.0, .25, length(fwidth(uv)))); + uv.x += swirl / iFloat * cos(t + iFloat * 1.5 * uv.y); + uv.y += swirl / iFloat * cos(t + iFloat * 1. * uv.x); + } + + float proportion = clamp(u_proportion, 0., 1.); + + float shape = 0.; + if (u_shape < .5) { + vec2 checksShape_uv = uv * (.5 + 3.5 * u_shapeScale); + shape = .5 + .5 * sin(checksShape_uv.x) * cos(checksShape_uv.y); + shape += .48 * sign(proportion - .5) * pow(abs(proportion - .5), .5); + } else if (u_shape < 1.5) { + vec2 stripesShape_uv = uv * (2. * u_shapeScale); + float f = fract(stripesShape_uv.y); + shape = smoothstep(.0, .55, f) * (1.0 - smoothstep(.45, 1., f)); + shape += .48 * sign(proportion - .5) * pow(abs(proportion - .5), .5); + } else { + float shapeScaling = 5. * (1. - u_shapeScale); + float e0 = 0.45 - shapeScaling; + float e1 = 0.55 + shapeScaling; + shape = smoothstep(min(e0, e1), max(e0, e1), 1.0 - uv.y + 0.3 * (proportion - 0.5)); + } + + float mixer = shape * (u_colorsCount - 1.); + vec4 gradient = u_colors[0]; + gradient.rgb *= gradient.a; + float aa = fwidth(shape); + for (int i = 1; i < ${warpMeta.maxColorCount}; i++) { + if (i >= int(u_colorsCount)) break; + float m = clamp(mixer - float(i - 1), 0.0, 1.0); + + float localMixerStart = floor(m); + float softness = .5 * u_softness + fwidth(m); + float smoothed = smoothstep(max(0., .5 - softness - aa), min(1., .5 + softness + aa), m - localMixerStart); + float stepped = localMixerStart + smoothed; + + m = mix(stepped, m, u_softness); + + vec4 c = u_colors[i]; + c.rgb *= c.a; + gradient = mix(gradient, c, m); + } + + vec3 color = gradient.rgb; + float opacity = gradient.a; + + ${colorBandingFix} + + fragColor = vec4(color, opacity); +} +`; +const WarpPatterns = { + checks: 0, + stripes: 1, + edge: 2 +}; +export { + WarpPatterns, + warpFragmentShader, + warpMeta +}; +//# sourceMappingURL=warp.js.map diff --git a/public/vendor/paper-shaders/shaders/warp.js.map b/public/vendor/paper-shaders/shaders/warp.js.map new file mode 100644 index 0000000..e2acd7a --- /dev/null +++ b/public/vendor/paper-shaders/shaders/warp.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../../src/shaders/warp.ts"], + "sourcesContent": ["import type { vec4 } from '../types.js';\nimport type { ShaderMotionParams } from '../shader-mount.js';\nimport { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { declarePI, rotation2, colorBandingFix } from '../shader-utils.js';\n\nexport const warpMeta = {\n maxColorCount: 10,\n} as const;\n\n/**\n * Animated color fields warped by noise and swirls, applied over base patterns\n * (checks, stripes, or split edge). Blends up to 10 colors with adjustable distribution,\n * softness, distortion, and swirl. Great for fluid, smoky, or marbled effects.\n *\n * Fragment shader uniforms:\n * - u_time (float): Animation time\n * - u_scale (float): Overall zoom level, used for anti-aliasing calculations\n * - u_colors (vec4[]): Up to 10 gradient colors in RGBA\n * - u_colorsCount (float): Number of active colors\n * - u_proportion (float): Blend point between colors, 0.5 = equal distribution (0 to 1)\n * - u_softness (float): Color transition sharpness, 0 = hard edge, 1 = smooth gradient (0 to 1)\n * - u_shape (float): Base pattern type (0 = checks, 1 = stripes, 2 = edge)\n * - u_shapeScale (float): Zoom level of the base pattern (0 to 1)\n * - u_distortion (float): Strength of noise-based distortion (0 to 1)\n * - u_swirl (float): Strength of the swirl distortion (0 to 1)\n * - u_swirlIterations (float): Number of layered swirl passes, effective with swirl > 0 (0 to 20)\n * - u_noiseTexture (sampler2D): Pre-computed randomizer source texture\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_patternUV (vec2): UV coordinates for pattern with global sizing (rotation, scale, offset, etc) applied\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n *\n */\n\n// language=GLSL\nexport const warpFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform float u_time;\nuniform float u_scale;\n\nuniform sampler2D u_noiseTexture;\n\nuniform vec4 u_colors[${ warpMeta.maxColorCount }];\nuniform float u_colorsCount;\nuniform float u_proportion;\nuniform float u_softness;\nuniform float u_shape;\nuniform float u_shapeScale;\nuniform float u_distortion;\nuniform float u_swirl;\nuniform float u_swirlIterations;\n\nin vec2 v_patternUV;\n\nout vec4 fragColor;\n\n${ declarePI }\n${ rotation2 }\nfloat randomG(vec2 p) {\n vec2 uv = floor(p) / 100. + .5;\n return texture(u_noiseTexture, fract(uv)).g;\n}\nfloat valueNoise(vec2 st) {\n vec2 i = floor(st);\n vec2 f = fract(st);\n float a = randomG(i);\n float b = randomG(i + vec2(1.0, 0.0));\n float c = randomG(i + vec2(0.0, 1.0));\n float d = randomG(i + vec2(1.0, 1.0));\n vec2 u = f * f * (3.0 - 2.0 * f);\n float x1 = mix(a, b, u.x);\n float x2 = mix(c, d, u.x);\n return mix(x1, x2, u.y);\n}\n\n\nvoid main() {\n vec2 uv = v_patternUV;\n uv *= .5;\n\n const float firstFrameOffset = 118.;\n float t = 0.0625 * (u_time + firstFrameOffset);\n\n float n1 = valueNoise(uv * 1. + t);\n float n2 = valueNoise(uv * 2. - t);\n float angle = n1 * TWO_PI;\n uv.x += 4. * u_distortion * n2 * cos(angle);\n uv.y += 4. * u_distortion * n2 * sin(angle);\n\n float swirl = u_swirl;\n for (int i = 1; i <= 20; i++) {\n if (i >= int(u_swirlIterations)) break;\n float iFloat = float(i);\n // swirl *= (1. - smoothstep(.0, .25, length(fwidth(uv))));\n uv.x += swirl / iFloat * cos(t + iFloat * 1.5 * uv.y);\n uv.y += swirl / iFloat * cos(t + iFloat * 1. * uv.x);\n }\n\n float proportion = clamp(u_proportion, 0., 1.);\n\n float shape = 0.;\n if (u_shape < .5) {\n vec2 checksShape_uv = uv * (.5 + 3.5 * u_shapeScale);\n shape = .5 + .5 * sin(checksShape_uv.x) * cos(checksShape_uv.y);\n shape += .48 * sign(proportion - .5) * pow(abs(proportion - .5), .5);\n } else if (u_shape < 1.5) {\n vec2 stripesShape_uv = uv * (2. * u_shapeScale);\n float f = fract(stripesShape_uv.y);\n shape = smoothstep(.0, .55, f) * (1.0 - smoothstep(.45, 1., f));\n shape += .48 * sign(proportion - .5) * pow(abs(proportion - .5), .5);\n } else {\n float shapeScaling = 5. * (1. - u_shapeScale);\n float e0 = 0.45 - shapeScaling;\n float e1 = 0.55 + shapeScaling;\n shape = smoothstep(min(e0, e1), max(e0, e1), 1.0 - uv.y + 0.3 * (proportion - 0.5));\n }\n\n float mixer = shape * (u_colorsCount - 1.);\n vec4 gradient = u_colors[0];\n gradient.rgb *= gradient.a;\n float aa = fwidth(shape);\n for (int i = 1; i < ${ warpMeta.maxColorCount }; i++) {\n if (i >= int(u_colorsCount)) break;\n float m = clamp(mixer - float(i - 1), 0.0, 1.0);\n\n float localMixerStart = floor(m);\n float softness = .5 * u_softness + fwidth(m);\n float smoothed = smoothstep(max(0., .5 - softness - aa), min(1., .5 + softness + aa), m - localMixerStart);\n float stepped = localMixerStart + smoothed;\n\n m = mix(stepped, m, u_softness);\n\n vec4 c = u_colors[i];\n c.rgb *= c.a;\n gradient = mix(gradient, c, m);\n }\n\n vec3 color = gradient.rgb;\n float opacity = gradient.a;\n\n ${ colorBandingFix }\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface WarpUniforms extends ShaderSizingUniforms {\n u_colors: vec4[];\n u_colorsCount: number;\n u_proportion: number;\n u_softness: number;\n u_shape: (typeof WarpPatterns)[WarpPattern];\n u_shapeScale: number;\n u_distortion: number;\n u_swirl: number;\n u_swirlIterations: number;\n u_noiseTexture?: HTMLImageElement;\n}\n\nexport interface WarpParams extends ShaderSizingParams, ShaderMotionParams {\n colors?: string[];\n rotation?: number;\n proportion?: number;\n softness?: number;\n shape?: WarpPattern;\n shapeScale?: number;\n distortion?: number;\n swirl?: number;\n swirlIterations?: number;\n}\n\nexport const WarpPatterns = {\n checks: 0,\n stripes: 1,\n edge: 2,\n} as const;\n\nexport type WarpPattern = keyof typeof WarpPatterns;\n"], + "mappings": ";;;;;AAEA,eAAmE;AACnE,SAAS,WAAW,WAAW,uBAAuB;AAE/C,MAAM,WAAW;AAAA,EACtB,eAAe;AACjB;AAwCO,MAAM,qBAA6B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAQjB,SAAS,aAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAc7C,SAAU;AAAA,EACV,SAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAgEY,SAAS,aAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAmB3C,eAAgB;AAAA;AAAA;AAAA;AAAA;AA+Bd,MAAM,eAAe;AAAA,EAC1B,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,MAAM;AACR;", + "names": [] +} diff --git a/public/vendor/paper-shaders/shaders/water.d.ts b/public/vendor/paper-shaders/shaders/water.d.ts new file mode 100644 index 0000000..11bff99 --- /dev/null +++ b/public/vendor/paper-shaders/shaders/water.d.ts @@ -0,0 +1,59 @@ +import type { ShaderMotionParams } from '../shader-mount.js'; +import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js'; +/** + * Water-like surface distortion with natural caustic realism. Works as an image filter or standalone animated texture. + * + * Fragment shader uniforms: + * - u_time (float): Animation time + * - u_image (sampler2D): Optional source image texture + * - u_imageAspectRatio (float): Aspect ratio of the source image + * - u_colorBack (vec4): Background color in RGBA + * - u_colorHighlight (vec4): Highlight color in RGBA + * - u_highlights (float): Coloring added over image/background following caustic shape (0 to 1) + * - u_layering (float): Power of 2nd layer of caustic distortion (0 to 1) + * - u_edges (float): Caustic distortion power on the image edges (0 to 1) + * - u_waves (float): Additional distortion based on simplex noise, independent from caustic (0 to 1) + * - u_caustic (float): Power of caustic distortion (0 to 1) + * - u_size (float): Pattern scale relative to the image (0.01 to 7) + * + * Vertex shader outputs (used in fragment shader): + * - v_imageUV (vec2): UV coordinates for sampling the source image, with fit, scale, rotation, and offset applied + * + * Vertex shader uniforms: + * - u_resolution (vec2): Canvas resolution in pixels + * - u_pixelRatio (float): Device pixel ratio + * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1) + * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1) + * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas + * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas + * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover) + * - u_scale (float): Overall zoom level of the graphics (0.01 to 4) + * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360) + * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1) + * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1) + * - u_imageAspectRatio (float): Aspect ratio of the source image + * + */ +export declare const waterFragmentShader: string; +export interface WaterUniforms extends ShaderSizingUniforms { + u_image: HTMLImageElement | string | undefined; + u_colorBack: [number, number, number, number]; + u_colorHighlight: [number, number, number, number]; + u_highlights: number; + u_layering: number; + u_edges: number; + u_caustic: number; + u_waves: number; + u_size: number; +} +export interface WaterParams extends ShaderSizingParams, ShaderMotionParams { + image?: HTMLImageElement | string; + colorBack?: string; + colorHighlight?: string; + highlights?: number; + layering?: number; + edges?: number; + caustic?: number; + waves?: number; + size?: number; +} diff --git a/public/vendor/paper-shaders/shaders/water.js b/public/vendor/paper-shaders/shaders/water.js new file mode 100644 index 0000000..6c0ff86 --- /dev/null +++ b/public/vendor/paper-shaders/shaders/water.js @@ -0,0 +1,120 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Paper Shaders * + * https://github.com/paper-design/shaders * + * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +import {} from "../shader-sizing.js"; +import { declarePI, rotation2, simplexNoise } from "../shader-utils.js"; +const waterFragmentShader = `#version 300 es +precision mediump float; + +uniform float u_time; + +uniform vec4 u_colorBack; +uniform vec4 u_colorHighlight; + +uniform sampler2D u_image; +uniform float u_imageAspectRatio; + +uniform float u_size; +uniform float u_highlights; +uniform float u_layering; +uniform float u_edges; +uniform float u_caustic; +uniform float u_waves; + +in vec2 v_imageUV; + +out vec4 fragColor; + +${declarePI} +${rotation2} +${simplexNoise} + +float getUvFrame(vec2 uv) { + float aax = 2. * fwidth(uv.x); + float aay = 2. * fwidth(uv.y); + + float left = smoothstep(0., aax, uv.x); + float right = 1.0 - smoothstep(1. - aax, 1., uv.x); + float bottom = smoothstep(0., aay, uv.y); + float top = 1.0 - smoothstep(1. - aay, 1., uv.y); + + return left * right * bottom * top; +} + +mat2 rotate2D(float r) { + return mat2(cos(r), sin(r), -sin(r), cos(r)); +} + +float getCausticNoise(vec2 uv, float t, float scale) { + vec2 n = vec2(.1); + vec2 N = vec2(.1); + mat2 m = rotate2D(.5); + for (int j = 0; j < 6; j++) { + uv *= m; + n *= m; + vec2 q = uv * scale + float(j) + n + (.5 + .5 * float(j)) * (mod(float(j), 2.) - 1.) * t; + n += sin(q); + N += cos(q) / scale; + scale *= 1.1; + } + return (N.x + N.y + 1.); +} + +void main() { + vec2 imageUV = v_imageUV; + vec2 patternUV = v_imageUV - .5; + patternUV = (patternUV * vec2(u_imageAspectRatio, 1.)); + patternUV /= (.01 + .09 * u_size); + + float t = u_time; + + float wavesNoise = snoise((.3 + .1 * sin(t)) * .1 * patternUV + vec2(0., .4 * t)); + + float causticNoise = getCausticNoise(patternUV + u_waves * vec2(1., -1.) * wavesNoise, 2. * t, 1.5); + + causticNoise += u_layering * getCausticNoise(patternUV + 2. * u_waves * vec2(1., -1.) * wavesNoise, 1.5 * t, 2.); + causticNoise = causticNoise * causticNoise; + + float edgesDistortion = smoothstep(0., .1, imageUV.x); + edgesDistortion *= smoothstep(0., .1, imageUV.y); + edgesDistortion *= (smoothstep(1., 1.1, imageUV.x) + (1.0 - smoothstep(.8, .95, imageUV.x))); + edgesDistortion *= (1.0 - smoothstep(.9, 1., imageUV.y)); + edgesDistortion = mix(edgesDistortion, 1., u_edges); + + float causticNoiseDistortion = .02 * causticNoise * edgesDistortion; + + float wavesDistortion = .1 * u_waves * wavesNoise; + + imageUV += vec2(wavesDistortion, -wavesDistortion); + imageUV += (u_caustic * causticNoiseDistortion); + + float frame = getUvFrame(imageUV); + + vec4 image = texture(u_image, imageUV); + vec4 backColor = u_colorBack; + backColor.rgb *= backColor.a; + + vec3 color = mix(backColor.rgb, image.rgb, image.a * frame); + float opacity = backColor.a + image.a * frame; + + causticNoise = max(-.2, causticNoise); + + float hightlight = .025 * u_highlights * causticNoise; + hightlight *= u_colorHighlight.a; + color = mix(color, u_colorHighlight.rgb, .05 * u_highlights * causticNoise); + opacity += hightlight; + + color += hightlight * (.5 + .5 * wavesNoise); + opacity += hightlight * (.5 + .5 * wavesNoise); + + opacity = clamp(opacity, 0., 1.); + + fragColor = vec4(color, opacity); +} +`; +export { + waterFragmentShader +}; +//# sourceMappingURL=water.js.map diff --git a/public/vendor/paper-shaders/shaders/water.js.map b/public/vendor/paper-shaders/shaders/water.js.map new file mode 100644 index 0000000..35ced9b --- /dev/null +++ b/public/vendor/paper-shaders/shaders/water.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../../src/shaders/water.ts"], + "sourcesContent": ["import type { ShaderMotionParams } from '../shader-mount.js';\nimport { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { declarePI, rotation2, simplexNoise } from '../shader-utils.js';\n\n/**\n * Water-like surface distortion with natural caustic realism. Works as an image filter or standalone animated texture.\n *\n * Fragment shader uniforms:\n * - u_time (float): Animation time\n * - u_image (sampler2D): Optional source image texture\n * - u_imageAspectRatio (float): Aspect ratio of the source image\n * - u_colorBack (vec4): Background color in RGBA\n * - u_colorHighlight (vec4): Highlight color in RGBA\n * - u_highlights (float): Coloring added over image/background following caustic shape (0 to 1)\n * - u_layering (float): Power of 2nd layer of caustic distortion (0 to 1)\n * - u_edges (float): Caustic distortion power on the image edges (0 to 1)\n * - u_waves (float): Additional distortion based on simplex noise, independent from caustic (0 to 1)\n * - u_caustic (float): Power of caustic distortion (0 to 1)\n * - u_size (float): Pattern scale relative to the image (0.01 to 7)\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_imageUV (vec2): UV coordinates for sampling the source image, with fit, scale, rotation, and offset applied\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n * - u_imageAspectRatio (float): Aspect ratio of the source image\n *\n */\n\n// language=GLSL\nexport const waterFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform float u_time;\n\nuniform vec4 u_colorBack;\nuniform vec4 u_colorHighlight;\n\nuniform sampler2D u_image;\nuniform float u_imageAspectRatio;\n\nuniform float u_size;\nuniform float u_highlights;\nuniform float u_layering;\nuniform float u_edges;\nuniform float u_caustic;\nuniform float u_waves;\n\nin vec2 v_imageUV;\n\nout vec4 fragColor;\n\n${ declarePI }\n${ rotation2 }\n${ simplexNoise }\n\nfloat getUvFrame(vec2 uv) {\n float aax = 2. * fwidth(uv.x);\n float aay = 2. * fwidth(uv.y);\n\n float left = smoothstep(0., aax, uv.x);\n float right = 1.0 - smoothstep(1. - aax, 1., uv.x);\n float bottom = smoothstep(0., aay, uv.y);\n float top = 1.0 - smoothstep(1. - aay, 1., uv.y);\n\n return left * right * bottom * top;\n}\n\nmat2 rotate2D(float r) {\n return mat2(cos(r), sin(r), -sin(r), cos(r));\n}\n\nfloat getCausticNoise(vec2 uv, float t, float scale) {\n vec2 n = vec2(.1);\n vec2 N = vec2(.1);\n mat2 m = rotate2D(.5);\n for (int j = 0; j < 6; j++) {\n uv *= m;\n n *= m;\n vec2 q = uv * scale + float(j) + n + (.5 + .5 * float(j)) * (mod(float(j), 2.) - 1.) * t;\n n += sin(q);\n N += cos(q) / scale;\n scale *= 1.1;\n }\n return (N.x + N.y + 1.);\n}\n\nvoid main() {\n vec2 imageUV = v_imageUV;\n vec2 patternUV = v_imageUV - .5;\n patternUV = (patternUV * vec2(u_imageAspectRatio, 1.));\n patternUV /= (.01 + .09 * u_size);\n\n float t = u_time;\n\n float wavesNoise = snoise((.3 + .1 * sin(t)) * .1 * patternUV + vec2(0., .4 * t));\n\n float causticNoise = getCausticNoise(patternUV + u_waves * vec2(1., -1.) * wavesNoise, 2. * t, 1.5);\n\n causticNoise += u_layering * getCausticNoise(patternUV + 2. * u_waves * vec2(1., -1.) * wavesNoise, 1.5 * t, 2.);\n causticNoise = causticNoise * causticNoise;\n\n float edgesDistortion = smoothstep(0., .1, imageUV.x);\n edgesDistortion *= smoothstep(0., .1, imageUV.y);\n edgesDistortion *= (smoothstep(1., 1.1, imageUV.x) + (1.0 - smoothstep(.8, .95, imageUV.x)));\n edgesDistortion *= (1.0 - smoothstep(.9, 1., imageUV.y));\n edgesDistortion = mix(edgesDistortion, 1., u_edges);\n\n float causticNoiseDistortion = .02 * causticNoise * edgesDistortion;\n\n float wavesDistortion = .1 * u_waves * wavesNoise;\n\n imageUV += vec2(wavesDistortion, -wavesDistortion);\n imageUV += (u_caustic * causticNoiseDistortion);\n\n float frame = getUvFrame(imageUV);\n\n vec4 image = texture(u_image, imageUV);\n vec4 backColor = u_colorBack;\n backColor.rgb *= backColor.a;\n\n vec3 color = mix(backColor.rgb, image.rgb, image.a * frame);\n float opacity = backColor.a + image.a * frame;\n\n causticNoise = max(-.2, causticNoise);\n\n float hightlight = .025 * u_highlights * causticNoise;\n hightlight *= u_colorHighlight.a;\n color = mix(color, u_colorHighlight.rgb, .05 * u_highlights * causticNoise);\n opacity += hightlight;\n\n color += hightlight * (.5 + .5 * wavesNoise);\n opacity += hightlight * (.5 + .5 * wavesNoise);\n\n opacity = clamp(opacity, 0., 1.);\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface WaterUniforms extends ShaderSizingUniforms {\n u_image: HTMLImageElement | string | undefined;\n u_colorBack: [number, number, number, number];\n u_colorHighlight: [number, number, number, number];\n u_highlights: number;\n u_layering: number;\n u_edges: number;\n u_caustic: number;\n u_waves: number;\n u_size: number;\n}\n\nexport interface WaterParams extends ShaderSizingParams, ShaderMotionParams {\n image?: HTMLImageElement | string;\n colorBack?: string;\n colorHighlight?: string;\n highlights?: number;\n layering?: number;\n edges?: number;\n caustic?: number;\n waves?: number;\n size?: number;\n}\n"], + "mappings": ";;;;;AACA,eAAmE;AACnE,SAAS,WAAW,WAAW,oBAAoB;AAsC5C,MAAM,sBAA8B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAsBxC,SAAU;AAAA,EACV,SAAU;AAAA,EACV,YAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;", + "names": [] +} diff --git a/public/vendor/paper-shaders/shaders/waves.d.ts b/public/vendor/paper-shaders/shaders/waves.d.ts new file mode 100644 index 0000000..e5265fd --- /dev/null +++ b/public/vendor/paper-shaders/shaders/waves.d.ts @@ -0,0 +1,53 @@ +import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js'; +/** + * Static line pattern configurable into textures ranging from sharp zigzags to smooth flowing waves. + * + * Fragment shader uniforms: + * - u_colorFront (vec4): Foreground color in RGBA + * - u_colorBack (vec4): Background color in RGBA + * - u_shape (float): Line shape, 0 = zigzag, 1 = sine, 2-3 = irregular waves, fractional values morph between shapes (0 to 3) + * - u_amplitude (float): Wave amplitude (0 to 1) + * - u_frequency (float): Wave frequency (0 to 2) + * - u_spacing (float): Space between every two wavy lines (0 to 2) + * - u_proportion (float): Blend point between front and back colors, 0.5 = equal distribution (0 to 1) + * - u_softness (float): Color transition sharpness, 0 = hard edge, 1 = smooth gradient (0 to 1) + * + * Vertex shader outputs (used in fragment shader): + * - v_patternUV (vec2): UV coordinates for pattern with global sizing (rotation, scale, offset, etc) applied + * + * Vertex shader uniforms: + * - u_resolution (vec2): Canvas resolution in pixels + * - u_pixelRatio (float): Device pixel ratio + * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1) + * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1) + * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas + * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas + * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover) + * - u_scale (float): Overall zoom level of the graphics (0.01 to 4) + * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360) + * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1) + * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1) + * + */ +export declare const wavesFragmentShader: string; +export interface WavesUniforms extends ShaderSizingUniforms { + u_colorFront: [number, number, number, number]; + u_colorBack: [number, number, number, number]; + u_shape: number; + u_frequency: number; + u_amplitude: number; + u_spacing: number; + u_proportion: number; + u_softness: number; +} +export interface WavesParams extends ShaderSizingParams { + colorFront?: string; + colorBack?: string; + rotation?: number; + shape?: number; + frequency?: number; + amplitude?: number; + spacing?: number; + proportion?: number; + softness?: number; +} diff --git a/public/vendor/paper-shaders/shaders/waves.js b/public/vendor/paper-shaders/shaders/waves.js new file mode 100644 index 0000000..887b7f7 --- /dev/null +++ b/public/vendor/paper-shaders/shaders/waves.js @@ -0,0 +1,66 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Paper Shaders * + * https://github.com/paper-design/shaders * + * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +import {} from "../shader-sizing.js"; +import { declarePI } from "../shader-utils.js"; +const wavesFragmentShader = `#version 300 es +precision mediump float; + +uniform vec4 u_colorFront; +uniform vec4 u_colorBack; +uniform float u_shape; +uniform float u_frequency; +uniform float u_amplitude; +uniform float u_spacing; +uniform float u_proportion; +uniform float u_softness; + +in vec2 v_patternUV; + +out vec4 fragColor; + +${declarePI} + +void main() { + vec2 shape_uv = v_patternUV; + shape_uv *= 4.; + + float wave = .5 * cos(shape_uv.x * u_frequency * TWO_PI); + float zigzag = 2. * abs(fract(shape_uv.x * u_frequency) - .5); + float irregular = sin(shape_uv.x * .25 * u_frequency * TWO_PI) * cos(shape_uv.x * u_frequency * TWO_PI); + float irregular2 = .75 * (sin(shape_uv.x * u_frequency * TWO_PI) + .5 * cos(shape_uv.x * .5 * u_frequency * TWO_PI)); + + float offset = mix(zigzag, wave, smoothstep(0., 1., u_shape)); + offset = mix(offset, irregular, smoothstep(1., 2., u_shape)); + offset = mix(offset, irregular2, smoothstep(2., 3., u_shape)); + offset *= 2. * u_amplitude; + + float spacing = (.001 + u_spacing); + float shape = .5 + .5 * sin((shape_uv.y + offset) * PI / spacing); + + float aa = .0001 + fwidth(shape); + float dc = 1. - clamp(u_proportion, 0., 1.); + float e0 = dc - u_softness - aa; + float e1 = dc + u_softness + aa; + float res = smoothstep(min(e0, e1), max(e0, e1), shape); + + vec3 fgColor = u_colorFront.rgb * u_colorFront.a; + float fgOpacity = u_colorFront.a; + vec3 bgColor = u_colorBack.rgb * u_colorBack.a; + float bgOpacity = u_colorBack.a; + + vec3 color = fgColor * res; + float opacity = fgOpacity * res; + + color += bgColor * (1. - opacity); + opacity += bgOpacity * (1. - opacity); + + fragColor = vec4(color, opacity); +} +`; +export { + wavesFragmentShader +}; +//# sourceMappingURL=waves.js.map diff --git a/public/vendor/paper-shaders/shaders/waves.js.map b/public/vendor/paper-shaders/shaders/waves.js.map new file mode 100644 index 0000000..0d8ad65 --- /dev/null +++ b/public/vendor/paper-shaders/shaders/waves.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../../src/shaders/waves.ts"], + "sourcesContent": ["import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { declarePI } from '../shader-utils.js';\n\n/**\n * Static line pattern configurable into textures ranging from sharp zigzags to smooth flowing waves.\n *\n * Fragment shader uniforms:\n * - u_colorFront (vec4): Foreground color in RGBA\n * - u_colorBack (vec4): Background color in RGBA\n * - u_shape (float): Line shape, 0 = zigzag, 1 = sine, 2-3 = irregular waves, fractional values morph between shapes (0 to 3)\n * - u_amplitude (float): Wave amplitude (0 to 1)\n * - u_frequency (float): Wave frequency (0 to 2)\n * - u_spacing (float): Space between every two wavy lines (0 to 2)\n * - u_proportion (float): Blend point between front and back colors, 0.5 = equal distribution (0 to 1)\n * - u_softness (float): Color transition sharpness, 0 = hard edge, 1 = smooth gradient (0 to 1)\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_patternUV (vec2): UV coordinates for pattern with global sizing (rotation, scale, offset, etc) applied\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n *\n */\n\n// language=GLSL\nexport const wavesFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform vec4 u_colorFront;\nuniform vec4 u_colorBack;\nuniform float u_shape;\nuniform float u_frequency;\nuniform float u_amplitude;\nuniform float u_spacing;\nuniform float u_proportion;\nuniform float u_softness;\n\nin vec2 v_patternUV;\n\nout vec4 fragColor;\n\n${ declarePI }\n\nvoid main() {\n vec2 shape_uv = v_patternUV;\n shape_uv *= 4.;\n\n float wave = .5 * cos(shape_uv.x * u_frequency * TWO_PI);\n float zigzag = 2. * abs(fract(shape_uv.x * u_frequency) - .5);\n float irregular = sin(shape_uv.x * .25 * u_frequency * TWO_PI) * cos(shape_uv.x * u_frequency * TWO_PI);\n float irregular2 = .75 * (sin(shape_uv.x * u_frequency * TWO_PI) + .5 * cos(shape_uv.x * .5 * u_frequency * TWO_PI));\n\n float offset = mix(zigzag, wave, smoothstep(0., 1., u_shape));\n offset = mix(offset, irregular, smoothstep(1., 2., u_shape));\n offset = mix(offset, irregular2, smoothstep(2., 3., u_shape));\n offset *= 2. * u_amplitude;\n\n float spacing = (.001 + u_spacing);\n float shape = .5 + .5 * sin((shape_uv.y + offset) * PI / spacing);\n\n float aa = .0001 + fwidth(shape);\n float dc = 1. - clamp(u_proportion, 0., 1.);\n float e0 = dc - u_softness - aa;\n float e1 = dc + u_softness + aa;\n float res = smoothstep(min(e0, e1), max(e0, e1), shape);\n\n vec3 fgColor = u_colorFront.rgb * u_colorFront.a;\n float fgOpacity = u_colorFront.a;\n vec3 bgColor = u_colorBack.rgb * u_colorBack.a;\n float bgOpacity = u_colorBack.a;\n\n vec3 color = fgColor * res;\n float opacity = fgOpacity * res;\n\n color += bgColor * (1. - opacity);\n opacity += bgOpacity * (1. - opacity);\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface WavesUniforms extends ShaderSizingUniforms {\n u_colorFront: [number, number, number, number];\n u_colorBack: [number, number, number, number];\n u_shape: number;\n u_frequency: number;\n u_amplitude: number;\n u_spacing: number;\n u_proportion: number;\n u_softness: number;\n}\n\nexport interface WavesParams extends ShaderSizingParams {\n colorFront?: string;\n colorBack?: string;\n rotation?: number;\n shape?: number;\n frequency?: number;\n amplitude?: number;\n spacing?: number;\n proportion?: number;\n softness?: number;\n}\n"], + "mappings": ";;;;;AAAA,eAAmE;AACnE,SAAS,iBAAiB;AAkCnB,MAAM,sBAA8B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBxC,SAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;", + "names": [] +} diff --git a/public/vendor/paper-shaders/types.d.ts b/public/vendor/paper-shaders/types.d.ts new file mode 100644 index 0000000..d675c51 --- /dev/null +++ b/public/vendor/paper-shaders/types.d.ts @@ -0,0 +1,3 @@ +export type vec4 = [number, number, number, number]; +export type vec3 = [number, number, number]; +export type vec2 = [number, number]; diff --git a/public/vendor/paper-shaders/types.js b/public/vendor/paper-shaders/types.js new file mode 100644 index 0000000..32b5358 --- /dev/null +++ b/public/vendor/paper-shaders/types.js @@ -0,0 +1,6 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Paper Shaders * + * https://github.com/paper-design/shaders * + * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +//# sourceMappingURL=types.js.map diff --git a/public/vendor/paper-shaders/types.js.map b/public/vendor/paper-shaders/types.js.map new file mode 100644 index 0000000..9865211 --- /dev/null +++ b/public/vendor/paper-shaders/types.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": [], + "sourcesContent": [], + "mappings": "", + "names": [] +} diff --git a/public/vendor/paper-shaders/vertex-shader.d.ts b/public/vendor/paper-shaders/vertex-shader.d.ts new file mode 100644 index 0000000..7cf9b45 --- /dev/null +++ b/public/vendor/paper-shaders/vertex-shader.d.ts @@ -0,0 +1,2 @@ +/** Vertex shader for the shader mount */ +export declare const vertexShaderSource = "#version 300 es\nprecision mediump float;\n\nlayout(location = 0) in vec4 a_position;\n\nuniform vec2 u_resolution;\nuniform float u_pixelRatio;\nuniform float u_imageAspectRatio;\nuniform float u_originX;\nuniform float u_originY;\nuniform float u_worldWidth;\nuniform float u_worldHeight;\nuniform float u_fit;\nuniform float u_scale;\nuniform float u_rotation;\nuniform float u_offsetX;\nuniform float u_offsetY;\n\nout vec2 v_objectUV;\nout vec2 v_objectBoxSize;\nout vec2 v_responsiveUV;\nout vec2 v_responsiveBoxGivenSize;\nout vec2 v_patternUV;\nout vec2 v_patternBoxSize;\nout vec2 v_imageUV;\n\nvec3 getBoxSize(float boxRatio, vec2 givenBoxSize) {\n vec2 box = vec2(0.);\n // fit = none\n box.x = boxRatio * min(givenBoxSize.x / boxRatio, givenBoxSize.y);\n float noFitBoxWidth = box.x;\n if (u_fit == 1.) { // fit = contain\n box.x = boxRatio * min(u_resolution.x / boxRatio, u_resolution.y);\n } else if (u_fit == 2.) { // fit = cover\n box.x = boxRatio * max(u_resolution.x / boxRatio, u_resolution.y);\n }\n box.y = box.x / boxRatio;\n return vec3(box, noFitBoxWidth);\n}\n\nvoid main() {\n gl_Position = a_position;\n\n vec2 uv = gl_Position.xy * .5;\n vec2 boxOrigin = vec2(.5 - u_originX, u_originY - .5);\n vec2 givenBoxSize = vec2(u_worldWidth, u_worldHeight);\n givenBoxSize = max(givenBoxSize, vec2(1.)) * u_pixelRatio;\n float r = u_rotation * 3.14159265358979323846 / 180.;\n mat2 graphicRotation = mat2(cos(r), sin(r), -sin(r), cos(r));\n vec2 graphicOffset = vec2(-u_offsetX, u_offsetY);\n\n\n // ===================================================\n\n float fixedRatio = 1.;\n vec2 fixedRatioBoxGivenSize = vec2(\n (u_worldWidth == 0.) ? u_resolution.x : givenBoxSize.x,\n (u_worldHeight == 0.) ? u_resolution.y : givenBoxSize.y\n );\n\n v_objectBoxSize = getBoxSize(fixedRatio, fixedRatioBoxGivenSize).xy;\n vec2 objectWorldScale = u_resolution.xy / v_objectBoxSize;\n\n v_objectUV = uv;\n v_objectUV *= objectWorldScale;\n v_objectUV += boxOrigin * (objectWorldScale - 1.);\n v_objectUV += graphicOffset;\n v_objectUV /= u_scale;\n v_objectUV = graphicRotation * v_objectUV;\n\n // ===================================================\n\n v_responsiveBoxGivenSize = vec2(\n (u_worldWidth == 0.) ? u_resolution.x : givenBoxSize.x,\n (u_worldHeight == 0.) ? u_resolution.y : givenBoxSize.y\n );\n float responsiveRatio = v_responsiveBoxGivenSize.x / v_responsiveBoxGivenSize.y;\n vec2 responsiveBoxSize = getBoxSize(responsiveRatio, v_responsiveBoxGivenSize).xy;\n vec2 responsiveBoxScale = u_resolution.xy / responsiveBoxSize;\n\n #ifdef ADD_HELPERS\n v_responsiveHelperBox = uv;\n v_responsiveHelperBox *= responsiveBoxScale;\n v_responsiveHelperBox += boxOrigin * (responsiveBoxScale - 1.);\n #endif\n\n v_responsiveUV = uv;\n v_responsiveUV *= responsiveBoxScale;\n v_responsiveUV += boxOrigin * (responsiveBoxScale - 1.);\n v_responsiveUV += graphicOffset;\n v_responsiveUV /= u_scale;\n v_responsiveUV.x *= responsiveRatio;\n v_responsiveUV = graphicRotation * v_responsiveUV;\n v_responsiveUV.x /= responsiveRatio;\n\n // ===================================================\n\n float patternBoxRatio = givenBoxSize.x / givenBoxSize.y;\n vec2 patternBoxGivenSize = vec2(\n (u_worldWidth == 0.) ? u_resolution.x : givenBoxSize.x,\n (u_worldHeight == 0.) ? u_resolution.y : givenBoxSize.y\n );\n patternBoxRatio = patternBoxGivenSize.x / patternBoxGivenSize.y;\n\n vec3 boxSizeData = getBoxSize(patternBoxRatio, patternBoxGivenSize);\n v_patternBoxSize = boxSizeData.xy;\n float patternBoxNoFitBoxWidth = boxSizeData.z;\n vec2 patternBoxScale = u_resolution.xy / v_patternBoxSize;\n\n v_patternUV = uv;\n v_patternUV += graphicOffset / patternBoxScale;\n v_patternUV += boxOrigin;\n v_patternUV -= boxOrigin / patternBoxScale;\n v_patternUV *= u_resolution.xy;\n v_patternUV /= u_pixelRatio;\n if (u_fit > 0.) {\n v_patternUV *= (patternBoxNoFitBoxWidth / v_patternBoxSize.x);\n }\n v_patternUV /= u_scale;\n v_patternUV = graphicRotation * v_patternUV;\n v_patternUV += boxOrigin / patternBoxScale;\n v_patternUV -= boxOrigin;\n // x100 is a default multiplier between vertex and fragmant shaders\n // we use it to avoid UV presision issues\n v_patternUV *= .01;\n\n // ===================================================\n\n vec2 imageBoxSize;\n if (u_fit == 1.) { // contain\n imageBoxSize.x = min(u_resolution.x / u_imageAspectRatio, u_resolution.y) * u_imageAspectRatio;\n } else if (u_fit == 2.) { // cover\n imageBoxSize.x = max(u_resolution.x / u_imageAspectRatio, u_resolution.y) * u_imageAspectRatio;\n } else {\n imageBoxSize.x = min(10.0, 10.0 / u_imageAspectRatio * u_imageAspectRatio);\n }\n imageBoxSize.y = imageBoxSize.x / u_imageAspectRatio;\n vec2 imageBoxScale = u_resolution.xy / imageBoxSize;\n\n v_imageUV = uv;\n v_imageUV *= imageBoxScale;\n v_imageUV += boxOrigin * (imageBoxScale - 1.);\n v_imageUV += graphicOffset;\n v_imageUV /= u_scale;\n v_imageUV.x *= u_imageAspectRatio;\n v_imageUV = graphicRotation * v_imageUV;\n v_imageUV.x /= u_imageAspectRatio;\n\n v_imageUV += .5;\n v_imageUV.y = 1. - v_imageUV.y;\n}"; diff --git a/public/vendor/paper-shaders/vertex-shader.js b/public/vendor/paper-shaders/vertex-shader.js new file mode 100644 index 0000000..73d7aba --- /dev/null +++ b/public/vendor/paper-shaders/vertex-shader.js @@ -0,0 +1,160 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Paper Shaders * + * https://github.com/paper-design/shaders * + * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +const vertexShaderSource = `#version 300 es +precision mediump float; + +layout(location = 0) in vec4 a_position; + +uniform vec2 u_resolution; +uniform float u_pixelRatio; +uniform float u_imageAspectRatio; +uniform float u_originX; +uniform float u_originY; +uniform float u_worldWidth; +uniform float u_worldHeight; +uniform float u_fit; +uniform float u_scale; +uniform float u_rotation; +uniform float u_offsetX; +uniform float u_offsetY; + +out vec2 v_objectUV; +out vec2 v_objectBoxSize; +out vec2 v_responsiveUV; +out vec2 v_responsiveBoxGivenSize; +out vec2 v_patternUV; +out vec2 v_patternBoxSize; +out vec2 v_imageUV; + +vec3 getBoxSize(float boxRatio, vec2 givenBoxSize) { + vec2 box = vec2(0.); + // fit = none + box.x = boxRatio * min(givenBoxSize.x / boxRatio, givenBoxSize.y); + float noFitBoxWidth = box.x; + if (u_fit == 1.) { // fit = contain + box.x = boxRatio * min(u_resolution.x / boxRatio, u_resolution.y); + } else if (u_fit == 2.) { // fit = cover + box.x = boxRatio * max(u_resolution.x / boxRatio, u_resolution.y); + } + box.y = box.x / boxRatio; + return vec3(box, noFitBoxWidth); +} + +void main() { + gl_Position = a_position; + + vec2 uv = gl_Position.xy * .5; + vec2 boxOrigin = vec2(.5 - u_originX, u_originY - .5); + vec2 givenBoxSize = vec2(u_worldWidth, u_worldHeight); + givenBoxSize = max(givenBoxSize, vec2(1.)) * u_pixelRatio; + float r = u_rotation * 3.14159265358979323846 / 180.; + mat2 graphicRotation = mat2(cos(r), sin(r), -sin(r), cos(r)); + vec2 graphicOffset = vec2(-u_offsetX, u_offsetY); + + + // =================================================== + + float fixedRatio = 1.; + vec2 fixedRatioBoxGivenSize = vec2( + (u_worldWidth == 0.) ? u_resolution.x : givenBoxSize.x, + (u_worldHeight == 0.) ? u_resolution.y : givenBoxSize.y + ); + + v_objectBoxSize = getBoxSize(fixedRatio, fixedRatioBoxGivenSize).xy; + vec2 objectWorldScale = u_resolution.xy / v_objectBoxSize; + + v_objectUV = uv; + v_objectUV *= objectWorldScale; + v_objectUV += boxOrigin * (objectWorldScale - 1.); + v_objectUV += graphicOffset; + v_objectUV /= u_scale; + v_objectUV = graphicRotation * v_objectUV; + + // =================================================== + + v_responsiveBoxGivenSize = vec2( + (u_worldWidth == 0.) ? u_resolution.x : givenBoxSize.x, + (u_worldHeight == 0.) ? u_resolution.y : givenBoxSize.y + ); + float responsiveRatio = v_responsiveBoxGivenSize.x / v_responsiveBoxGivenSize.y; + vec2 responsiveBoxSize = getBoxSize(responsiveRatio, v_responsiveBoxGivenSize).xy; + vec2 responsiveBoxScale = u_resolution.xy / responsiveBoxSize; + + #ifdef ADD_HELPERS + v_responsiveHelperBox = uv; + v_responsiveHelperBox *= responsiveBoxScale; + v_responsiveHelperBox += boxOrigin * (responsiveBoxScale - 1.); + #endif + + v_responsiveUV = uv; + v_responsiveUV *= responsiveBoxScale; + v_responsiveUV += boxOrigin * (responsiveBoxScale - 1.); + v_responsiveUV += graphicOffset; + v_responsiveUV /= u_scale; + v_responsiveUV.x *= responsiveRatio; + v_responsiveUV = graphicRotation * v_responsiveUV; + v_responsiveUV.x /= responsiveRatio; + + // =================================================== + + float patternBoxRatio = givenBoxSize.x / givenBoxSize.y; + vec2 patternBoxGivenSize = vec2( + (u_worldWidth == 0.) ? u_resolution.x : givenBoxSize.x, + (u_worldHeight == 0.) ? u_resolution.y : givenBoxSize.y + ); + patternBoxRatio = patternBoxGivenSize.x / patternBoxGivenSize.y; + + vec3 boxSizeData = getBoxSize(patternBoxRatio, patternBoxGivenSize); + v_patternBoxSize = boxSizeData.xy; + float patternBoxNoFitBoxWidth = boxSizeData.z; + vec2 patternBoxScale = u_resolution.xy / v_patternBoxSize; + + v_patternUV = uv; + v_patternUV += graphicOffset / patternBoxScale; + v_patternUV += boxOrigin; + v_patternUV -= boxOrigin / patternBoxScale; + v_patternUV *= u_resolution.xy; + v_patternUV /= u_pixelRatio; + if (u_fit > 0.) { + v_patternUV *= (patternBoxNoFitBoxWidth / v_patternBoxSize.x); + } + v_patternUV /= u_scale; + v_patternUV = graphicRotation * v_patternUV; + v_patternUV += boxOrigin / patternBoxScale; + v_patternUV -= boxOrigin; + // x100 is a default multiplier between vertex and fragmant shaders + // we use it to avoid UV presision issues + v_patternUV *= .01; + + // =================================================== + + vec2 imageBoxSize; + if (u_fit == 1.) { // contain + imageBoxSize.x = min(u_resolution.x / u_imageAspectRatio, u_resolution.y) * u_imageAspectRatio; + } else if (u_fit == 2.) { // cover + imageBoxSize.x = max(u_resolution.x / u_imageAspectRatio, u_resolution.y) * u_imageAspectRatio; + } else { + imageBoxSize.x = min(10.0, 10.0 / u_imageAspectRatio * u_imageAspectRatio); + } + imageBoxSize.y = imageBoxSize.x / u_imageAspectRatio; + vec2 imageBoxScale = u_resolution.xy / imageBoxSize; + + v_imageUV = uv; + v_imageUV *= imageBoxScale; + v_imageUV += boxOrigin * (imageBoxScale - 1.); + v_imageUV += graphicOffset; + v_imageUV /= u_scale; + v_imageUV.x *= u_imageAspectRatio; + v_imageUV = graphicRotation * v_imageUV; + v_imageUV.x /= u_imageAspectRatio; + + v_imageUV += .5; + v_imageUV.y = 1. - v_imageUV.y; +}`; +export { + vertexShaderSource +}; +//# sourceMappingURL=vertex-shader.js.map diff --git a/public/vendor/paper-shaders/vertex-shader.js.map b/public/vendor/paper-shaders/vertex-shader.js.map new file mode 100644 index 0000000..07cd0ca --- /dev/null +++ b/public/vendor/paper-shaders/vertex-shader.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../src/vertex-shader.ts"], + "sourcesContent": ["/** Vertex shader for the shader mount */\n// language=GLSL\nexport const vertexShaderSource = `#version 300 es\nprecision mediump float;\n\nlayout(location = 0) in vec4 a_position;\n\nuniform vec2 u_resolution;\nuniform float u_pixelRatio;\nuniform float u_imageAspectRatio;\nuniform float u_originX;\nuniform float u_originY;\nuniform float u_worldWidth;\nuniform float u_worldHeight;\nuniform float u_fit;\nuniform float u_scale;\nuniform float u_rotation;\nuniform float u_offsetX;\nuniform float u_offsetY;\n\nout vec2 v_objectUV;\nout vec2 v_objectBoxSize;\nout vec2 v_responsiveUV;\nout vec2 v_responsiveBoxGivenSize;\nout vec2 v_patternUV;\nout vec2 v_patternBoxSize;\nout vec2 v_imageUV;\n\nvec3 getBoxSize(float boxRatio, vec2 givenBoxSize) {\n vec2 box = vec2(0.);\n // fit = none\n box.x = boxRatio * min(givenBoxSize.x / boxRatio, givenBoxSize.y);\n float noFitBoxWidth = box.x;\n if (u_fit == 1.) { // fit = contain\n box.x = boxRatio * min(u_resolution.x / boxRatio, u_resolution.y);\n } else if (u_fit == 2.) { // fit = cover\n box.x = boxRatio * max(u_resolution.x / boxRatio, u_resolution.y);\n }\n box.y = box.x / boxRatio;\n return vec3(box, noFitBoxWidth);\n}\n\nvoid main() {\n gl_Position = a_position;\n\n vec2 uv = gl_Position.xy * .5;\n vec2 boxOrigin = vec2(.5 - u_originX, u_originY - .5);\n vec2 givenBoxSize = vec2(u_worldWidth, u_worldHeight);\n givenBoxSize = max(givenBoxSize, vec2(1.)) * u_pixelRatio;\n float r = u_rotation * 3.14159265358979323846 / 180.;\n mat2 graphicRotation = mat2(cos(r), sin(r), -sin(r), cos(r));\n vec2 graphicOffset = vec2(-u_offsetX, u_offsetY);\n\n\n // ===================================================\n\n float fixedRatio = 1.;\n vec2 fixedRatioBoxGivenSize = vec2(\n (u_worldWidth == 0.) ? u_resolution.x : givenBoxSize.x,\n (u_worldHeight == 0.) ? u_resolution.y : givenBoxSize.y\n );\n\n v_objectBoxSize = getBoxSize(fixedRatio, fixedRatioBoxGivenSize).xy;\n vec2 objectWorldScale = u_resolution.xy / v_objectBoxSize;\n\n v_objectUV = uv;\n v_objectUV *= objectWorldScale;\n v_objectUV += boxOrigin * (objectWorldScale - 1.);\n v_objectUV += graphicOffset;\n v_objectUV /= u_scale;\n v_objectUV = graphicRotation * v_objectUV;\n\n // ===================================================\n\n v_responsiveBoxGivenSize = vec2(\n (u_worldWidth == 0.) ? u_resolution.x : givenBoxSize.x,\n (u_worldHeight == 0.) ? u_resolution.y : givenBoxSize.y\n );\n float responsiveRatio = v_responsiveBoxGivenSize.x / v_responsiveBoxGivenSize.y;\n vec2 responsiveBoxSize = getBoxSize(responsiveRatio, v_responsiveBoxGivenSize).xy;\n vec2 responsiveBoxScale = u_resolution.xy / responsiveBoxSize;\n\n #ifdef ADD_HELPERS\n v_responsiveHelperBox = uv;\n v_responsiveHelperBox *= responsiveBoxScale;\n v_responsiveHelperBox += boxOrigin * (responsiveBoxScale - 1.);\n #endif\n\n v_responsiveUV = uv;\n v_responsiveUV *= responsiveBoxScale;\n v_responsiveUV += boxOrigin * (responsiveBoxScale - 1.);\n v_responsiveUV += graphicOffset;\n v_responsiveUV /= u_scale;\n v_responsiveUV.x *= responsiveRatio;\n v_responsiveUV = graphicRotation * v_responsiveUV;\n v_responsiveUV.x /= responsiveRatio;\n\n // ===================================================\n\n float patternBoxRatio = givenBoxSize.x / givenBoxSize.y;\n vec2 patternBoxGivenSize = vec2(\n (u_worldWidth == 0.) ? u_resolution.x : givenBoxSize.x,\n (u_worldHeight == 0.) ? u_resolution.y : givenBoxSize.y\n );\n patternBoxRatio = patternBoxGivenSize.x / patternBoxGivenSize.y;\n\n vec3 boxSizeData = getBoxSize(patternBoxRatio, patternBoxGivenSize);\n v_patternBoxSize = boxSizeData.xy;\n float patternBoxNoFitBoxWidth = boxSizeData.z;\n vec2 patternBoxScale = u_resolution.xy / v_patternBoxSize;\n\n v_patternUV = uv;\n v_patternUV += graphicOffset / patternBoxScale;\n v_patternUV += boxOrigin;\n v_patternUV -= boxOrigin / patternBoxScale;\n v_patternUV *= u_resolution.xy;\n v_patternUV /= u_pixelRatio;\n if (u_fit > 0.) {\n v_patternUV *= (patternBoxNoFitBoxWidth / v_patternBoxSize.x);\n }\n v_patternUV /= u_scale;\n v_patternUV = graphicRotation * v_patternUV;\n v_patternUV += boxOrigin / patternBoxScale;\n v_patternUV -= boxOrigin;\n // x100 is a default multiplier between vertex and fragmant shaders\n // we use it to avoid UV presision issues\n v_patternUV *= .01;\n\n // ===================================================\n\n vec2 imageBoxSize;\n if (u_fit == 1.) { // contain\n imageBoxSize.x = min(u_resolution.x / u_imageAspectRatio, u_resolution.y) * u_imageAspectRatio;\n } else if (u_fit == 2.) { // cover\n imageBoxSize.x = max(u_resolution.x / u_imageAspectRatio, u_resolution.y) * u_imageAspectRatio;\n } else {\n imageBoxSize.x = min(10.0, 10.0 / u_imageAspectRatio * u_imageAspectRatio);\n }\n imageBoxSize.y = imageBoxSize.x / u_imageAspectRatio;\n vec2 imageBoxScale = u_resolution.xy / imageBoxSize;\n\n v_imageUV = uv;\n v_imageUV *= imageBoxScale;\n v_imageUV += boxOrigin * (imageBoxScale - 1.);\n v_imageUV += graphicOffset;\n v_imageUV /= u_scale;\n v_imageUV.x *= u_imageAspectRatio;\n v_imageUV = graphicRotation * v_imageUV;\n v_imageUV.x /= u_imageAspectRatio;\n\n v_imageUV += .5;\n v_imageUV.y = 1. - v_imageUV.y;\n}`;\n"], + "mappings": ";;;;;AAEO,MAAM,qBAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;", + "names": [] +} diff --git a/scripts/serve-dev.mjs b/scripts/serve-dev.mjs index 39fb5ae..ea45c70 100644 --- a/scripts/serve-dev.mjs +++ b/scripts/serve-dev.mjs @@ -21,7 +21,7 @@ function ensureEditsDir() { function isLocalRequest(req) { const host = (req.headers.host || "").split(":")[0]; - const ALLOWED = ["localhost", "127.0.0.1", "dev.mamadaevv.site", "f2ogw6fzi6trnp7cp43x8wsd.31.129.103.242.sslip.io"]; + const ALLOWED = ["localhost", "127.0.0.1", "10.200.201.3", "dev.mamadaevv.site", "f2ogw6fzi6trnp7cp43x8wsd.31.129.103.242.sslip.io"]; return ALLOWED.includes(host); } diff --git a/src/pages/resume.en.html b/src/pages/resume.en.html index 3eddfb1..746630f 100644 --- a/src/pages/resume.en.html +++ b/src/pages/resume.en.html @@ -9,220 +9,23 @@ /> Resume — Nikolai Mamadaev {{> head-links}} - {{> header-minimal}} {{> fab-stack-resume}}
      -
      -
      - Nikolai Mamadaev +
      +
      +
      + Nikolai Mamadaev

      Resume

      Nikolai Mamadaev

      -

      Senior UX/UI Designer, Product Designer

      +

      Senior UX/UI Designer
      + Product Designer
      + AI Designer

      -
      - -
      +
      -
      Salary Range
      -
      250,000 – 310,000 rubles
      +
      Salary
      +
      from 250,000 ₽
      +
      +
      Languages
      +
      English (B2)
      +
      - -
      - -

      Work Experience

      - -
      - -
      -
      -

      Astratech

      -

      January 2026 — Present

      -
      -

      Development and support of digital systems and tools to improve employee productivity.

      - -
      -
      -
      -

      Responsibilities:

      -
        -
      • Worked on interface design
      • -
      -
      -
      -

      Achievements:

      -
        -
      • Successfully completed assigned tasks
      • -
      -
      -
      -

      Stack:

      -
        -
      • Figma
      • -
      • HTML/CSS
      • -
      • AI/LLM
      • -
      -
      -
      -
      -
      +
      +

      Work Experience

      +
        +
      1. +
        +

        Astratech

        +

        — Present

        +
        +

        Development and support of digital systems and tools to improve employee productivity.

        -
        -
        -

        Primo RPA

        -

        February 2023 — November 2025 (2 years and 10 months)·primo-rpa.com

        -
        -

        A Russian enterprise-grade RPA platform: a suite of desktop robot development environments and web services for management, analytics, and ML. I worked as a lead designer on the entire product line, consisting of 6 products.

        - -
        -

        AI Server Platform (SaaS)

        -

        A control panel for training, running, testing, and other operations involving neural networks deployed within the company’s internal network.

        -
        -
        -

        Responsibilities:

        -
          -
        • Designing the model management interface: training, deployment, testing, versioning, and monitoring
        • -
        • Developing workflows for Smart OCR—extracting data from various types of documents
        • -
        • Designing document markup and validating recognition results
        • -
        • Managing the states of long-running processes: model training, progress, errors, rollback
        • -
        • Preparing interactive prototypes and overseeing implementation
        • -
        • Conducting interviews with ML engineers and business users to validate behavioral models
        • -
        -
        -
        -

        Achievements:

        -
          -
        • Packaged complex ML logic into an interface that is understandable not only to ML engineers but also to business analysts without a technical background
        • -
        • Streamlined work with models into a single, predictable 4-step workflow instead of 9 disparate screens
        • -
        • Reduced the time required to configure a new model from 40 to 15 minutes, based on test results
        • -
        • Designed a document annotation interface that reduced support requests on this topic by 60%
        • -
        • Conducted 8 usability sessions and, based on the results, revised the key model training scenario
        • -
        -
        -
        -

        Stack:

        -
          -
        • ML / neural networks
        • -
        • Smart OCR
        • -
        +
        +
        +
        +

        Responsibilities

        +
          +
        • Creating production-ready interfaces
        • +
        • Breaking down ideas and concepts and turning them into design tasks
        • +
        +
        +
        +

        Achievements

        +
          +
        • Set up a configured environment for delivering interfaces to production
        • +
        • Ran more than 15 hypothesis tests on working prototypes without involving the development department
        • +
        • Sped up processing of user testing results by applying AI tools (summarization, classification, transcription)
        • +
        +
        +
        +

        Stack

        +
          +
        • Figma
        • +
        • HTML/CSS/JS
        • +
        • AI/LLM
        • +
        • GitHub
        • +
        • Gitea
        • +
        • Coolify
        • +
        • CI/CD
        • +
        • Hermes Agent
        • +
        • Zed IDE
        • +
        +
        -
        +
      2. -
        - -
        -

        Robot Automation Studio (Windows)

        -

        An environment for developing and debugging robots for business process automation.

        -
        -
        -

        Responsibilities:

        -
          -
        • Designing the interface for a professional desktop IDE: workspace, toolbars, process tree, debugger
        • -
        • Developing the product’s component library and visual language
        • -
        • Designing debugging scenarios: breakpoints, step-by-step execution, variable inspection
        • -
        • Designing support for large activity trees and nesting
        • -
        • Working in tandem with the development team on component implementation, providing author supervision
        • -
        • Conducting regular design reviews within the team
        • -
        -
        -
        -

        Achievements:

        -
          -
        • Updated the product’s visual language to the Windows 10/11 standard—components are now a generation more modern
        • -
        • Redesigned over 80 screens and dialogs, bringing them into a unified grid and typography
        • -
        • Compiled a library of 140 components, covering 90% of the interface’s needs
        • -
        • Converted icons and some illustrations to vector graphics: ensuring correct display at any zoom level and DPI
        • -
        • Reduced the time it took the team to build a new screen from 2 days to 4 hours by using pre-built components
        • -
        -
        -
        -

        Stack:

        -
          -
        • Desktop IDE
        • -
        • Windows 10/11
        • -
        • Component library
        • -
        +
      3. +
        +

        Primo RPA

        +

        — (2 years and 10 months)·primo-rpa.com

        +
        +

        A Russian enterprise-grade B2B RPA platform: a suite of desktop robot development environments and web services for management, analytics, and ML.
        + I worked as a lead designer on the entire product line, consisting of 6 products.

        +
        +

        AI Server Platform (SaaS)

        +

        A control panel for training, running, testing, and other operations involving neural networks deployed within the company’s internal network.

        +
        +
        +
        Responsibilities
        +
          +
        • Design a web interface for the local LLM control panel. Enable the following scenarios: dataset creation, training of narrowly focused models, rapid testing, and administration of deployment on the client’s local infrastructure.
        • +
        • Improve how Smart OCR is configured for more accurate data extraction from documents of various types
        • +
        • Managing the states of long-running processes: model training, progress, errors, rollback
        • +
        • Preparing interactive prototypes and overseeing implementation
        • +
        +
        +
        +
        Achievements
        +
          +
        • Created an intuitive interface for handling the complex setup of LLM models. This significantly lowered the barrier to entry for users without deep neural network expertise.
        • +
        • Reduced setup time from 3–5 days to 2 hours, based on conversations with users
        • +
        • Designed a document annotation interface that reduced support requests on this topic by 60%
        • +
        • Conducted 8 usability sessions and, based on the results, revised the key model training scenario
        • +
        +
        +
        +
        Stack
        +
          +
        • Figma
        • +
        • React
        • +
        • Ant Design
        • +
        • Hope UI
        • +
        • LLM core
        • +
        • Smart OCR
        • +
        +
        -
      4. - -
        - -
        -

        Robot Automation Studio (Linux)

        -

        An environment for developing and debugging robots for business process automation.

        -
        -
        -

        Responsibilities:

        -
          -
        • Adapting the Studio design for the Linux version using the Avalonia framework
        • -
        • Designing components while taking into account the framework’s technical limitations
        • -
        • Synchronizing the visual language between the Windows and Linux versions of the product
        • -
        • Collaborating with the development team to determine what is technically feasible in Avalonia and what requires workarounds
        • -
        • Preparing component behavior specifications for implementation
        • -
        -
        -
        -

        Achievements:

        -
          -
        • Compiled an extensive library of 95 components for Avalonia, which did not exist in the project before I joined
        • -
        • Ensured product consistency across two platforms with different technology stacks
        • -
        • Reduced the number of visual discrepancies between versions from several dozen to just a few isolated cases
        • -
        • Provided the Linux version team with a ready-made set of solutions instead of having to design each screen from scratch
        • -
        -
        -
        -

        Stack:

        -
          -
        • Avalonia
        • -
        • .NET
        • -
        • Linux
        • -
        + +
        +

        Robot Automation Studio (Windows)

        +

        An environment for developing and debugging robots for business process automation.

        +
        +
        +
        Responsibilities
        +
          +
        • Designing the interface for a professional desktop IDE: workspace, toolbars, process tree, debugger
        • +
        • Developing the product’s component library and visual language
        • +
        • Designing debugging scenarios: breakpoints, step-by-step execution, variable inspection
        • +
        • Designing support for large activity trees and nesting
        • +
        • Working in tandem with the development team on component implementation, providing author supervision
        • +
        • Conducting regular design reviews within the team
        • +
        +
        +
        +
        Achievements
        +
          +
        • Updated the product’s visual language to the Windows 11 standard—components are now a generation more modern
        • +
        • Redesigned dozens of screens and modal windows, bringing them into a single token-based design system.
        • +
        • Built a library of more than 50 reusable components, making it possible to design new functionality scenarios while preserving established behavior patterns
        • +
        • Redrew all legacy raster icons as vectors. This produced a library of over 300 unique icons that display perfectly at any UI scale and DPI
        • +
        • Reduced the time it took the team to build a new screen from 2 days to 4 hours by using pre-built components
        • +
        +
        +
        +
        Stack
        +
          +
        • Desktop IDE
        • +
        • Windows 10/11
        • +
        • Figma
        • +
        • AI tools
        • +
        • DevExpress UI
        • +
        • Handy Controls
        • +
        +
        -
        - -
        - -
        -

        Idea Hub Dashboard (SaaS)

        -

        Enables the collection and analysis of employee suggestions, performance evaluation, and monitoring of automation implementation status. Analytics on key performance indicators and a high-level view of automation.

        -
        -
        -

        Responsibilities:

        -
          -
        • Designing dashboards and analytical views for robotization KPIs
        • -
        • Managing the idea lifecycle: submission → evaluation → prioritization → implementation → impact measurement
        • -
        • Section information architecture, working with dense tables, filters, and bulk operations
        • -
        • Designing a role-based model: employee, analyst, manager
        • -
        • Selecting data visualization types for specific management questions
        • -
        -
        -
        -

        Achievements:

        -
          -
        • Integrated high-level analytics and work on a specific idea into a single continuous workflow without switching between sections
        • -
        • Designed data visualizations so that managers can see the impact of automation without having to manually export data to Excel
        • -
        • Reduced the process from idea submission to evaluation from 6 steps to 3
        • -
        • Designed 12 analytics widgets covering customers’ key questions about the ROI of automation
        • -
        -
        -
        -

        Stack:

        -
          -
        • Analytics / Dashboards
        • -
        • KPIs
        • -
        • Data Visualization
        • -
        + +
        +

        Robot Automation Studio (Linux)

        +

        An environment for developing and debugging robots for business process automation.

        +
        +
        +
        Responsibilities
        +
          +
        • Designing the IDE interface for Linux, based on the selected feature set and the already implemented Windows version
        • +
        • Designing components with the technical constraints of the Avalonia Suki UI framework in mind
        • +
        • Preparing component behavior specifications for implementation
        • +
        +
        +
        +
        Achievements
        +
          +
        • Built a component library based on Suki UI that lets me quickly assemble interfaces in Figma and hand them off to developers
        • +
        • Developed a product style that meets international standards, which will support expansion into foreign markets
        • +
        • Handed developers design instructions for assembling screens, so they can build interfaces for new features on their own and ship releases according to the roadmap
        • +
        +
        +
        +
        Stack
        +
          +
        • Avalonia
        • +
        • Suki UI
        • +
        • Figma
        • +
        • AI tools
        • +
        • Cursor IDE
        • +
        • MobaXterm RDP
        • +
        • Linux
        • +
        +
        -
        - -
        - -
        -

        Orchestrator Automation Management Tool (SaaS)

        -

        Ensures seamless system operation and management of hundreds of robots: launching, monitoring, and management.

        -
        -
        -

        Responsibilities:

        -
          -
        • Designing a management interface for a fleet of hundreds of robots: schedules, queues, priorities, and monitoring
        • -
        • Developing state management and error handling for bulk launches
        • -
        • Designing a system for notifications and alerts regarding failures
        • -
        • Working with complex tables: sorting, filtering, bulk actions, saved views
        • -
        • Prototyping complex scenarios for validation prior to development
        • -
        -
        -
        -

        Achievements:

        -
          -
        • Designed a system to manage hundreds of objects so that the operator doesn’t get lost in the scale: from the big picture to a specific robot in just 2 clicks
        • -
        • Aligned the service with a unified design system alongside the rest of the product line’s web products
        • -
        • Reduced operator response time to robot failures from 12 to 4 minutes thanks to a redesigned alert system
        • -
        • Consolidated 5 different robot list views into a single customizable one
        • -
        -
        -
        -

        Stack:

        -
          -
        • Monitoring
        • -
        • Schedules / Queues
        • -
        • Notifications / Alerts
        • -
        + +
        +

        Idea Hub Dashboard (SaaS)

        +

        Enables the collection and analysis of employee suggestions, performance evaluation, and monitoring of automation implementation status. Analytics on key performance indicators and a high-level view of automation.

        +
        +
        +
        Responsibilities
        +
          +
        • Designing dashboards and analytical views for robotization KPIs
        • +
        • Managing the idea lifecycle: submission → evaluation → prioritization → implementation → impact measurement
        • +
        • Section information architecture, working with dense tables, filters, and bulk operations
        • +
        • Designing a role-based model: employee, analyst, manager
        • +
        • Selecting data visualization types for specific management questions
        • +
        +
        +
        +
        Achievements
        +
          +
        • Integrated high-level analytics and work on a specific idea into a single continuous workflow without switching between sections
        • +
        • Designed data visualizations so that managers can see the impact of automation without having to manually export data to Excel
        • +
        • Reduced the process from idea submission to evaluation from 6 steps to 3
        • +
        • Designed 12 analytics widgets covering customers’ key questions about the ROI of automation
        • +
        +
        +
        +
        Stack
        +
          +
        • Figma
        • + + +
        +
        -
        - -
        - -
        -

        Q&A Portal (WEB)

        -

        A platform for posting questions and receiving answers from support

        -
        -
        -

        Responsibilities:

        -
          -
        • Designing workflows for posting questions, providing answers, and searching the accumulated knowledge base
        • -
        • Designing the portal interface based on the company’s common design system
        • -
        • Developing a role model: user, expert, support team, moderator
        • -
        • Designing search mechanics and suggestions for similar questions when posting
        • -
        -
        -
        -

        Achievements:

        -
          -
        • Launched the portal using off-the-shelf components from the design system in 3 weeks instead of the planned 8
        • -
        • Reduced the support workload by approximately 25% by reusing existing answers
        • -
        • The suggestion feature for similar questions reduced duplicate questions by 45%
        • -
        • Ensured visual consistency with other products in the line—the portal does not look like a third-party service
        • -
        -
        -
        -

        Stack:

        -
          -
        • Web portal
        • -
        • Design system
        • -
        • Knowledge base
        • -
        + +
        +

        Orchestrator Automation Management Tool (SaaS)

        +

        Ensures seamless system operation and management of hundreds of robots: launching, monitoring, and management.

        +
        +
        +
        Responsibilities
        +
          +
        • Designing a management interface for a fleet of hundreds of robots: schedules, queues, priorities, and monitoring
        • +
        • Developing state management and error handling for bulk launches
        • +
        • Designing a system for notifications and alerts regarding failures
        • +
        • Working with complex tables: sorting, filtering, bulk actions, saved views
        • +
        • Prototyping complex scenarios for validation prior to development
        • +
        +
        +
        +
        Achievements
        +
          +
        • Designed a system to manage hundreds of objects so that the operator doesn’t get lost in the scale: from the big picture to a specific robot in just 2 clicks
        • +
        • Aligned the service with a unified design system alongside the rest of the product line’s web products
        • +
        • Reduced operator response time to robot failures from 12 to 4 minutes thanks to a redesigned alert system
        • +
        • Consolidated 5 different robot list views into a single customizable one
        • +
        +
        +
        +
        Stack
        +
          +
        • Figma
        • +
        • Ant Design
        • +
        • Storybook
        • +
        • AI tools
        • + + +
        +
        -
        - -
        - -
        -

        Company-wide

        -
          -
        • I initiated a visual refresh of the entire product line—the company decided to redesign the products upon my arrival
        • -
        • I developed and implemented a unified design system for web services, integrating the company’s brand identity with the new interface structure
        • -
        • The design system was adopted by four product teams; it includes 210 components and theming tokens
        • -
        • Reduced the average time to prepare mockups across the product line by 35%
        • -
        • Created and maintained a UI kit to ensure consistency and accelerate development
        • -
        • Conducted more than 20 user studies and usability sessions during my tenure
        • -
        • Oversaw implementation, participated in design reviews, product discussions, and release planning
        • -
        • Served as the sole lead designer for an entire product line consisting of 6 products and two platforms
        • -
        -
        -
        - -
        - -
        -
        -

        Lunacy (Icons8)

        -

        July 2022 – January 2023 (7 months) · icons8.com/lunacy

        -
        -

        A graphic editor for working on interface designs and other mockups. Similar to Sketch App and Figma.

        - -
        -
        -
        -

        Responsibilities:

        -
          -
        • Designing the graphic editor’s interface: tools, property panels, working with the canvas and layers
        • -
        • Documenting solutions as user flows and handing them off to developers
        • -
        • Creating complex interactive prototypes in Protopie to demonstrate tool behavior
        • -
        • Illustrating missing icons in the product’s style
        • -
        • Making suggestions for improving the editor’s functionality
        • -
        • Participating in discussions about product solutions with the team
        • -
        -
        -
        -

        Achievements:

        -
          -
        • Designed 6 functional blocks for the editor, including work with components and styles
        • -
        • Created 15+ prototypes in Protopie, which helped eliminate unsuccessful solutions before development
        • -
        • Some of my feature suggestions were included in product releases
        • -
        • Designed over 60 icons to complement the editor’s system set
        • -
        • Worked on a product for a professional audience of designers, where the requirements for interface details are higher than usual
        • -
        -
        -
        -

        Stack:

        -
          -
        • Protopie
        • -
        • Graphics editor
        • -
        • Icons / Illustrations
        • -
        + +
        +

        Q&A Portal (WEB)

        +

        A platform for posting questions and receiving answers from support

        +
        +
        +
        Responsibilities
        +
          +
        • Designing workflows for posting questions, providing answers, and searching the accumulated knowledge base
        • +
        • Designing the portal interface under the constraints of the PHP engine used for a QnA-type site.
        • +
        • Developing a role model: user, expert, support team, moderator
        • +
        • Designing search mechanics and suggestions for similar questions when posting
        • +
        +
        +
        +
        Achievements
        +
          +
        • Launched the portal using off-the-shelf components from the design system in 3 weeks instead of the planned 8
        • +
        • Reduced the support workload by approximately 25% by reusing existing answers
        • +
        • The suggestion feature for similar questions reduced duplicate questions by 45%
        • +
        • Ensured visual consistency with other products in the line—the portal does not look like a third-party service
        • +
        +
        +
        +
        Stack
        +
          +
        • PHP QnA Engine
        • +
        • Figma
        • +
        • Design system
        • + +
        +
        -
        -
        + +
        +

        Company-wide

        +
          + +
        • I developed and implemented a unified design system for web services, integrating the company’s brand identity with the new interface structure
        • + +
        • Reduced the average time to prepare mockups across the product line by 35%
        • +
        • Created and maintained a UI kit to ensure consistency and accelerate development
        • +
        • Conducted more than 20 user studies and usability sessions during my tenure
        • +
        • Oversaw implementation, participated in design reviews, product discussions, and release planning
        • +
        • Hired 4 interface designers for different company projects
        • +
        • Conducted more than 30 interviews, including introducing the WhiteBoard Interview format
        • +
        • Developed test assignments tailored to the needs of specific roles and tasks
        • +
        • Introduced an internal video call system based on Jitsi within the company’s internal network, together with the technical support department
        • + +
        +
        + -
        - -
        -
        -

        MANU Video Game Maker

        -

        January 2019 — December 2021 (3 years)·manu.co

        -
        -

        A game engine for creating video games without writing code.

        - -
        -
        -
        -

        Responsibilities:

        -
          -
        • End-to-end product design of the engine: from interaction concepts to the final UI
        • -
        • Designing interface behavior for complex user scenarios
        • -
        • User research: observation, in-depth interviews, surveys
        • -
        • Creating user personas and empathy maps
        • -
        • Working with product analytics and metrics tied to user scenarios
        • -
        • Layout of the website’s homepage on Tilda, designing the site’s information architecture together with the team
        • -
        • Supervising the work of the web graphic designer
        • -
        • Hiring for the product department: conducting interviews and selecting specialists
        • -
        • Leading the department and establishing workflows for the entire product team
        • -
        • Overseeing the creation of user documentation
        • -
        • Implementing automation tools (Integromat, Zapier) for internal tasks
        • -
        -
        -
        -

        Achievements:

        -
          -
        • Led a large-scale redesign of the entire program: established a fundamentally new concept and style
        • -
        • Designed the interface behavior for over 100 complex user scenarios
        • -
        • Designed the product’s design system from scratch: 120 components
        • -
        • Received a lot of positive, and in some cases enthusiastic, user feedback—the product became much easier to navigate
        • -
        • Onboarding completion rates increased from 34% to 58% following the redesign
        • -
        • Conducted 25 in-depth interviews and 4 rounds of surveys, and revised 3 key scenarios based on the results
        • -
        • Hired 4 specialists for the product department and grew from a designer to a team lead
        • -
        • Established departmental processes: design reviews, backlog management, and handoff to development
        • -
        • Automated the team’s internal routines, freeing up time for product tasks
        • -
        -
        -
        -

        Stack:

        -
          -
        • Tilda
        • -
        • Integromat / Zapier
        • -
        • User research
        • -
        +
      5. +
        +

        Lunacy (Icons8)

        +

        July 2022 – January 2023 (7 months) · icons8.com/lunacy

        +
        +

        A graphic editor for working on interface designs and other mockups. Similar to Sketch App and Figma.

        +
        +
        +
        +

        Responsibilities

        +
          +
        • Designing the graphic editor’s interface: tools, property panels, working with the canvas and layers
        • +
        • Documenting solutions as user flows and handing them off to developers
        • +
        • Creating complex interactive prototypes in Protopie to demonstrate tool behavior
        • +
        +
        +
        +

        Achievements

        +
          +
        • Designed 6 functional blocks for the editor, including work with components and styles
        • +
        • Built a Protopie prototype for a new feature: editing multi-layered realistic object shadows with complex behavior logic, almost indistinguishable from the production solution. Not counting smaller, simple prototypes.
        • +
        • Validated 3 hypotheses for improving the editor with real users. 1 made it into the release.
        • +
        +
        +
        +

        Stack

        +
          +
        • Protopie
        • +
        • Figma
        • +
        • Design system
        • +
        • Avalonia Custom UI
        • +
        • Windows
        • +
        • Linux
        • +
        • macOS
        • +
        +
        -
      6. -
        + -
        - -
        -
        -

        Aegees Messenger

        -

        October 2017 — December 2018 (1 year and 3 months)·aegees.com

        -
        -

        A cross-platform messenger with secure storage and audio calls.

        - -
        -
        -
        -

        Responsibilities:

        -
          -
        • Designing the messenger for five platforms simultaneously: Android, iOS, macOS, Windows, and Linux
        • -
        • Developing use cases for secure storage and audio calls
        • -
        • Designing scenarios for registration, encryption, and access recovery
        • -
        • Adapting a unified product logic to each platform’s guidelines
        • -
        • Supervising the work of international illustrators in the preparation of graphic assets
        • -
        • Preparation of materials for app stores
        • -
        -
        -
        -

        Achievements:

        -
          -
        • Developed a unified visual language for the product while adhering to the guidelines of five platforms simultaneously
        • -
        • Designed over 90 screens across five platform versions
        • -
        • Ensured a steady flow of graphic assets from external contractors without compromising the design style
        • -
        • Simplified the secure storage workflow so that people without technical training could use it
        • -
        • Worked in the sensitive areas of privacy and security, where a single interface error can cost user trust
        • -
        -
        -
        -

        Stack:

        -
          -
        • Android
        • -
        • iOS
        • -
        • macOS
        • -
        • Windows
        • -
        • Linux
        • -
        +
      7. +
        +

        MANU Video Game Maker

        +

        — (3 years)·manu.co

        +
        +

        A game engine for creating video games without writing code.

        +
        +
        +
        +

        Responsibilities

        +
          +
        • End-to-end product design of the engine: from interaction concepts to the final UI
        • +
        • Designing interface behavior for complex user scenarios
        • +
        • User research: observation, in-depth interviews, surveys
        • +
        • Creating user personas and empathy maps
        • +
        • Working with product analytics and metrics tied to user scenarios
        • +
        • Layout of the website’s homepage on Tilda, designing the site’s information architecture together with the team
        • +
        • Supervising the work of the web graphic designer
        • +
        • Hiring for the product department: conducting interviews and selecting specialists
        • +
        • Leading the department and establishing workflows for the entire product team
        • +
        • Overseeing the creation of user documentation
        • +
        • Implementing automation tools (Integromat, Zapier) for internal tasks
        • +
        +
        +
        +

        Achievements

        +
          +
        • Led a large-scale redesign of the entire program: established a fundamentally new concept and style
        • +
        • Designed the interface behavior for over 100 complex user scenarios
        • +
        • Designed the product’s design system from scratch: 120 components
        • +
        • Received a lot of positive, and in some cases enthusiastic, user feedback—the product became much easier to navigate
        • +
        • Onboarding completion rates increased from 34% to 58% following the redesign
        • +
        • Conducted 25 in-depth interviews and 4 rounds of surveys, and revised 3 key scenarios based on the results
        • +
        • Hired 4 specialists for the product department and grew from a designer to a team lead
        • +
        • Established departmental processes: design reviews, backlog management, and handoff to development
        • +
        • Automated the team’s internal routines, freeing up time for product tasks
        • +
        +
        +
        +

        Stack

        +
          + +
        • Zapier
        • +
        • Figma
        • +
        • Miro
        • +
        • Mailchimp
        • +
        • Windows
        • +
        • Notion
        • +
        • Airtable
        • +
        +
        -
      8. -
        + -
        - -
        -
        -

        Orion Innovation (formerly MERA)

        -

        July 2016 – October 2017 (1 year and 4 months)·orioninnovation.com

        -
        -

        Software development for external clients.

        - -
        -
        -
        -

        Responsibilities:

        -
          -
        • Worked in a design department with up to 8 people
        • -
        • Creating user personas and mapping product functionality based on user needs
        • -
        • Creating wireframes and designing the final UI
        • -
        • Designing use cases, screen maps, and micro-animation demos
        • -
        • Preparing mood boards and design concepts, and discussing them with clients
        • -
        • Preparing and delivering presentations on design concepts
        • -
        • Turning mockups into prototypes, writing scripts, and conducting qualitative usability testing
        • -
        • Making revisions based on test results
        • -
        • Overseeing the implementation of designs by developers
        • -
        • Participating in design reviews: analyzing colleagues’ work and defending your own decisions
        • -
        • Direct communication with international clients to discuss design and receive project briefs
        • -
        -
        -
        -

        Achievements:

        -
          -
        • Conducted 10 usability testing sessions, from writing the test script to implementing changes
        • -
        • Learned to work with the Smart TV platform, which was new to me, and brought the project to successful release in the app store
        • -
        • Communicated directly with international clients, without intermediaries
        • -
        • Actively participated in improving the company’s design department workflow
        • -
        • Completed the full product design cycle on 5 client projects
        • -
        -
        -
        -

        Stack:

        -
          -
        • Smart TV
        • -
        • Usability testing
        • -
        • Mood boards / design concepts
        • -
        +
      9. +
        +

        Aegees Messenger

        +

        — (1 year and 3 months)·aegees.com

        +
        +

        A cross-platform messenger with secure storage and audio calls.

        +
        +
        +
        +

        Responsibilities

        +
          +
        • Designing the messenger for five platforms simultaneously: Android, iOS, macOS, Windows, and Linux
        • +
        • Developing use cases for secure storage and audio calls
        • +
        • Designing scenarios for registration, encryption, and access recovery
        • +
        • Adapting a unified product logic to each platform’s guidelines
        • +
        • Supervising the work of international illustrators in the preparation of graphic assets
        • +
        • Preparation of materials for app stores
        • +
        +
        +
        +

        Achievements

        +
          +
        • Developed a unified visual language for the product while adhering to the guidelines of five platforms simultaneously
        • +
        • Designed over 90 screens across five platform versions
        • +
        • Ensured a steady flow of graphic assets from external contractors without compromising the design style
        • +
        • Simplified the secure storage workflow so that people without technical training could use it
        • +
        • Worked in the sensitive areas of privacy and security, where a single interface error can cost user trust
        • +
        +
        +
        +

        Stack

        +
          +
        • Android
        • +
        • iOS
        • +
        • macOS
        • +
        • Windows
        • +
        • Linux
        • +
        +
        -
      10. -
        + -
        - -
        -
        -

        SpaceshipApps Studio

        -

        June 2015 — June 2016 (1 year and 1 month)·spaceshipapps.ru

        -
        -

        Mobile app and website development studio.

        - -
        -
        -
        -

        Responsibilities:

        -
          -
        • Designing mobile and web products as part of the studio’s workflow
        • -
        • Worked across various sectors: social gaming, beauty services, food delivery, voice interfaces, legal services, and collaborative tools
        • -
        • Responsive web design and design of administrative dashboards
        • -
        • Illustrating icons and preparing graphics for projects
        • -
        • Preparing mockups for handoff to development
        • -
        -
        -
        -

        Achievements:

        -
          -
        • Launched 6 products in one year: a geolocation-based social game with real-world quests, an app for booking beauty professionals, a food delivery service, a voice-based word game, a website and admin panel for a copyright registration service, and a mobile “whiteboard” for collaboration
        • -
        • Learned to quickly get up to speed in new subject areas and maintain quality while keeping up with the studio’s fast pace
        • -
        • Handled the full range of tasks: mobile, web, admin panels, and graphics
        • -
        • Laid the groundwork for transitioning from execution-focused design to product-focused design
        • -
        -
        -
        -

        Stack:

        -
          -
        • Mobile
        • -
        • Web
        • -
        • Dashboards
        • -
        • Graphics
        • -
        +
      11. +
        +

        Orion Innovation (formerly MERA)

        +

        July 2016 – October 2017 (1 year and 4 months)·orioninnovation.com

        +
        +

        Software development for external clients.

        +
        +
        +
        +

        Responsibilities

        +
          +
        • Worked in a design department with up to 8 people
        • +
        • Creating user personas and mapping product functionality based on user needs
        • +
        • Creating wireframes and designing the final UI
        • + +
        • Preparing mood boards and design concepts, and discussing them with clients
        • + +
        • Turning mockups into prototypes, writing scripts, and conducting qualitative usability testing
        • + + +
        • Participating in design reviews: analyzing colleagues’ work and defending your own decisions
        • + +
        +
        +
        +

        Achievements

        +
          +
        • Conducted 10 usability testing sessions, from writing the test script to implementing changes
        • +
        • Learned to work with the Smart TV platform, which was new to me, and brought the project to successful release in the app store
        • +
        • Conducted research and reverse-engineering of app design for the Roku TV platform and created a client app design development workflow that includes: idea formation, clickable prototype development, usability testing on the actual device, and design control in the app built by our developers
        • +
        • Communicated directly with international clients, without intermediaries
        • +
        • Actively participated in improving the company’s design department workflow
        • +
        • Introduced the team to using Miro (ex. Realtime Board) for storing research artifacts
        • + +
        +
        +
        +

        Stack

        +
          +
        • Sketch
        • +
        • Miro
        • +
        • Android
        • +
        • iOS
        • +
        • ROKU TV Box
        • +
        • Smart TV
        • +
        • Marvel App
        • +
        • ProtoPie
        • +
        • Framer
        • + + +
        +
        -
      12. -
        + -
        +
      13. +
        +

        SpaceshipApps Studio

        +

        — (1 year and 1 month)·spaceshipapps.ru

        +
        +

        Mobile app and website development studio.

        +
        +
        +
        +

        Responsibilities

        +
          +
        • Designing mobile and web products as part of the studio’s workflow
        • +
        • Worked across various sectors: social gaming, beauty services, food delivery, voice interfaces, legal services, and collaborative tools
        • +
        • Responsive web design and design of administrative dashboards
        • +
        • Illustrating icons and preparing graphics for projects
        • +
        • Preparing mockups for handoff to development
        • +
        +
        +
        +

        Achievements

        +
          +
        • Launched 6 products in one year: a geolocation-based social game with real-world quests, an app for booking beauty professionals, a food delivery service, a voice-based word game, a website and admin panel for a copyright registration service, and a mobile “whiteboard” for collaboration
        • +
        • Learned to quickly get up to speed in new subject areas and maintain quality while keeping up with the studio’s fast pace
        • +
        • Handled the full range of tasks: mobile, web, admin panels, and graphics
        • +
        • Laid the groundwork for transitioning from execution-focused design to product-focused design
        • +
        +
        +
        +

        Stack

        +
          +
        • Mobile
        • +
        • Web
        • +
        • Adobe Photoshop
        • +
        • After Effects
        • +
        • Adobe Illustrator
        • -

          Skills

          -
          + + +
        +
        +
        +
        +
      14. +
      +
      + +
      +

      Skills

      +
      -

      Design

      -

      UX/UI, product design, information architecture, responsive design, design systems

      +
      Design
      +
      UX/UI, product design, information architecture, responsive design, design systems
      -

      Research

      -

      Interviews, surveys, usability testing, JTBD, empathy maps, conversion, retention, NPS

      +
      Research
      +
      Interviews, surveys, usability testing, JTBD, empathy maps, conversion, retention, NPS
      -

      Tools

      -

      Figma, Protopie, Sketch, Adobe Creative Suite, Tilda, AI tools

      +
      Management
      +
      Team building, Agile, Kanban, project supervision, working with stakeholders
      -

      Management

      -

      Team building, Agile, Kanban, project supervision, working with stakeholders

      +
      Tools
      +
      Figma, Protopie, Sketch, Adobe Creative Suite, Storybook
      -
      +
      +
      AI Tools
      +
      Hermes Agent, Perplexity, Cursor IDE, Zed IDE, Open Design, Codex, Claude Code
      +
      + + -
      +
      +

      About Me

      +

      + I specialize in SaaS products and desktop applications. I design clear, scalable, and efficient interfaces for complex workflows, so users solve their tasks faster and the product becomes more convenient and useful. +

      +

      + I work across every stage of product design: researching user needs, shaping information architecture, designing user flows, building interactive prototypes with vibe coding, and creating scalable design systems with Figma + Storybook. +

      +

      + I stay active in the community: I run the Telegram channel “Design Isn’t Pizza,” share resources on Figma Community, spoke about voice skill analytics at a Yandex meetup, and talked about a designer’s toolkit at a business forum. I’ve won hackathons more than once. +

      +
      -

      About Me

      -

      - I’ve been in design for over 10 years, and in recent years I’ve focused on product design for complex B2B products. I work at the intersection of design and product management: I conduct research, formulate hypotheses and features, help with prioritization, and participate in release planning. -

      -

      - I love diving into complex topics and making them understandable—which is why I feel right at home with products like IDEs, orchestration tools, and ML dashboards, where a typical designer might find the work boring or intimidating. -

      -

      - I don’t wait for someone else to solve a problem—I build my own tools. I’ve created a private AI plugin for Figma, automate processes using n8n and PostgreSQL, and turn my ideas into working products through AI-assisted development. My skills for Alisa have attracted over 37,000 and 33,000 users, and the Slider Set file for designers has been downloaded more than 20,000 times. -

      -

      - I’m active in the community: I run the Telegram channel “Design Isn’t Pizza,” share useful resources on the Figma Community, gave a talk on analytics at a Yandex meetup, and have won hackathons—my most memorable victory was at the Yandex.I’m currently in St. Petersburg working on a QR code payment app. -

      -

      - English—B1. I work remotely and communicate smoothly with a distributed team. -

      -
      +
      {{> footer}} diff --git a/src/pages/resume.html b/src/pages/resume.html index a23122a..6223175 100644 --- a/src/pages/resume.html +++ b/src/pages/resume.html @@ -9,220 +9,23 @@ /> Резюме — Николай Мамадаев {{> head-links}} - {{> header-minimal}} {{> fab-stack-resume}}
      -
      -
      - Николай Мамадаев +
      +
      +
      + Николай Мамадаев

      Резюме

      Николай Мамадаев

      -

      Senior UX/UI Designer, Product Designer

      +

      Senior UX/UI Designer
      + Product Designer
      + AI Designer

      -
      - -
      +
      @@ -230,8 +33,8 @@
      mamadaevv.site
      -
      Вилка по ЗП
      -
      250 000 – 310 000 руб.
      +
      Зарплата
      +
      от 250 000 ₽
      Формат работы
      @@ -245,567 +48,579 @@
      Соц.сети
      @mamadaevv
      +
      +
      Знание языков
      +
      Английский (B2)
      +
      - -
      - - -

      О себе

      -

      - В дизайне больше 10 лет, последние годы — продуктовый дизайн сложных B2B-продуктов. Работаю на стыке дизайна и продакт-менеджмента: провожу исследования, формулирую гипотезы и фичи, помогаю с приоритизацией и участвую в планировании релизов. -

      -

      - Люблю разбираться в сложном и делать его понятным — поэтому мне комфортно в продуктах вроде IDE, оркестраторов и ML-панелей, где обычному дизайнеру скучно или страшно. -

      -

      - Не жду, пока задачу сделает кто-то другой: пишу себе инструменты сам. Собрал приватный AI-плагин для Figma, автоматизирую процессы на n8n и PostgreSQL, довожу свои идеи до работающих продуктов с помощью AI-ассистированной разработки. Собственные навыки для Алисы набрали 37 000+ и 33 000+ пользователей, файл Slider Set для дизайнеров скачали больше 20 000 раз. -

      -

      - Участвую в жизни сообщества: веду Telegram-канал «Дизайн не пицца», выкладываю полезности в Figma Community, выступал на митапе Яндекса с докладом по аналитике, побеждал на хакатонах — самая приятная победа на хакатоне Яндекс.Денег в Петербурге за приложение оплаты по QR-коду. -

      -

      - Английский — B1. Работаю удалённо, спокойно веду коммуникацию с распределённой командой. -

      - -
      -

      Опыт работы

      - -
      - -
      -
      -

      Astratech

      -

      Январь 2026 — Настоящее время

      -
      -

      Разработка и поддержка цифровых систем и инструментов для повышения эффективности сотрудников.

      - -
      -
      -
      -

      Обязанности:

      -
        -
      • Занимался дизайном интерфейсов
      • -
      -
      -
      -

      Достижения:

      -
        -
      • Успешно закрывал входящие задачи
      • -
      -
      -
      -

      Стэк:

      -
        -
      • Figma
      • -
      • HTML/CSS
      • -
      • AI/LLM
      • -
      -
      -
      -
      -
      +
      +

      О себе

      +

      + Специализируюсь на SaaS-продуктах и desktop-приложениях. Проектирую понятные, масштабируемые и эффективные интерфейсы для сложных рабочих процессов — чтобы пользователи быстрее решали свои задачи, а продукт становился удобнее и полезнее. +

      +

      + Работаю на всех этапах продуктового дизайна: изучаю потребности пользователей, формирую информационную архитектуру, проектирую пользовательские сценарии, создаю интерактивные прототипы используя вайбкоддинг и масштабируемые дизайн-системы в связке Figma + Storybook. +

      +

      + Участвую в жизни сообщества: веду Telegram-канал «Дизайн не пицца», выкладываю полезности в Figma Community, выступал на митапе Яндекса с докладом про аналитику голосовых навыков и на бизнес-форуме с рассказом про инструменты дизайнера. Неоднократно побеждал на хакатонах. +

      +
      -
      -
      -

      Primo RPA

      -

      Февраль 2023 — Ноябрь 2025 (2 года и 10 месяцев)·primo-rpa.com

      -
      -

      Российская RPA-платформа корпоративного уровня: линейка из desktop-среды разработки роботов и веб-сервисов управления, аналитики и ML. Работал ведущим дизайнером на всю продуктовую линейку из 6 продуктов.

      +
      +

      Опыт работы

      +
        +
      1. +
        +

        Astratech

        +

        — Настоящее время

        +
        +

        Разработка и поддержка цифровых систем и инструментов для повышения эффективности сотрудников.

        -
        -

        AI Server platform (Saas)

        -

        Панель управления для обучения/запуска/тестирования и других операций с нейросетями развёрнутыми внутри контура компании.

        -
        -
        -

        Обязанности:

        -
          -
        • Проектирование интерфейса управления моделями: обучение, запуск, тестирование, версионирование, мониторинг
        • -
        • Проработка сценариев работы с Smart OCR — извлечение данных из документов различных типов
        • -
        • Проектирование разметки документов и валидации результатов распознавания
        • -
        • Работа с состояниями долгих процессов: обучение модели, прогресс, ошибки, откат
        • -
        • Подготовка интерактивных прототипов и авторский надзор за реализацией
        • -
        • Проведение интервью с ML-инженерами и бизнес-пользователями для сверки моделей поведения
        • -
        -
        -
        -

        Достижения:

        -
          -
        • Упаковал сложную ML-логику в интерфейс, понятный не только ML-инженеру, но и бизнес-аналитику без технического бэкграунда
        • -
        • Свёл работу с моделями к единому предсказуемому сценарию из 4 шагов вместо 9 разрозненных экранов
        • -
        • Сократил время настройки новой модели с 40 до 15 минут по результатам замеров на тестировании
        • -
        • Спроектировал интерфейс разметки документов, который снял 60% обращений в поддержку по этой теме
        • -
        • Провёл 8 юзабилити-сессий, по итогам переработал ключевой сценарий обучения модели
        • -
        -
        -
        -

        Стэк:

        -
          -
        • ML / нейросети
        • -
        • Smart OCR
        • -
        +
        +
        +
        +

        Обязанности

        +
          +
        • Создание готовых к продакшену интерфейсов
        • +
        • Разбор идей и концепций и трансформация их в дизайнерские задачи
        • +
        +
        +
        +

        Достижения

        +
          +
        • Реализовал настроенную среду доставки интерфейсов до продакшена
        • +
        • Провёл более 15 тестов гипотез на рабочих прототипах без привлечения отдела разработки
        • +
        • Ускорил процесс обработки результатов пользовательского тестирования за счёт применения AI инструментов (суммаризация, классификация, трансрибация)
        • +
        +
        +
        +

        Стэк

        +
          +
        • Figma
        • +
        • HTML/CSS/JS
        • +
        • AI/LLM
        • +
        • GitHub
        • +
        • Gitea
        • +
        • Coolify
        • +
        • CI/CD
        • +
        • Hermes Agent
        • +
        • Zed IDE
        • +
        +
        -
        +
      2. -
        - -
        -

        Robot automation studio (Windows)

        -

        Среда для разработки и отладки роботов для автоматизации бизнес-процессов.

        -
        -
        -

        Обязанности:

        -
          -
        • Проектирование интерфейса профессиональной desktop-IDE: рабочая область, панели инструментов, дерево процесса, отладчик
        • -
        • Развитие библиотеки компонентов и визуального языка продукта
        • -
        • Проработка сценариев отладки: точки останова, пошаговое выполнение, просмотр переменных
        • -
        • Проектирование работы с большими деревьями активностей и вложенностью
        • -
        • Работа в паре с разработкой по реализации компонентов, авторский надзор
        • -
        • Ведение регулярных дизайн-ревью внутри команды
        • -
        -
        -
        -

        Достижения:

        -
          -
        • Обновил визуальный язык продукта до уровня Windows 10/11 — компоненты стали на поколение современнее
        • -
        • Переработал 80+ экранов и диалогов, приведя их к единой сетке и типографике
        • -
        • Собрал библиотеку из 140 компонентов, закрывшую 90% потребностей интерфейса
        • -
        • Перевёл иконки и часть иллюстраций на векторную графику: корректное отображение при любом масштабировании и DPI
        • -
        • Сократил время сборки нового экрана командой с 2 дней до 4 часов за счёт готовых компонентов
        • -
        -
        -
        -

        Стэк:

        -
          -
        • Desktop IDE
        • -
        • Windows 10/11
        • -
        • Компонентная библиотека
        • -
        +
      3. +
        +

        Primo RPA

        +

        — (2 года и 10 месяцев)·primo-rpa.com

        +
        +

        Российская B2B RPA-платформа корпоративного уровня: линейка из desktop-среды разработки роботов и веб-сервисов управления, аналитики и ML.
        + Работал ведущим дизайнером на всю продуктовую линейку из 6 продуктов.

        +
        +

        AI Server platform (SaaS)

        +

        Панель управления для обучения/запуска/тестирования и других операций с нейросетями, развёрнутыми внутри контура компании.

        +
        +
        +
        Обязанности
        +
          +
        • Спроектировать web интерфейс панели управления локальных LLM. Реализовать возможность выполнения сценариев: создание датасетов, обучение узконаправленных моделей, быстрое тестирование и администрирование развёртыванием на локальной инфраструктуре клиента.
        • +
        • Улучшить способ конфигурирования работы Smart OCR для более точного извлечения данных из документов различного типа
        • +
        • Работа с состояниями долгих процессов: обучение модели, прогресс, ошибки, откат
        • +
        • Подготовка интерактивных прототипов и авторский надзор за реализацией
        • +
        +
        +
        +
        Достижения
        +
          +
        • Создал интуитивный интерфейс для работы со сложной настройкой LLM моделей. Таким образом существенно снизил порог входа для пользователей без глубокой экспертизы в работе нейросетей.
        • +
        • Сократил время настройки с 3-5 дней до 2 часов по результатам общения с пользователями
        • +
        • Спроектировал интерфейс разметки документов, который снял 60% обращений в поддержку по этой теме
        • +
        • Провёл 8 юзабилити-сессий, по итогам переработал ключевой сценарий обучения модели
        • +
        +
        +
        +
        Стэк
        +
          +
        • Figma
        • +
        • React
        • +
        • Ant Design
        • +
        • Hope UI
        • +
        • LLM core
        • +
        • Smart OCR
        • +
        +
        -
      4. - -
        - -
        -

        Robot automation studio (Linux)

        -

        Среда для разработки и отладки роботов для автоматизации бизнес-процессов.

        -
        -
        -

        Обязанности:

        -
          -
        • Адаптация дизайна Студии под Linux-версию на фреймворке Avalonia
        • -
        • Проектирование компонентов с учётом технических ограничений фреймворка
        • -
        • Синхронизация визуального языка между Windows- и Linux-версиями продукта
        • -
        • Совместная работа с разработкой над тем, что технически реализуемо в Avalonia, а что требует обходных решений
        • -
        • Подготовка спецификаций поведения компонентов для реализации
        • -
        -
        -
        -

        Достижения:

        -
          -
        • Собрал расширенную библиотеку из 95 компонентов для Avalonia, которой в проекте не существовало до меня
        • -
        • Обеспечил единообразие продукта на двух платформах при разных технологических стеках
        • -
        • Сократил количество визуальных расхождений между версиями с нескольких десятков до единичных случаев
        • -
        • Дал команде Linux-версии готовый набор решений вместо дизайна каждого экрана с нуля
        • -
        -
        -
        -

        Стэк:

        -
          -
        • Avalonia
        • -
        • .NET
        • -
        • Linux
        • -
        + +
        +

        Robot automation studio (Windows)

        +

        Среда для разработки и отладки роботов для автоматизации бизнес-процессов.

        +
        +
        +
        Обязанности
        +
          +
        • Проектирование интерфейса профессиональной desktop-IDE: рабочая область, панели инструментов, дерево процесса, отладчик
        • +
        • Развитие библиотеки компонентов и визуального языка продукта
        • +
        • Проработка сценариев отладки: точки останова, пошаговое выполнение, просмотр переменных
        • +
        • Проектирование работы с большими деревьями активностей и вложенностью
        • +
        • Работа в паре с разработкой по реализации компонентов, авторский надзор
        • +
        • Ведение регулярных дизайн-ревью внутри команды
        • +
        +
        +
        +
        Достижения
        +
          +
        • Обновил визуальный язык продукта до уровня Windows 11 — компоненты стали на поколение современнее
        • +
        • Переработал 10-ки экранов и модальных окон, приведя их к единой дизайн-системе основанной на токенах.
        • +
        • Собрал библиотеку из более чем 50-ти компонентов, которые можно переиспользовать и проектировать сценарии нового функционала с сохранением заложенных паттернов поведения
        • +
        • Перерисовал все старые растровые иконки в новые векторные. Таким образом появилась библиотека уникальных иконок количеством более 300 штук. Идеально отображаются на любом масштабе UI и DPI
        • +
        • Сократил время сборки нового экрана командой с 2 дней до 4 часов за счёт готовых компонентов
        • +
        +
        +
        +
        Стэк
        +
          +
        • Desktop IDE
        • +
        • Windows 10/11
        • +
        • Figma
        • +
        • AI инструменты
        • +
        • DevExpress UI
        • +
        • Handy Controls
        • +
        +
        -
        - -
        - -
        -

        Idea Hub Dashboard (Saas)

        -

        Обеспечивает сбор и анализ предложений сотрудников, оценка эффективности и мониторинг статуса реализации автоматизаций. Аналитика по ключевым показателям эффективности и верхнеуровневый взгляд на роботизацию.

        -
        -
        -

        Обязанности:

        -
          -
        • Проектирование дашбордов и аналитических представлений по KPI роботизации
        • -
        • Проработка жизненного цикла идеи: подача → оценка → приоритизация → реализация → замер эффекта
        • -
        • Информационная архитектура раздела, работа с плотными таблицами, фильтрами и массовыми операциями
        • -
        • Проектирование ролевой модели: сотрудник, аналитик, руководитель
        • -
        • Подбор типов визуализации данных под конкретные управленческие вопросы
        • -
        -
        -
        -

        Достижения:

        -
          -
        • Свёл верхнеуровневую аналитику и работу с конкретной идеей в один непрерывный сценарий без переключения между разделами
        • -
        • Спроектировал представление данных так, что руководитель видит эффект от роботизации без ручных выгрузок в Excel
        • -
        • Сократил путь от подачи идеи до её оценки с 6 шагов до 3
        • -
        • Спроектировал 12 виджетов аналитики, покрывающих основные вопросы заказчиков о ROI роботизации
        • -
        -
        -
        -

        Стэк:

        -
          -
        • Аналитика / дашборды
        • -
        • KPI
        • -
        • Визуализация данных
        • -
        + +
        +

        Robot automation studio (Linux)

        +

        Среда для разработки и отладки роботов для автоматизации бизнес-процессов.

        +
        +
        +
        Обязанности
        +
          +
        • Разработка интерфейса IDE для платформы Linux с учётом выбранного функционала на основе реализованной версии под Windows
        • +
        • Проектирование компонентов с учётом технических ограничений фреймворка Avalonia Suki UI
        • +
        • Подготовка спецификаций поведения компонентов для реализации
        • +
        +
        +
        +
        Достижения
        +
          +
        • Собрал библиотеку компонентов основанную на библиотеке Suki UI из которых можно быстро собирать интерфейс в Figma и передавать разработчикам
        • +
        • Разработал стиль программы, которая соответствует международному уровню, что положительно скажется при экспансии зарубежных рынков
        • +
        • Передал дизайн-инструкции по сборке экранов разработчикам, чтобы они могли самостоятельно собирать интерфейс под новые функции и выпускать релизы согласно роадмэп
        • +
        +
        +
        +
        Стэк
        +
          +
        • Avalonia
        • +
        • Suki UI
        • +
        • Figma
        • +
        • AI инструменты
        • +
        • Cursor IDE
        • +
        • MobaXterm RDP
        • +
        • Linux
        • +
        +
        -
        - -
        - -
        -

        Orchestrator Automation Management Tool (Saas)

        -

        Обеспечивает слаженную работу системы и управление сотнями роботов: запуски, мониторинг и менеджмент.

        -
        -
        -

        Обязанности:

        -
          -
        • Проектирование интерфейса управления парком из сотен роботов: расписания, очереди, приоритеты, мониторинг
        • -
        • Проработка состояний и обработки ошибок при массовых запусках
        • -
        • Проектирование системы уведомлений и алертов о сбоях
        • -
        • Работа со сложными таблицами: сортировка, фильтрация, массовые действия, сохранённые представления
        • -
        • Прототипирование сложных сценариев для валидации до начала разработки
        • -
        -
        -
        -

        Достижения:

        -
          -
        • Спроектировал управление сотнями объектов так, что оператор не теряется в масштабе: от общей картины до конкретного робота за 2 клика
        • -
        • Привёл сервис к единой дизайн-системе вместе с остальными веб-продуктами линейки
        • -
        • Сократил время реакции оператора на сбой робота с 12 до 4 минут за счёт переработанной системы алертов
        • -
        • Свёл 5 разных представлений списка роботов к одному настраиваемому
        • -
        -
        -
        -

        Стэк:

        -
          -
        • Мониторинг
        • -
        • Расписания / очереди
        • -
        • Уведомления / алерты
        • -
        + +
        +

        Idea Hub Dashboard (SaaS)

        +

        Обеспечивает сбор и анализ предложений сотрудников, оценка эффективности и мониторинг статуса реализации автоматизаций. Аналитика по ключевым показателям эффективности и верхнеуровневый взгляд на роботизацию.

        +
        +
        +
        Обязанности
        +
          +
        • Проектирование дашбордов и аналитических представлений по KPI роботизации
        • +
        • Проработка жизненного цикла идеи: подача → оценка → приоритизация → реализация → замер эффекта
        • +
        • Информационная архитектура раздела, работа с плотными таблицами, фильтрами и массовыми операциями
        • +
        • Проектирование ролевой модели: сотрудник, аналитик, руководитель
        • +
        • Подбор типов визуализации данных под конкретные управленческие вопросы
        • +
        +
        +
        +
        Достижения
        +
          +
        • Свёл верхнеуровневую аналитику и работу с конкретной идеей в один непрерывный сценарий без переключения между разделами
        • +
        • Спроектировал представление данных так, что руководитель видит эффект от роботизации без ручных выгрузок в Excel
        • +
        • Сократил путь от подачи идеи до её оценки с 6 шагов до 3
        • +
        • Спроектировал 12 виджетов аналитики, покрывающих основные вопросы заказчиков о ROI роботизации
        • +
        +
        +
        +
        Стэк
        +
          +
        • Figma
        • + + +
        +
        -
        - -
        - -
        -

        QnA portal (WEB)

        -

        Площадка для постинга вопросов и получения ответов от службы поддержки

        -
        -
        -

        Обязанности:

        -
          -
        • Проектирование сценариев публикации вопроса, ответа и поиска по накопленной базе знаний
        • -
        • Дизайн интерфейса портала на базе общей дизайн-системы компании
        • -
        • Проработка ролевой модели: пользователь, эксперт, служба поддержки, модератор
        • -
        • Проектирование механики поиска и подсказок похожих вопросов при публикации
        • -
        -
        -
        -

        Достижения:

        -
          -
        • Запустил портал на готовых компонентах дизайн-системы за 3 недели вместо запланированных 8
        • -
        • Снизил нагрузку на поддержку примерно на 25% за счёт переиспользования уже данных ответов
        • -
        • Механика подсказок похожих вопросов сократила количество дублей на 45%
        • -
        • Обеспечил визуальную преемственность с продуктами линейки — портал не выглядит сторонним сервисом
        • -
        -
        -
        -

        Стэк:

        -
          -
        • Веб-портал
        • -
        • Дизайн-система
        • -
        • База знаний
        • -
        + +
        +

        Orchestrator Automation Management Tool (SaaS)

        +

        Обеспечивает слаженную работу системы и управление сотнями роботов: запуски, мониторинг и менеджмент.

        +
        +
        +
        Обязанности
        +
          +
        • Проектирование интерфейса управления парком из сотен роботов: расписания, очереди, приоритеты, мониторинг
        • +
        • Проработка состояний и обработки ошибок при массовых запусках
        • +
        • Проектирование системы уведомлений и алертов о сбоях
        • +
        • Работа со сложными таблицами: сортировка, фильтрация, массовые действия, сохранённые представления
        • +
        • Прототипирование сложных сценариев для валидации до начала разработки
        • +
        +
        +
        +
        Достижения
        +
          +
        • Спроектировал управление сотнями объектов так, что оператор не теряется в масштабе: от общей картины до конкретного робота за 2 клика
        • +
        • Привёл сервис к единой дизайн-системе вместе с остальными веб-продуктами линейки
        • +
        • Сократил время реакции оператора на сбой робота с 12 до 4 минут за счёт переработанной системы алертов
        • +
        • Свёл 5 разных представлений списка роботов к одному настраиваемому
        • +
        +
        +
        +
        Стэк
        +
          +
        • Figma
        • +
        • Ant Design
        • +
        • Storybook
        • +
        • AI инструменты
        • + + +
        +
        -
        - -
        - -
        -

        Общее по компании

        -
          -
        • Инициировал обновление внешнего вида всей продуктовой линейки — решение о редизайне компания приняла с моим приходом
        • -
        • Собрал и внедрил единую дизайн-систему для веб-сервисов, соединив фирменный стиль компании с новой структурой интерфейсов
        • -
        • Дизайн-систему приняли 4 продуктовые команды; она включает 210 компонентов и токены темизации
        • -
        • Сократил среднее время подготовки макетов по линейке на 35%
        • -
        • Создавал и поддерживал UI-kit для консистентности и ускорения разработки
        • -
        • Провёл более 20 пользовательских исследований и юзабилити-сессий за время работы
        • -
        • Вёл авторский надзор за реализацией, участвовал в дизайн-ревью, продуктовых обсуждениях и планировании релизов
        • -
        • Был единственным ведущим дизайнером на всю линейку из 6 продуктов и двух платформ
        • -
        -
        -
        - -
        - -
        -
        -

        Lunacy (Icons8)

        -

        Июль 2022 — Январь 2023 (7 месяцев)·icons8.com/lunacy

        -
        -

        Графический редактор для работы над дизайном интерфейсов и прочих макетов. Аналог Sketch App и Figma.

        - -
        -
        -
        -

        Обязанности:

        -
          -
        • Проектирование интерфейса графического редактора: инструменты, панели свойств, работа с холстом и слоями
        • -
        • Оформление решений в виде юзерфлоу и передача разработчикам
        • -
        • Создание сложных интерактивных прототипов в Protopie для демонстрации поведения инструментов
        • -
        • Отрисовка недостающих иконок в стилистике продукта
        • -
        • Внесение предложений по улучшению функциональности редактора
        • -
        • Участие в обсуждениях продуктовых решений с командой
        • -
        -
        -
        -

        Достижения:

        -
          -
        • Спроектировал 6 функциональных блоков редактора, включая работу с компонентами и стилями
        • -
        • Собрал 15+ прототипов в Protopie, что позволило отсечь неудачные решения до разработки
        • -
        • Часть моих предложений по функциональности вошла в релизы продукта
        • -
        • Отрисовал более 60 иконок, дополнивших системный набор редактора
        • -
        • Работал над продуктом для профессиональной аудитории дизайнеров, где требования к деталям интерфейса выше обычных
        • -
        -
        -
        -

        Стэк:

        -
          -
        • Protopie
        • -
        • Графический редактор
        • -
        • Иконки / иллюстрации
        • -
        + +
        +

        QnA portal (WEB)

        +

        Площадка для постинга вопросов и получения ответов от службы поддержки

        +
        +
        +
        Обязанности
        +
          +
        • Проектирование сценариев публикации вопроса, ответа и поиска по накопленной базе знаний
        • +
        • Дизайн интерфейса портала в условиях ограничения используемого PHP движка для QnA типа сайта.
        • +
        • Проработка ролевой модели: пользователь, эксперт, служба поддержки, модератор
        • +
        • Проектирование механики поиска и подсказок похожих вопросов при публикации
        • +
        +
        +
        +
        Достижения
        +
          +
        • Запустил портал на готовых компонентах дизайн-системы за 3 недели вместо запланированных 8
        • +
        • Снизил нагрузку на поддержку примерно на 25% за счёт переиспользования уже данных ответов
        • +
        • Механика подсказок похожих вопросов сократила количество дублей на 45%
        • +
        • Обеспечил визуальную преемственность с продуктами линейки — портал не выглядит сторонним сервисом
        • +
        +
        +
        +
        Стэк
        +
          +
        • PHP QnA Engine
        • +
        • Figma
        • +
        • Дизайн-система
        • + +
        +
        -
        -
        + +
        +

        Общее по компании

        +
          + +
        • Собрал и внедрил единую дизайн-систему для веб-сервисов, соединив фирменный стиль компании с новой структурой интерфейсов
        • + +
        • Сократил среднее время подготовки макетов по линейке на 35%
        • +
        • Создавал и поддерживал UI-kit для консистентности и ускорения разработки
        • +
        • Провёл более 20 пользовательских исследований и юзабилити-сессий за время работы
        • +
        • Вёл авторский надзор за реализацией, участвовал в дизайн-ревью, продуктовых обсуждениях и планировании релизов
        • +
        • Нанял 4 дизайнеров интерфейсов для разных проектов компании
        • +
        • Провел больше 30 собеседований, в том числе внедрил формат WhiteBoard Interview
        • +
        • Разрабатывал тестовые задания с учётом потребностей конкретной должности и задач
        • +
        • Внедрил внутреннюю систему видеозвонков на основе Jitsi во внутреннем контуре компании совместно с отделом технической поддержки компании
        • + +
        +
        + -
        - -
        -
        -

        MANU Video Game Maker

        -

        Январь 2019 — Декабрь 2021 (3 года)·manu.co

        -
        -

        Игровой движок для создания видеоигр без написания кода.

        - -
        -
        -
        -

        Обязанности:

        -
          -
        • Продуктовый дизайн движка целиком: от концепции взаимодействия до конечного UI
        • -
        • Проектирование поведения интерфейса для сложных пользовательских сценариев
        • -
        • Исследования пользователей: наблюдение, глубинные интервью, опросы
        • -
        • Составление портретов потенциальных пользователей и карт эмпатии
        • -
        • Работа с продуктовой аналитикой и метриками, завязанными на пользовательские сценарии
        • -
        • Вёрстка главной страницы сайта на Tilda, проектирование информационной архитектуры сайта вместе с командой
        • -
        • Контроль работы веб-графического дизайнера
        • -
        • Найм в продуктовый отдел: проведение собеседований и отбор специалистов
        • -
        • Руководство отделом, построение рабочих процессов всей продуктовой команды
        • -
        • Кураторство работ по созданию пользовательской документации
        • -
        • Внедрение инструментов автоматизации (Integromat, Zapier) для внутренних задач
        • -
        -
        -
        -

        Достижения:

        -
          -
        • Провёл масштабный редизайн всей программы: заложил принципиально новую концепцию работы и стилистику
        • -
        • Спроектировал поведение интерфейса для 100+ сложных пользовательских сценариев
        • -
        • Спроектировал дизайн-систему продукта с нуля: 120 компонентов
        • -
        • Получили массу положительных, местами восторженных отзывов пользователей — в продукте стало значительно легче ориентироваться
        • -
        • Завершаемость онбординга выросла с 34% до 58% после редизайна
        • -
        • Провёл 25 глубинных интервью и 4 волны опросов, на их основе переработал 3 ключевых сценария
        • -
        • Нанял 4 специалистов в продуктовый отдел и вырос из дизайнера в тимлида команды
        • -
        • Выстроил процессы отдела: дизайн-ревью, работа с бэклогом, передача в разработку
        • -
        • Автоматизировал внутренние рутины команды, освободив время на продуктовые задачи
        • -
        -
        -
        -

        Стэк:

        -
          -
        • Tilda
        • -
        • Integromat / Zapier
        • -
        • Исследования пользователей
        • -
        +
      5. +
        +

        Lunacy (Icons8)

        +

        — (7 месяцев)·icons8.com/lunacy

        +
        +

        Графический редактор для работы над дизайном интерфейсов и прочих макетов. Аналог Sketch App и Figma.

        +
        +
        +
        +

        Обязанности

        +
          +
        • Проектирование интерфейса графического редактора: инструменты, панели свойств, работа с холстом и слоями
        • +
        • Оформление решений в виде юзерфлоу и передача разработчикам
        • +
        • Создание сложных интерактивных прототипов в Protopie для демонстрации поведения инструментов
        • +
        +
        +
        +

        Достижения

        +
          +
        • Спроектировал 6 функциональных блоков редактора, включая работу с компонентами и стилями
        • +
        • Собрал прототип нового функционала в Protopie для редактирования многослойной реалистичной тени от объекта со сложной логикой поведения, практически не отличимый от решения в продакшене. Не считая мелких простых прототипов.
        • +
        • Провалидировал 3 гипотезы относительно улучшений работы редактора на реальных пользователях. 1 ушла в релиз.
        • +
        +
        +
        +

        Стэк

        +
          +
        • Protopie
        • +
        • Figma
        • +
        • Дизайн-система
        • +
        • Avalonia Custom UI
        • +
        • Windows
        • +
        • Linux
        • +
        • macOS
        • +
        +
        -
      6. -
        + -
        - -
        -
        -

        Aegees Messenger

        -

        Октябрь 2017 — Декабрь 2018 (1 год и 3 месяца)·aegees.com

        -
        -

        Кроссплатформенный мессенджер с защищенным хранилищем и аудиозвонками.

        - -
        -
        -
        -

        Обязанности:

        -
          -
        • Дизайн мессенджера сразу под пять платформ: Android, iOS, macOS, Windows, Linux
        • -
        • Проработка сценариев защищённого хранилища и аудиозвонков
        • -
        • Проектирование сценариев регистрации, шифрования и восстановления доступа
        • -
        • Адаптация единой продуктовой логики под гайдлайны каждой платформы
        • -
        • Контроль работы зарубежных иллюстраторов по подготовке графических материалов
        • -
        • Подготовка материалов для магазинов приложений
        • -
        -
        -
        -

        Достижения:

        -
          -
        • Выстроил единый визуальный язык продукта при соблюдении гайдлайнов пяти платформ одновременно
        • -
        • Спроектировал более 90 экранов в пяти платформенных вариантах
        • -
        • Обеспечил стабильный поток графических материалов от внешних подрядчиков без потери стилистики
        • -
        • Упростил сценарий защищённого хранилища так, чтобы им пользовались люди без технической подготовки
        • -
        • Работал в чувствительной области приватности и безопасности, где ошибка в интерфейсе стоит доверия пользователя
        • -
        -
        -
        -

        Стэк:

        -
          -
        • Android
        • -
        • iOS
        • -
        • macOS
        • -
        • Windows
        • -
        • Linux
        • -
        +
      7. +
        +

        MANU Video Game Maker

        +

        — (3 года)·manu.co

        +
        +

        Игровой движок для создания видеоигр без написания кода.

        +
        +
        +
        +

        Обязанности

        +
          +
        • Продуктовый дизайн движка целиком: от концепции взаимодействия до конечного UI
        • +
        • Проектирование поведения интерфейса для сложных пользовательских сценариев
        • +
        • Исследования пользователей: наблюдение, глубинные интервью, опросы
        • +
        • Составление портретов потенциальных пользователей и карт эмпатии
        • +
        • Работа с продуктовой аналитикой и метриками, завязанными на пользовательские сценарии
        • +
        • Вёрстка главной страницы сайта на Tilda, проектирование информационной архитектуры сайта вместе с командой
        • +
        • Контроль работы веб-графического дизайнера
        • +
        • Найм в продуктовый отдел: проведение собеседований и отбор специалистов
        • +
        • Руководство отделом, построение рабочих процессов всей продуктовой команды
        • +
        • Кураторство работ по созданию пользовательской документации
        • +
        • Внедрение инструментов автоматизации (Integromat, Zapier) для внутренних задач
        • +
        +
        +
        +

        Достижения

        +
          +
        • Провёл масштабный редизайн всей программы: заложил принципиально новую концепцию работы и стилистику
        • +
        • Спроектировал поведение интерфейса для 100+ сложных пользовательских сценариев
        • +
        • Спроектировал дизайн-систему продукта с нуля: 120 компонентов
        • +
        • Получили массу положительных, местами восторженных отзывов пользователей — в продукте стало значительно легче ориентироваться
        • +
        • Завершаемость онбординга выросла с 34% до 58% после редизайна
        • +
        • Провёл 25 глубинных интервью и 4 волны опросов, на их основе переработал 3 ключевых сценария
        • +
        • Нанял 4 специалистов в продуктовый отдел и вырос из дизайнера в тимлида команды
        • +
        • Выстроил процессы отдела: дизайн-ревью, работа с бэклогом, передача в разработку
        • +
        • Автоматизировал внутренние рутины команды, освободив время на продуктовые задачи
        • +
        +
        +
        +

        Стэк

        +
          + +
        • Zapier
        • +
        • Figma
        • +
        • Miro
        • +
        • Mailchimp
        • +
        • Windows
        • +
        • Notion
        • +
        • Airtable
        • +
        +
        -
      8. -
        + -
        - -
        -
        -

        Orion Innovation (ex MERA)

        -

        Июль 2016 — Октябрь 2017 (1 год и 4 месяца)·orioninnovation.com

        -
        -

        Разработка ПО для внешних заказчиков.

        - -
        -
        -
        -

        Обязанности:

        -
          -
        • Работа в дизайн-отделе численностью до 8 человек
        • -
        • Создание анкет персон и составление карты функциональности продукта в соответствии с потребностями персон
        • -
        • Вайрфреймы и отрисовка конечного UI интерфейсов
        • -
        • Проектирование юзкейсов, карт экранов, демонстрации микроанимаций
        • -
        • Подготовка мудбордов и дизайн-концепций, обсуждение их с клиентами
        • -
        • Подготовка и проведение презентаций дизайн-концепций
        • -
        • Линковка мокапов в прототипы, написание сценариев и проведение качественных юзабилити-тестирований
        • -
        • Внесение правок по результатам тестирований
        • -
        • Авторский надзор над реализацией дизайна разработчиками
        • -
        • Участие в дизайн-ревью: разбор работ коллег и защита собственных решений
        • -
        • Прямая коммуникация с зарубежными клиентами для обсуждения дизайна и получения задач
        • -
        -
        -
        -

        Достижения:

        -
          -
        • Провёл 10 сессий юзабилити-тестирования от написания сценария до внесения правок
        • -
        • Освоил новую для себя платформу Smart TV и довёл проект до успешной публикации в магазине приложений
        • -
        • Вёл коммуникацию с зарубежными заказчиками напрямую, без посредников
        • -
        • Активно участвовал в улучшении рабочего процесса дизайн-отдела компании
        • -
        • Прошёл полный цикл продуктового дизайна на 5 клиентских проектах
        • -
        -
        -
        -

        Стэк:

        -
          -
        • Smart TV
        • -
        • Юзабилити-тестирование
        • -
        • Мудборды / дизайн-концепции
        • -
        +
      9. +
        +

        Aegees Messenger

        +

        — (1 год и 3 месяца)·aegees.com

        +
        +

        Кроссплатформенный мессенджер с защищенным хранилищем и аудиозвонками.

        +
        +
        +
        +

        Обязанности

        +
          +
        • Дизайн мессенджера сразу под пять платформ: Android, iOS, macOS, Windows, Linux
        • +
        • Проработка сценариев защищённого хранилища и аудиозвонков
        • +
        • Проектирование сценариев регистрации, шифрования и восстановления доступа
        • +
        • Адаптация единой продуктовой логики под гайдлайны каждой платформы
        • +
        • Контроль работы зарубежных иллюстраторов по подготовке графических материалов
        • +
        • Подготовка материалов для магазинов приложений
        • +
        +
        +
        +

        Достижения

        +
          +
        • Выстроил единый визуальный язык продукта при соблюдении гайдлайнов пяти платформ одновременно
        • +
        • Спроектировал более 90 экранов в пяти платформенных вариантах
        • +
        • Обеспечил стабильный поток графических материалов от внешних подрядчиков без потери стилистики
        • +
        • Упростил сценарий защищённого хранилища так, чтобы им пользовались люди без технической подготовки
        • +
        • Работал в чувствительной области приватности и безопасности, где ошибка в интерфейсе стоит доверия пользователя
        • +
        +
        +
        +

        Стэк

        +
          +
        • Android
        • +
        • iOS
        • +
        • macOS
        • +
        • Windows
        • +
        • Linux
        • +
        +
        -
      10. -
        + -
        - -
        -
        -

        SpaceshipApps Studio

        -

        Июнь 2015 — Июнь 2016 (1 год и 1 месяц)·spaceshipapps.ru

        -
        -

        Студия разработки мобильных приложений и сайтов.

        - -
        -
        -
        -

        Обязанности:

        -
          -
        • Дизайн мобильных и веб-продуктов в потоковом режиме студии
        • -
        • Работа с разными доменами: соцгейминг, бьюти-услуги, доставка еды, голосовые интерфейсы, легал-сервисы, коллаборативные инструменты
        • -
        • Адаптивный веб-дизайн и дизайн административных панелей
        • -
        • Отрисовка иконок и подготовка графики для проектов
        • -
        • Подготовка макетов к передаче в разработку
        • -
        -
        -
        -

        Достижения:

        -
          -
        • Выпустил 6 продуктов за год: геолокационная социальная игра с квестами в реальном мире, приложение записи к бьюти-специалистам, сервис доставки еды, голосовая игра со словами, сайт и админка сервиса регистрации авторского права, мобильная «белая доска» для совместной работы
        • -
        • Научился быстро входить в новую предметную область и держать качество при высоком темпе студии
        • -
        • Закрыл весь спектр задач: мобайл, веб, админ-панели, графика
        • -
        • Заложил базу для перехода от исполнительского дизайна к продуктовому
        • -
        -
        -
        -

        Стэк:

        -
          -
        • Мобайл
        • -
        • Веб
        • -
        • Админ-панели
        • -
        • Графика
        • -
        +
      11. +
        +

        Orion Innovation (ex MERA)

        +

        — (1 год и 4 месяца)·orioninnovation.com

        +
        +

        Разработка ПО для внешних заказчиков.

        +
        +
        +
        +

        Обязанности

        +
          +
        • Работа в дизайн-отделе численностью до 8 человек
        • +
        • Создание анкет персон и составление карты функциональности продукта в соответствии с потребностями персон
        • +
        • Вайрфреймы и отрисовка конечного UI интерфейсов
        • + +
        • Подготовка мудбордов и дизайн-концепций, обсуждение их с клиентами
        • + +
        • Линковка мокапов в прототипы, написание сценариев и проведение качественных юзабилити-тестирований
        • + + +
        • Участие в дизайн-ревью: разбор работ коллег и защита собственных решений
        • + +
        +
        +
        +

        Достижения

        +
          +
        • Провёл 10 сессий юзабилити-тестирования от написания сценария до внесения правок
        • +
        • Освоил новую для себя платформу Smart TV и довёл проект до успешной публикации в магазине приложений
        • +
        • Провёл исследования и реверс-инжиниринг дизайна приложений для платформы Roku TV и создал рабочий процесс разработки дизайна приложения заказчика, включающий: формирование идеи, разработку кликабельных прототипов, тестирование юзабилити на рабочем устройстве, контроль дизайна в приложении, разработанном нашими разработчиками
        • +
        • Вёл коммуникацию с зарубежными заказчиками напрямую, без посредников
        • +
        • Активно участвовал в улучшении рабочего процесса дизайн-отдела компании
        • +
        • Внедрил в команду использование Miro (ex. Realtime Board) для хранения артефактов исследований
        • + +
        +
        +
        +

        Стэк

        +
          +
        • Sketch
        • +
        • Miro
        • +
        • Android
        • +
        • iOS
        • +
        • ROKU TV Box
        • +
        • Smart TV
        • +
        • Marvel App
        • +
        • ProtoPie
        • +
        • Framer
        • + + +
        +
        -
      12. -
        + -
        +
      13. +
        +

        SpaceshipApps Studio

        +

        — (1 год и 1 месяц)·spaceshipapps.ru

        +
        +

        Студия разработки мобильных приложений и сайтов.

        +
        +
        +
        +

        Обязанности

        +
          +
        • Дизайн мобильных и веб-продуктов в потоковом режиме студии
        • +
        • Работа с разными доменами: соцгейминг, бьюти-услуги, доставка еды, голосовые интерфейсы, легал-сервисы, коллаборативные инструменты
        • +
        • Адаптивный веб-дизайн и дизайн административных панелей
        • +
        • Отрисовка иконок и подготовка графики для проектов
        • +
        • Подготовка макетов к передаче в разработку
        • +
        +
        +
        +

        Достижения

        +
          +
        • Выпустил 6 продуктов за год: геолокационная социальная игра с квестами в реальном мире, приложение записи к бьюти-специалистам, сервис доставки еды, голосовая игра со словами, сайт и админка сервиса регистрации авторского права, мобильная «белая доска» для совместной работы
        • +
        • Научился быстро входить в новую предметную область и держать качество при высоком темпе студии
        • +
        • Закрыл весь спектр задач: мобайл, веб, админ-панели, графика
        • +
        • Заложил базу для перехода от исполнительского дизайна к продуктовому
        • +
        +
        +
        +

        Стэк

        +
          +
        • Мобайл
        • +
        • Веб
        • +
        • Adobe Photoshop
        • +
        • After Effects
        • +
        • Adobe Illustrator
        • -

          Навыки

          -
          + + +
        +
        +
        +
        +
      14. +
      +
      + +
      +

      Навыки

      +
      -

      Проектирование

      -

      UX/UI, product design, информационная архитектура, адаптивный дизайн, дизайн-системы

      +
      Проектирование
      +
      UX/UI, product design, информационная архитектура, адаптивный дизайн, дизайн-системы
      -

      Исследования

      -

      Интервью, опросы, usability testing, JTBD, карты эмпатии, конверсия, retention, NPS

      +
      Исследования
      +
      Интервью, опросы, usability testing, JTBD, карты эмпатии, конверсия, retention, NPS
      -

      Инструменты

      -

      Figma, Protopie, Sketch, Adobe Creative Suite, Tilda, AI-инструменты

      +
      Управление
      +
      Построение команды, Agile, Kanban, авторский надзор, работа со стейкхолдерами
      -

      Управление

      -

      Построение команды, Agile, Kanban, авторский надзор, работа со стейкхолдерами

      +
      Инструменты
      +
      Figma, Protopie, Sketch, Adobe Creative Suite, Storybook
      -
      +
      +
      AI инструменты
      +
      Hermes Agent, Perplexity, Cursor IDE, Zed IDE, Open Design, Codex, Claude Code
      +
      + + - -
      +
      {{> footer}} diff --git a/src/partials/head-links.html b/src/partials/head-links.html index 2501e41..7c62c3f 100644 --- a/src/partials/head-links.html +++ b/src/partials/head-links.html @@ -7,6 +7,7 @@ + {{> head-seo}} {{> json-ld}} diff --git a/texts/content-edits/pending.json b/texts/content-edits/pending.json index 6d3f77d..2bed88e 100644 --- a/texts/content-edits/pending.json +++ b/texts/content-edits/pending.json @@ -1,6 +1,6 @@ { "version": 2, - "updatedAt": "2026-08-15T20:32:52.216Z", + "updatedAt": "2026-09-24T19:32:33.153Z", "items": [], "lastAppliedAt": "2026-06-06T11:54:50.470Z" }

      b8kfTa)o^5dG7K)<^ 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 OA8Jb4iq-O#VgCUPvb%Ty literal 0 HcmV?d00001 diff --git a/public/assets/index/resume-photo.webp b/public/assets/index/resume-photo.webp new file mode 100644 index 0000000000000000000000000000000000000000..8ca5150d72dffc155ab5c363889ad5ac1d1af52e GIT binary patch literal 90134 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%0A$R8LmHb*-EZA9aHtsqoeFyZ zDM*%aVgzst{o_L!QN9RH;Z{;U>@4J^YGCRr_k$>Iz!WiC>?X5xLYcQr1T`Hh*m!4@ z`RO3+<_0>hICGQ2$SAdjv~uO(&)+Mt#9;@Ay_2?nZCX6^9pCi874P1~bJP#Z3F~aR zXtY9wn#NLI;GnaIJ`TPDBj1T$Y64y(nl3SM?X)Dl!J>WWDdgBzN z;R!sV1ydsH(o{}6x5Fo8)cyr%B;`t~S0P!V?zW6}VXJ@oJiYVp4$7=T*y&g+^8Q9Y zCA0xO11a5WzDmUvjH?h#kc6rP=F?Y+ zsOM5!38&I-egttCh?eY){!V98*@KutWxywt&!ucu7}3aOG6_+?x!=ScfZ>^7Q9}?* z#9LnRxSP!Py!Ph3gPlonmBEo^VX3OTaN!(-CYN@u+4qVtqpiQ@^C6M+qI}u zSn|2WCI$7#uFmgSvRh9sY2iwHasmeD4KSjWzj(jItKo#7oXgJ#uoI#lSuF>)YszxZ zUJ%ISa4CiVVlGIP^XQJKxOc=^2oQ=s)bNMX)r^=`NZN6Ug4q4%y=3P1mL6E-&6oh(p;+ zYB)Dz%DB}mdU@1_6p(tMUGM#SpFCQsGePPv0PwRlJiD%GEaMQ{v0H`0ECZ3~HSO$f zrbieU!DvC4AEY7JGDY{GO#M9E%%|n5_?`&zwe5Jzkh>pzz(a=$HEBL*ZJzw^9&AZ@AI^k6fXY> z&c*`a5^2~Kc2Bh?>5f^^od1IjdfA7`hc$LFJw%JCiD1-Xg0w0He0?Os*u#lR zyIM|_+tYv=VzR$#7-LZ*=}ja&9Nb_TXhKyX!4*`a%)|$+QPoFL+y)XW7IxUHBgpQo zSCra7gCG6Fa5-4XNxg@MnQ*w)#?S9h8k!TNB0~8Ok4>fk31xTpcTwS~XoAgoSiRWIpOY_otq-(zbyJEX~Qls#}2DLh)i8Lnl6j zB{smg=2i2Y`>FI$)}{8(E^wOQCQLXoQBv(k)boH&uP8)M6-<#9mWBHV{hbt0@`$c* zMX*jy4(d@;FiJg!jD!i>2%=b_$2@6#hv7!-778yd>-OqB5`!F>^(_-KO9xS!CNwBL zBYfjp8Ch%b=A>2ZUNRU|Svl$zTF=9eJwghesk%!_^oR?J7lFIWbX2XJJMAjEVmZiA z6g+KhY&;SV%E4=~X@^~vcSDrZLjdbRok0IjN>X5b z+SA=jK|QQDrTTh_r2NuYV&fC)htXpeMuxJbk(hf~(rDgFmX}~e`vRO*9{aDt9@Lxo z>zG;Q4gr)pm^O)Pi?@-Tk!Z9d_RAVKik`UaB%**vGzV0J9MH^Nn&ftk6eFi|0t^lZ z?Xx2VnEs9xz^dpK{+ z{9q*|DRec2h;6G$>1B4y_z4=&8Y3Ai;|}&nW~xLRwWumJrQY*n(2wV zqMZlGX*cz=aFo@ z?XGr=i(ISNLF53`eNDA&n2n8Yxpui4aOk~-7%yG)H$*j%I2-#pcu%SzP9IKE5o4`1 zr9b%KMGDp4-$ex5d>@wVPGwZsWAx<$p`M;jq_A_XL}dMP-ZYdvS~U4II;8Fk-J(?p!BS)Wv^co~^&<$-xr ziSBN5Whv~6jM|M*n+l8Q$3^TGQOuK@mO1~#yEuvT^--;y@LqEk!S9MOw-vHmT7&bg zE>vwb4BEUMZFV^fqg`DdBB&Z8V*#v7gNEH&DC<}-vwyW=dYailEQCSyp7Ly6l}Fy3 zY7kUUNM<01q9JP%0-tP%h6#eX2&;GtN!w6l2iyq^9mmY6IV6$xVJ9~iSf>;#o*bTT z)zQsw@m#uu)`c+W4%sbhLN>;i==_R@s-udd2#mOGdPO;GK5X)6wMmXo%P|}XQ&=`r z^szRlpbJc6)Y0U;mKA2%U3@9ZMG<(5Y+-V{IU&t4^WQMbn4h}X3Z2%C))`D1aRJT1 zsvb{g{VN*7Gf<#;Mt|zt!vj2Yv|eh`c~%(B=kuf$c=~_ECNQ`I38twncKW (qqP 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 BQhopc literal 0 HcmV?d00001 diff --git a/public/cases/ai-assistant-figma/index.html b/public/cases/ai-assistant-figma/index.html index 18cec64..967e1da 100644 --- a/public/cases/ai-assistant-figma/index.html +++ b/public/cases/ai-assistant-figma/index.html @@ -97,6 +97,7 @@ + @@ -180,7 +181,7 @@ "creator": { "@id": "https://mamadaevv.site/#person" }, - "datePublished": "2026-09-15", + "datePublished": "2026-09-24", "about": "UX/UI-дизайн и проектирование интерфейсов" }, { diff --git a/public/cases/ai-platform-primo-rpa-2/index.html b/public/cases/ai-platform-primo-rpa-2/index.html index fa4e59f..a8f782b 100644 --- a/public/cases/ai-platform-primo-rpa-2/index.html +++ b/public/cases/ai-platform-primo-rpa-2/index.html @@ -97,6 +97,7 @@ + @@ -180,7 +181,7 @@ "creator": { "@id": "https://mamadaevv.site/#person" }, - "datePublished": "2026-09-15", + "datePublished": "2026-09-24", "about": "UX/UI-дизайн и проектирование интерфейсов" }, { diff --git a/public/cases/ai-platform-primo-rpa-v2/index.html b/public/cases/ai-platform-primo-rpa-v2/index.html index fb44c46..d70ffa5 100644 --- a/public/cases/ai-platform-primo-rpa-v2/index.html +++ b/public/cases/ai-platform-primo-rpa-v2/index.html @@ -97,6 +97,7 @@ + @@ -180,7 +181,7 @@ "creator": { "@id": "https://mamadaevv.site/#person" }, - "datePublished": "2026-09-15", + "datePublished": "2026-09-24", "about": "UX/UI-дизайн и проектирование интерфейсов" }, { diff --git a/public/cases/ai-platform-primo-rpa/index.html b/public/cases/ai-platform-primo-rpa/index.html index 223a5b2..3d2f191 100644 --- a/public/cases/ai-platform-primo-rpa/index.html +++ b/public/cases/ai-platform-primo-rpa/index.html @@ -97,6 +97,7 @@ + @@ -180,7 +181,7 @@ "creator": { "@id": "https://mamadaevv.site/#person" }, - "datePublished": "2026-09-15", + "datePublished": "2026-09-24", "about": "UX/UI-дизайн и проектирование интерфейсов" }, { diff --git a/public/cases/card-columns-obsidian/index.html b/public/cases/card-columns-obsidian/index.html index 7326aad..324d8e7 100644 --- a/public/cases/card-columns-obsidian/index.html +++ b/public/cases/card-columns-obsidian/index.html @@ -97,6 +97,7 @@ + @@ -180,7 +181,7 @@ "creator": { "@id": "https://mamadaevv.site/#person" }, - "datePublished": "2026-09-15", + "datePublished": "2026-09-24", "about": "UX/UI-дизайн и проектирование интерфейсов" }, { diff --git a/public/cases/design-system/index.html b/public/cases/design-system/index.html index 56af9dc..8335e9c 100644 --- a/public/cases/design-system/index.html +++ b/public/cases/design-system/index.html @@ -97,6 +97,7 @@ + diff --git a/public/cases/lunacy/index.html b/public/cases/lunacy/index.html index 6b8c1a7..b87250b 100644 --- a/public/cases/lunacy/index.html +++ b/public/cases/lunacy/index.html @@ -97,6 +97,7 @@ + @@ -180,7 +181,7 @@ "creator": { "@id": "https://mamadaevv.site/#person" }, - "datePublished": "2026-09-15", + "datePublished": "2026-09-24", "about": "UX/UI-дизайн и проектирование интерфейсов" }, { diff --git a/public/cases/manu-game-maker/index.html b/public/cases/manu-game-maker/index.html index 97032e8..200d4fe 100644 --- a/public/cases/manu-game-maker/index.html +++ b/public/cases/manu-game-maker/index.html @@ -97,6 +97,7 @@ + @@ -180,7 +181,7 @@ "creator": { "@id": "https://mamadaevv.site/#person" }, - "datePublished": "2026-09-15", + "datePublished": "2026-09-24", "about": "UX/UI-дизайн и проектирование интерфейсов" }, { diff --git a/public/cases/mini-projects-showcase/index.html b/public/cases/mini-projects-showcase/index.html index 1dad478..b09a38e 100644 --- a/public/cases/mini-projects-showcase/index.html +++ b/public/cases/mini-projects-showcase/index.html @@ -97,6 +97,7 @@ + diff --git a/public/cases/mobile-clinic-app/index.html b/public/cases/mobile-clinic-app/index.html index d1bc29a..fd3cb65 100644 --- a/public/cases/mobile-clinic-app/index.html +++ b/public/cases/mobile-clinic-app/index.html @@ -97,6 +97,7 @@ + @@ -180,7 +181,7 @@ "creator": { "@id": "https://mamadaevv.site/#person" }, - "datePublished": "2026-09-15", + "datePublished": "2026-09-24", "about": "UX/UI-дизайн и проектирование интерфейсов" }, { diff --git a/public/cases/obsidian-plugin-columns-view/index.html b/public/cases/obsidian-plugin-columns-view/index.html index 7d353fd..aae203e 100644 --- a/public/cases/obsidian-plugin-columns-view/index.html +++ b/public/cases/obsidian-plugin-columns-view/index.html @@ -97,6 +97,7 @@ + @@ -180,7 +181,7 @@ "creator": { "@id": "https://mamadaevv.site/#person" }, - "datePublished": "2026-09-15", + "datePublished": "2026-09-24", "about": "UX/UI-дизайн и проектирование интерфейсов" }, { diff --git a/public/cases/orc-automation-panel/index.html b/public/cases/orc-automation-panel/index.html index 234ddd1..d0600fc 100644 --- a/public/cases/orc-automation-panel/index.html +++ b/public/cases/orc-automation-panel/index.html @@ -97,6 +97,7 @@ + @@ -180,7 +181,7 @@ "creator": { "@id": "https://mamadaevv.site/#person" }, - "datePublished": "2026-09-15", + "datePublished": "2026-09-24", "about": "UX/UI-дизайн и проектирование интерфейсов" }, { diff --git a/public/cases/site-with-ai-ide/index.html b/public/cases/site-with-ai-ide/index.html index 7412e5d..40c9b67 100644 --- a/public/cases/site-with-ai-ide/index.html +++ b/public/cases/site-with-ai-ide/index.html @@ -97,6 +97,7 @@ + @@ -180,7 +181,7 @@ "creator": { "@id": "https://mamadaevv.site/#person" }, - "datePublished": "2026-09-15", + "datePublished": "2026-09-24", "about": "UX/UI-дизайн и проектирование интерфейсов" }, { diff --git a/public/cases/task-distribution-concept/index.html b/public/cases/task-distribution-concept/index.html index 58d3483..0af60fe 100644 --- a/public/cases/task-distribution-concept/index.html +++ b/public/cases/task-distribution-concept/index.html @@ -97,6 +97,7 @@ + @@ -180,7 +181,7 @@ "creator": { "@id": "https://mamadaevv.site/#person" }, - "datePublished": "2026-09-15", + "datePublished": "2026-09-24", "about": "UX/UI-дизайн и проектирование интерфейсов" }, { diff --git a/public/cases/task-tracker/index.html b/public/cases/task-tracker/index.html index e033e95..d282046 100644 --- a/public/cases/task-tracker/index.html +++ b/public/cases/task-tracker/index.html @@ -97,6 +97,7 @@ + @@ -180,7 +181,7 @@ "creator": { "@id": "https://mamadaevv.site/#person" }, - "datePublished": "2026-09-15", + "datePublished": "2026-09-24", "about": "UX/UI-дизайн и проектирование интерфейсов" }, { diff --git a/public/cases/template-elements-demo/index.html b/public/cases/template-elements-demo/index.html index be572e4..2301429 100644 --- a/public/cases/template-elements-demo/index.html +++ b/public/cases/template-elements-demo/index.html @@ -94,6 +94,7 @@ + diff --git a/public/cookie-policy/index.html b/public/cookie-policy/index.html index f01ffdd..9f08c58 100644 --- a/public/cookie-policy/index.html +++ b/public/cookie-policy/index.html @@ -97,6 +97,7 @@ + diff --git a/public/css/main.css b/public/css/main.css index 5d36f7a..3f9002a 100644 --- a/public/css/main.css +++ b/public/css/main.css @@ -289,7 +289,13 @@ body { width: 100%; height: 100%; display: block; - opacity: 0.4; /* приглушаем яркость живого шейдера */ + opacity: 0; /* старт для fade-in живого шэйдера */ + transition: opacity 0.9s ease; +} + +/* Шэйдер отрисовал первый кадр — плавно проявляем его поверх статичного фона */ +.page-mesh-bg.is-ready canvas { + opacity: 0.4; /* приглушаем яркость живого шэйдера */ } /* Вертикальный градиент-оверлэй: снизу фон закрыт цветом страницы (--bg, diff --git a/public/en/cases/ai-assistant-figma/index.html b/public/en/cases/ai-assistant-figma/index.html index 42b2507..d8b3a6c 100644 --- a/public/en/cases/ai-assistant-figma/index.html +++ b/public/en/cases/ai-assistant-figma/index.html @@ -97,6 +97,7 @@ + @@ -180,7 +181,7 @@ "creator": { "@id": "https://mamadaevv.site/#person" }, - "datePublished": "2026-09-15", + "datePublished": "2026-09-24", "about": "UX/UI design and interface design" }, { diff --git a/public/en/cases/ai-platform-primo-rpa-2/index.html b/public/en/cases/ai-platform-primo-rpa-2/index.html index 8266d73..f8fee07 100644 --- a/public/en/cases/ai-platform-primo-rpa-2/index.html +++ b/public/en/cases/ai-platform-primo-rpa-2/index.html @@ -97,6 +97,7 @@ + @@ -180,7 +181,7 @@ "creator": { "@id": "https://mamadaevv.site/#person" }, - "datePublished": "2026-09-15", + "datePublished": "2026-09-24", "about": "UX/UI design and interface design" }, { diff --git a/public/en/cases/ai-platform-primo-rpa-v2/index.html b/public/en/cases/ai-platform-primo-rpa-v2/index.html index fe840ef..d21fb6e 100644 --- a/public/en/cases/ai-platform-primo-rpa-v2/index.html +++ b/public/en/cases/ai-platform-primo-rpa-v2/index.html @@ -97,6 +97,7 @@ + @@ -180,7 +181,7 @@ "creator": { "@id": "https://mamadaevv.site/#person" }, - "datePublished": "2026-09-15", + "datePublished": "2026-09-24", "about": "UX/UI design and interface design" }, { diff --git a/public/en/cases/ai-platform-primo-rpa/index.html b/public/en/cases/ai-platform-primo-rpa/index.html index 73f5a36..35bd76c 100644 --- a/public/en/cases/ai-platform-primo-rpa/index.html +++ b/public/en/cases/ai-platform-primo-rpa/index.html @@ -97,6 +97,7 @@ + @@ -180,7 +181,7 @@ "creator": { "@id": "https://mamadaevv.site/#person" }, - "datePublished": "2026-09-15", + "datePublished": "2026-09-24", "about": "UX/UI design and interface design" }, { diff --git a/public/en/cases/card-columns-obsidian/index.html b/public/en/cases/card-columns-obsidian/index.html index 5307a54..a7d099f 100644 --- a/public/en/cases/card-columns-obsidian/index.html +++ b/public/en/cases/card-columns-obsidian/index.html @@ -97,6 +97,7 @@ + @@ -180,7 +181,7 @@ "creator": { "@id": "https://mamadaevv.site/#person" }, - "datePublished": "2026-09-15", + "datePublished": "2026-09-24", "about": "UX/UI design and interface design" }, { diff --git a/public/en/cases/design-system/index.html b/public/en/cases/design-system/index.html index baab557..be63275 100644 --- a/public/en/cases/design-system/index.html +++ b/public/en/cases/design-system/index.html @@ -97,6 +97,7 @@ + diff --git a/public/en/cases/lunacy/index.html b/public/en/cases/lunacy/index.html index 1f06a28..8eeb6fd 100644 --- a/public/en/cases/lunacy/index.html +++ b/public/en/cases/lunacy/index.html @@ -97,6 +97,7 @@ + @@ -180,7 +181,7 @@ "creator": { "@id": "https://mamadaevv.site/#person" }, - "datePublished": "2026-09-15", + "datePublished": "2026-09-24", "about": "UX/UI design and interface design" }, { diff --git a/public/en/cases/manu-game-maker/index.html b/public/en/cases/manu-game-maker/index.html index 777f2b3..1267200 100644 --- a/public/en/cases/manu-game-maker/index.html +++ b/public/en/cases/manu-game-maker/index.html @@ -97,6 +97,7 @@ + @@ -180,7 +181,7 @@ "creator": { "@id": "https://mamadaevv.site/#person" }, - "datePublished": "2026-09-15", + "datePublished": "2026-09-24", "about": "UX/UI design and interface design" }, { diff --git a/public/en/cases/mini-projects-showcase/index.html b/public/en/cases/mini-projects-showcase/index.html index 795c3c1..fed12d2 100644 --- a/public/en/cases/mini-projects-showcase/index.html +++ b/public/en/cases/mini-projects-showcase/index.html @@ -97,6 +97,7 @@ + diff --git a/public/en/cases/mobile-clinic-app/index.html b/public/en/cases/mobile-clinic-app/index.html index eaeaf43..aa75394 100644 --- a/public/en/cases/mobile-clinic-app/index.html +++ b/public/en/cases/mobile-clinic-app/index.html @@ -97,6 +97,7 @@ + @@ -180,7 +181,7 @@ "creator": { "@id": "https://mamadaevv.site/#person" }, - "datePublished": "2026-09-15", + "datePublished": "2026-09-24", "about": "UX/UI design and interface design" }, { diff --git a/public/en/cases/obsidian-plugin-columns-view/index.html b/public/en/cases/obsidian-plugin-columns-view/index.html index 44186df..88ac5a2 100644 --- a/public/en/cases/obsidian-plugin-columns-view/index.html +++ b/public/en/cases/obsidian-plugin-columns-view/index.html @@ -97,6 +97,7 @@ + @@ -180,7 +181,7 @@ "creator": { "@id": "https://mamadaevv.site/#person" }, - "datePublished": "2026-09-15", + "datePublished": "2026-09-24", "about": "UX/UI design and interface design" }, { diff --git a/public/en/cases/orc-automation-panel/index.html b/public/en/cases/orc-automation-panel/index.html index e98667a..8ed2f4b 100644 --- a/public/en/cases/orc-automation-panel/index.html +++ b/public/en/cases/orc-automation-panel/index.html @@ -97,6 +97,7 @@ + @@ -180,7 +181,7 @@ "creator": { "@id": "https://mamadaevv.site/#person" }, - "datePublished": "2026-09-15", + "datePublished": "2026-09-24", "about": "UX/UI design and interface design" }, { diff --git a/public/en/cases/site-with-ai-ide/index.html b/public/en/cases/site-with-ai-ide/index.html index 6b09227..5643c74 100644 --- a/public/en/cases/site-with-ai-ide/index.html +++ b/public/en/cases/site-with-ai-ide/index.html @@ -97,6 +97,7 @@ + @@ -180,7 +181,7 @@ "creator": { "@id": "https://mamadaevv.site/#person" }, - "datePublished": "2026-09-15", + "datePublished": "2026-09-24", "about": "UX/UI design and interface design" }, { diff --git a/public/en/cases/task-distribution-concept/index.html b/public/en/cases/task-distribution-concept/index.html index adbe7c4..faf416e 100644 --- a/public/en/cases/task-distribution-concept/index.html +++ b/public/en/cases/task-distribution-concept/index.html @@ -97,6 +97,7 @@ + @@ -180,7 +181,7 @@ "creator": { "@id": "https://mamadaevv.site/#person" }, - "datePublished": "2026-09-15", + "datePublished": "2026-09-24", "about": "UX/UI design and interface design" }, { diff --git a/public/en/cases/task-tracker/index.html b/public/en/cases/task-tracker/index.html index 49a72b4..144499f 100644 --- a/public/en/cases/task-tracker/index.html +++ b/public/en/cases/task-tracker/index.html @@ -97,6 +97,7 @@ + @@ -180,7 +181,7 @@ "creator": { "@id": "https://mamadaevv.site/#person" }, - "datePublished": "2026-09-15", + "datePublished": "2026-09-24", "about": "UX/UI design and interface design" }, { diff --git a/public/en/cases/template-elements-demo/index.html b/public/en/cases/template-elements-demo/index.html index 3af4e5e..f985693 100644 --- a/public/en/cases/template-elements-demo/index.html +++ b/public/en/cases/template-elements-demo/index.html @@ -94,6 +94,7 @@ + diff --git a/public/en/cookie-policy/index.html b/public/en/cookie-policy/index.html index 0048a35..c330d24 100644 --- a/public/en/cookie-policy/index.html +++ b/public/en/cookie-policy/index.html @@ -97,6 +97,7 @@ + diff --git a/public/en/index.html b/public/en/index.html index 581d4e2..3fad5cc 100644 --- a/public/en/index.html +++ b/public/en/index.html @@ -97,6 +97,7 @@ + diff --git a/public/en/resume/index.html b/public/en/resume/index.html index 978d004..bfbafbc 100644 --- a/public/en/resume/index.html +++ b/public/en/resume/index.html @@ -97,6 +97,7 @@ + diff --git a/public/index.html b/public/index.html index fc84cdf..e7c2cb0 100644 --- a/public/index.html +++ b/public/index.html @@ -97,6 +97,7 @@ + diff --git a/public/js/modules/ui/content-edit/content-edit-storage.js b/public/js/modules/ui/content-edit/content-edit-storage.js index e2a8db2..020b3ee 100644 --- a/public/js/modules/ui/content-edit/content-edit-storage.js +++ b/public/js/modules/ui/content-edit/content-edit-storage.js @@ -24,6 +24,6 @@ export async function saveEdits(payload) { export function isContentEditHost() { const host = window.location.hostname; - const ALLOWED_HOSTS = ["localhost", "127.0.0.1", "dev.mamadaevv.site", "f2ogw6fzi6trnp7cp43x8wsd.31.129.103.242.sslip.io"]; + const ALLOWED_HOSTS = ["localhost", "127.0.0.1", "10.200.201.3", "dev.mamadaevv.site", "f2ogw6fzi6trnp7cp43x8wsd.31.129.103.242.sslip.io"]; return ALLOWED_HOSTS.includes(host); } diff --git a/public/js/modules/ui/page-mesh-shader.js b/public/js/modules/ui/page-mesh-shader.js new file mode 100644 index 0000000..2d4f8ea --- /dev/null +++ b/public/js/modules/ui/page-mesh-shader.js @@ -0,0 +1,112 @@ +import { ShaderMount, meshGradientFragmentShader, getShaderColorFromString, defaultObjectSizing, ShaderFitOptions } from "/vendor/paper-shaders/index.js"; +import { prefersReducedMotion } from "../shared/media.js"; + +// Живой mesh-gradient фон главной страницы (Paper Shaders, zero-dep WebGL). +// Цвета берутся из акцентной темы сайта (--theme-h/s/l), чтобы фон всегда +// совпадал с выбранным пользователем акцентом. + +function hsl(h, s, l, a = 1) { + // getShaderColorFromString понимает "hsl(h, s%, l%)" — собираем ровно в этом виде. + return `hsl(${Math.round(h)}, ${Math.round(s)}%, ${Math.round(l)}%)`; +} + +function paletteFromTheme(root) { + const cs = getComputedStyle(root); + const h = parseFloat(cs.getPropertyValue("--theme-h")); + const s = parseFloat(cs.getPropertyValue("--theme-s")); + const l = parseFloat(cs.getPropertyValue("--theme-l")); + if (![h, s, l].every(Number.isFinite)) return null; + // Монохромная палитра: все цвета — вариации акцента (±18°/±36° hue, + // без крупных сдвигов), чтобы фон оставался однотонным, не разноцветным. + const a1 = (h + 36) % 360; + const a2 = (h + 18) % 360; + const a3 = (h - 18 + 360) % 360; + return [ + hsl(a1, s, Math.min(l + 2, 54)), + hsl(a2, s, Math.min(l, 50)), + hsl(a3, s, Math.min(l - 2, 46)), + hsl(h, s, Math.min(l + 6, 58)), + ]; +} + +function colorVec4Array(colors) { + // Шейдер ждёт u_colors как vec4[10] → массив из 10 под-массивов [r,g,b,a]. + // setUniformValues сам flatten'ит массив массивов в uniform4fv. + const out = []; + for (let i = 0; i < 10; i++) { + const c = colors[i % colors.length]; + out.push(getShaderColorFromString(c)); + } + return out; +} + +export function initPageMeshShader() { + const host = document.querySelector(".page-mesh-bg"); + if (!host) return; + if (prefersReducedMotion()) return; // статичный CSS-fallback остаётся виден + + const sizing = () => ({ + u_fit: ShaderFitOptions[defaultObjectSizing.fit], + u_scale: defaultObjectSizing.scale, + u_rotation: defaultObjectSizing.rotation, + u_offsetX: defaultObjectSizing.offsetX, + u_offsetY: defaultObjectSizing.offsetY, + u_originX: defaultObjectSizing.originX, + u_originY: defaultObjectSizing.originY, + u_worldWidth: defaultObjectSizing.worldWidth, + u_worldHeight: defaultObjectSizing.worldHeight, + }); + + const root = document.documentElement; + const base = paletteFromTheme(root) || ["#241d9a", "#f75092", "#9f50d3", "#0e6b8f"]; + + const uniforms = { + ...sizing(), + u_colors: colorVec4Array(base), + u_colorsCount: base.length, + u_distortion: 0.85, + u_swirl: 0.35, + u_grainMixer: 0.06, + u_grainOverlay: 0.04, + }; + + let mount; + try { + mount = new ShaderMount( + host, + meshGradientFragmentShader, + uniforms, + { antialias: true, alpha: true, preserveDrawingBuffer: true }, + 1.0, // speed + 0, // frame + 1, // minPixelRatio: ровно CSS-пиксели, без 2x апскейла (главный источник нагрузки) + 2_500_000 // maxPixelCount: потолок ~1600x1000, фон размытый — качество не страдает + ); + // не даём IntersectionObserver ставить паузу вне вьюпорта — фон на весь экран + try { mount.intersectionObserver?.disconnect(); } catch {} + + // Первый кадр уже отрисован в конструкторе — отмечаем готовность, + // чтобы CSS плавно проявил canvas (fade-in), без рывка. + host.classList.add("is-ready"); + } catch (e) { + console.warn("Mesh shader mount failed, fallback to static bg", e); + return; + } + + // Обновляем палитру при смене акцента/темы. + const onTheme = () => { + const next = paletteFromTheme(root); + if (!next) return; + mount.setUniforms({ + u_colors: colorVec4Array(next), + u_colorsCount: next.length, + }); + }; + window.addEventListener("site-theme-applied", onTheme, { passive: true }); + + // при уходе со страницы — чистим + window.addEventListener("pagehide", () => { + window.removeEventListener("site-theme-applied", onTheme); + try { mount.dispose(); } catch {} + }, { once: true }); +} diff --git a/public/resume/index.html b/public/resume/index.html index d6c967d..18e3c4d 100644 --- a/public/resume/index.html +++ b/public/resume/index.html @@ -97,6 +97,7 @@ + diff --git a/public/sitemap.xml b/public/sitemap.xml index 0f1c18b..de40751 100644 --- a/public/sitemap.xml +++ b/public/sitemap.xml @@ -3,112 +3,112 @@ xmlns:xhtml="http://www.w3.org/1999/xhtml"> https://mamadaevv.site/cases/ai-assistant-figma/ - 2026-09-15 + 2026-09-24 https://mamadaevv.site/cases/ai-platform-primo-rpa-2/ - 2026-09-15 + 2026-09-24 https://mamadaevv.site/cases/ai-platform-primo-rpa-v2/ - 2026-09-15 + 2026-09-24 https://mamadaevv.site/cases/ai-platform-primo-rpa/ - 2026-09-15 + 2026-09-24 https://mamadaevv.site/cases/card-columns-obsidian/ - 2026-09-15 + 2026-09-24 https://mamadaevv.site/cases/lunacy/ - 2026-09-15 + 2026-09-24 https://mamadaevv.site/cases/manu-game-maker/ - 2026-09-15 + 2026-09-24 https://mamadaevv.site/cases/mobile-clinic-app/ - 2026-09-15 + 2026-09-24 https://mamadaevv.site/cases/obsidian-plugin-columns-view/ - 2026-09-15 + 2026-09-24 https://mamadaevv.site/cases/orc-automation-panel/ - 2026-09-15 + 2026-09-24 https://mamadaevv.site/cases/site-with-ai-ide/ - 2026-09-15 + 2026-09-24 https://mamadaevv.site/cases/task-distribution-concept/ - 2026-09-15 + 2026-09-24 https://mamadaevv.site/cases/task-tracker/ - 2026-09-15 + 2026-09-24 https://mamadaevv.site/cookie-policy/ - 2026-09-16 + 2026-09-24 https://mamadaevv.site/ - 2026-09-19 + 2026-09-24 https://mamadaevv.site/resume/ - 2026-09-21 + 2026-09-24 diff --git a/public/vendor/paper-shaders/empty-pixel.d.ts b/public/vendor/paper-shaders/empty-pixel.d.ts new file mode 100644 index 0000000..eb24a1c --- /dev/null +++ b/public/vendor/paper-shaders/empty-pixel.d.ts @@ -0,0 +1 @@ +export declare const emptyPixel = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="; diff --git a/public/vendor/paper-shaders/empty-pixel.js b/public/vendor/paper-shaders/empty-pixel.js new file mode 100644 index 0000000..3e1e5fa --- /dev/null +++ b/public/vendor/paper-shaders/empty-pixel.js @@ -0,0 +1,10 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Paper Shaders * + * https://github.com/paper-design/shaders * + * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +const emptyPixel = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="; +export { + emptyPixel +}; +//# sourceMappingURL=empty-pixel.js.map diff --git a/public/vendor/paper-shaders/empty-pixel.js.map b/public/vendor/paper-shaders/empty-pixel.js.map new file mode 100644 index 0000000..5822ee8 --- /dev/null +++ b/public/vendor/paper-shaders/empty-pixel.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../src/empty-pixel.ts"], + "sourcesContent": ["export const emptyPixel = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==';\n"], + "mappings": ";;;;;AAAO,MAAM,aAAa;", + "names": [] +} diff --git a/public/vendor/paper-shaders/get-shader-color-from-string.d.ts b/public/vendor/paper-shaders/get-shader-color-from-string.d.ts new file mode 100644 index 0000000..b2ca63b --- /dev/null +++ b/public/vendor/paper-shaders/get-shader-color-from-string.d.ts @@ -0,0 +1,3 @@ +/** Convert color string from HSL, RGB, or hex to 0-to-1-range-RGBA array */ +export declare function getShaderColorFromString(colorString: string | [number, number, number] | [number, number, number, number] | undefined): [number, number, number, number]; +export declare const clamp: (n: number, min: number, max: number) => number; diff --git a/public/vendor/paper-shaders/get-shader-color-from-string.js b/public/vendor/paper-shaders/get-shader-color-from-string.js new file mode 100644 index 0000000..f90cf28 --- /dev/null +++ b/public/vendor/paper-shaders/get-shader-color-from-string.js @@ -0,0 +1,101 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Paper Shaders * + * https://github.com/paper-design/shaders * + * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +function getShaderColorFromString(colorString) { + if (Array.isArray(colorString)) { + if (colorString.length === 4) return colorString; + if (colorString.length === 3) return [...colorString, 1]; + return fallbackColor; + } + if (typeof colorString !== "string") { + return fallbackColor; + } + let r, g, b, a = 1; + if (colorString.startsWith("#")) { + [r, g, b, a] = hexToRgba(colorString); + } else if (colorString.startsWith("rgb")) { + const rgba = parseRgba(colorString); + if (rgba === null) return fallbackColor; + [r, g, b, a] = rgba; + } else if (colorString.startsWith("hsl")) { + const hsla = parseHsla(colorString); + if (hsla === null) return fallbackColor; + [r, g, b, a] = hslaToRgba(hsla); + } else { + console.error("Unsupported color format", colorString); + return fallbackColor; + } + return [clamp(r, 0, 1), clamp(g, 0, 1), clamp(b, 0, 1), clamp(a, 0, 1)]; +} +function hexToRgba(hex) { + hex = hex.replace(/^#/, ""); + if (hex.length === 3 || hex.length === 4) { + hex = hex.split("").map((char) => char + char).join(""); + } + if (hex.length === 6) { + hex = hex + "ff"; + } + if (!/^[0-9a-f]{8}$/i.test(hex)) { + console.warn("Invalid hex color"); + return fallbackColor; + } + const r = parseInt(hex.slice(0, 2), 16) / 255; + const g = parseInt(hex.slice(2, 4), 16) / 255; + const b = parseInt(hex.slice(4, 6), 16) / 255; + const a = parseInt(hex.slice(6, 8), 16) / 255; + return [r, g, b, a]; +} +function parseRgba(rgba) { + const match = rgba.match(/^rgba?\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*([0-9.]+))?\s*\)$/i); + if (!match) return null; + return [ + parseInt(match[1] ?? "0") / 255, + parseInt(match[2] ?? "0") / 255, + parseInt(match[3] ?? "0") / 255, + match[4] === void 0 ? 1 : parseFloat(match[4]) + ]; +} +function parseHsla(hsla) { + const match = hsla.match(/^hsla?\s*\(\s*(\d+)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*(?:,\s*([0-9.]+))?\s*\)$/i); + if (!match) return null; + return [ + parseInt(match[1] ?? "0"), + parseInt(match[2] ?? "0"), + parseInt(match[3] ?? "0"), + match[4] === void 0 ? 1 : parseFloat(match[4]) + ]; +} +function hslaToRgba(hsla) { + const [h, s, l, a] = hsla; + const hDecimal = h / 360; + const sDecimal = s / 100; + const lDecimal = l / 100; + let r, g, b; + if (s === 0) { + r = g = b = lDecimal; + } else { + const hue2rgb = (p2, q2, t) => { + if (t < 0) t += 1; + if (t > 1) t -= 1; + if (t < 1 / 6) return p2 + (q2 - p2) * 6 * t; + if (t < 1 / 2) return q2; + if (t < 2 / 3) return p2 + (q2 - p2) * (2 / 3 - t) * 6; + return p2; + }; + const q = lDecimal < 0.5 ? lDecimal * (1 + sDecimal) : lDecimal + sDecimal - lDecimal * sDecimal; + const p = 2 * lDecimal - q; + r = hue2rgb(p, q, hDecimal + 1 / 3); + g = hue2rgb(p, q, hDecimal); + b = hue2rgb(p, q, hDecimal - 1 / 3); + } + return [r, g, b, a]; +} +const clamp = (n, min, max) => Math.min(Math.max(n, min), max); +const fallbackColor = [0.5, 0.5, 0.5, 1]; +export { + clamp, + getShaderColorFromString +}; +//# sourceMappingURL=get-shader-color-from-string.js.map diff --git a/public/vendor/paper-shaders/get-shader-color-from-string.js.map b/public/vendor/paper-shaders/get-shader-color-from-string.js.map new file mode 100644 index 0000000..4f89049 --- /dev/null +++ b/public/vendor/paper-shaders/get-shader-color-from-string.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../src/get-shader-color-from-string.ts"], + "sourcesContent": ["/** Convert color string from HSL, RGB, or hex to 0-to-1-range-RGBA array */\nexport function getShaderColorFromString(\n colorString: string | [number, number, number] | [number, number, number, number] | undefined\n): [number, number, number, number] {\n // If the color string is already an array of 3 or 4 numbers, return it (with alpha=1 if needed)\n if (Array.isArray(colorString)) {\n if (colorString.length === 4) return colorString as [number, number, number, number];\n if (colorString.length === 3) return [...colorString, 1];\n return fallbackColor;\n }\n\n // If the color string is not a string, return the fallback\n if (typeof colorString !== 'string') {\n return fallbackColor;\n }\n\n let r: number,\n g: number,\n b: number,\n a = 1;\n if (colorString.startsWith('#')) {\n [r, g, b, a] = hexToRgba(colorString);\n } else if (colorString.startsWith('rgb')) {\n const rgba = parseRgba(colorString);\n if (rgba === null) return fallbackColor;\n [r, g, b, a] = rgba;\n } else if (colorString.startsWith('hsl')) {\n const hsla = parseHsla(colorString);\n if (hsla === null) return fallbackColor;\n [r, g, b, a] = hslaToRgba(hsla);\n } else {\n console.error('Unsupported color format', colorString);\n return fallbackColor;\n }\n\n return [clamp(r, 0, 1), clamp(g, 0, 1), clamp(b, 0, 1), clamp(a, 0, 1)];\n}\n\n/** Convert hex to RGBA (0 to 1 range) */\nfunction hexToRgba(hex: string): [number, number, number, number] {\n // Remove # if present\n hex = hex.replace(/^#/, '');\n\n // Expand shorthand hex (3-letter #rgb or 4-letter #rgba) by doubling each digit\n if (hex.length === 3 || hex.length === 4) {\n hex = hex\n .split('')\n .map((char) => char + char)\n .join('');\n }\n // Expand six-letter hex to eight-letter (add full opacity if no alpha)\n if (hex.length === 6) {\n hex = hex + 'ff';\n }\n\n // Bail out on malformed hex (wrong length or non-hex characters) so callers\n // get the fallback color instead of NaN channels leaking into the shader.\n if (!/^[0-9a-f]{8}$/i.test(hex)) {\n console.warn('Invalid hex color');\n return fallbackColor;\n }\n\n // Parse the components\n const r = parseInt(hex.slice(0, 2), 16) / 255;\n const g = parseInt(hex.slice(2, 4), 16) / 255;\n const b = parseInt(hex.slice(4, 6), 16) / 255;\n const a = parseInt(hex.slice(6, 8), 16) / 255;\n\n return [r, g, b, a];\n}\n\n/** Parse RGBA string to RGBA (0 to 1 range), or null if unparseable */\nfunction parseRgba(rgba: string): [number, number, number, number] | null {\n // Match both rgb and rgba patterns\n const match = rgba.match(/^rgba?\\s*\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*(?:,\\s*([0-9.]+))?\\s*\\)$/i);\n if (!match) return null;\n\n return [\n parseInt(match[1] ?? '0') / 255,\n parseInt(match[2] ?? '0') / 255,\n parseInt(match[3] ?? '0') / 255,\n match[4] === undefined ? 1 : parseFloat(match[4]),\n ];\n}\n\n/** Parse HSLA string, or null if unparseable */\nfunction parseHsla(hsla: string): [number, number, number, number] | null {\n const match = hsla.match(/^hsla?\\s*\\(\\s*(\\d+)\\s*,\\s*(\\d+)%\\s*,\\s*(\\d+)%\\s*(?:,\\s*([0-9.]+))?\\s*\\)$/i);\n if (!match) return null;\n\n return [\n parseInt(match[1] ?? '0'),\n parseInt(match[2] ?? '0'),\n parseInt(match[3] ?? '0'),\n match[4] === undefined ? 1 : parseFloat(match[4]),\n ];\n}\n\n/** Convert HSLA to RGBA (0 to 1 range) */\nfunction hslaToRgba(hsla: [number, number, number, number]): [number, number, number, number] {\n const [h, s, l, a] = hsla;\n const hDecimal = h / 360;\n const sDecimal = s / 100;\n const lDecimal = l / 100;\n let r, g, b;\n\n if (s === 0) {\n r = g = b = lDecimal; // achromatic\n } else {\n const hue2rgb = (p: number, q: number, t: number) => {\n if (t < 0) t += 1;\n if (t > 1) t -= 1;\n if (t < 1 / 6) return p + (q - p) * 6 * t;\n if (t < 1 / 2) return q;\n if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;\n return p;\n };\n\n const q = lDecimal < 0.5 ? lDecimal * (1 + sDecimal) : lDecimal + sDecimal - lDecimal * sDecimal;\n const p = 2 * lDecimal - q;\n r = hue2rgb(p, q, hDecimal + 1 / 3);\n g = hue2rgb(p, q, hDecimal);\n b = hue2rgb(p, q, hDecimal - 1 / 3);\n }\n\n return [r, g, b, a];\n}\n\nexport const clamp = (n: number, min: number, max: number): number => Math.min(Math.max(n, min), max);\n\nconst fallbackColor = [0.5, 0.5, 0.5, 1] as [number, number, number, number];\n"], + "mappings": ";;;;;AACO,SAAS,yBACd,aACkC;AAElC,MAAI,MAAM,QAAQ,WAAW,GAAG;AAC9B,QAAI,YAAY,WAAW,EAAG,QAAO;AACrC,QAAI,YAAY,WAAW,EAAG,QAAO,CAAC,GAAG,aAAa,CAAC;AACvD,WAAO;AAAA,EACT;AAGA,MAAI,OAAO,gBAAgB,UAAU;AACnC,WAAO;AAAA,EACT;AAEA,MAAI,GACF,GACA,GACA,IAAI;AACN,MAAI,YAAY,WAAW,GAAG,GAAG;AAC/B,KAAC,GAAG,GAAG,GAAG,CAAC,IAAI,UAAU,WAAW;AAAA,EACtC,WAAW,YAAY,WAAW,KAAK,GAAG;AACxC,UAAM,OAAO,UAAU,WAAW;AAClC,QAAI,SAAS,KAAM,QAAO;AAC1B,KAAC,GAAG,GAAG,GAAG,CAAC,IAAI;AAAA,EACjB,WAAW,YAAY,WAAW,KAAK,GAAG;AACxC,UAAM,OAAO,UAAU,WAAW;AAClC,QAAI,SAAS,KAAM,QAAO;AAC1B,KAAC,GAAG,GAAG,GAAG,CAAC,IAAI,WAAW,IAAI;AAAA,EAChC,OAAO;AACL,YAAQ,MAAM,4BAA4B,WAAW;AACrD,WAAO;AAAA,EACT;AAEA,SAAO,CAAC,MAAM,GAAG,GAAG,CAAC,GAAG,MAAM,GAAG,GAAG,CAAC,GAAG,MAAM,GAAG,GAAG,CAAC,GAAG,MAAM,GAAG,GAAG,CAAC,CAAC;AACxE;AAGA,SAAS,UAAU,KAA+C;AAEhE,QAAM,IAAI,QAAQ,MAAM,EAAE;AAG1B,MAAI,IAAI,WAAW,KAAK,IAAI,WAAW,GAAG;AACxC,UAAM,IACH,MAAM,EAAE,EACR,IAAI,CAAC,SAAS,OAAO,IAAI,EACzB,KAAK,EAAE;AAAA,EACZ;AAEA,MAAI,IAAI,WAAW,GAAG;AACpB,UAAM,MAAM;AAAA,EACd;AAIA,MAAI,CAAC,iBAAiB,KAAK,GAAG,GAAG;AAC/B,YAAQ,KAAK,mBAAmB;AAChC,WAAO;AAAA,EACT;AAGA,QAAM,IAAI,SAAS,IAAI,MAAM,GAAG,CAAC,GAAG,EAAE,IAAI;AAC1C,QAAM,IAAI,SAAS,IAAI,MAAM,GAAG,CAAC,GAAG,EAAE,IAAI;AAC1C,QAAM,IAAI,SAAS,IAAI,MAAM,GAAG,CAAC,GAAG,EAAE,IAAI;AAC1C,QAAM,IAAI,SAAS,IAAI,MAAM,GAAG,CAAC,GAAG,EAAE,IAAI;AAE1C,SAAO,CAAC,GAAG,GAAG,GAAG,CAAC;AACpB;AAGA,SAAS,UAAU,MAAuD;AAExE,QAAM,QAAQ,KAAK,MAAM,yEAAyE;AAClG,MAAI,CAAC,MAAO,QAAO;AAEnB,SAAO;AAAA,IACL,SAAS,MAAM,CAAC,KAAK,GAAG,IAAI;AAAA,IAC5B,SAAS,MAAM,CAAC,KAAK,GAAG,IAAI;AAAA,IAC5B,SAAS,MAAM,CAAC,KAAK,GAAG,IAAI;AAAA,IAC5B,MAAM,CAAC,MAAM,SAAY,IAAI,WAAW,MAAM,CAAC,CAAC;AAAA,EAClD;AACF;AAGA,SAAS,UAAU,MAAuD;AACxE,QAAM,QAAQ,KAAK,MAAM,2EAA2E;AACpG,MAAI,CAAC,MAAO,QAAO;AAEnB,SAAO;AAAA,IACL,SAAS,MAAM,CAAC,KAAK,GAAG;AAAA,IACxB,SAAS,MAAM,CAAC,KAAK,GAAG;AAAA,IACxB,SAAS,MAAM,CAAC,KAAK,GAAG;AAAA,IACxB,MAAM,CAAC,MAAM,SAAY,IAAI,WAAW,MAAM,CAAC,CAAC;AAAA,EAClD;AACF;AAGA,SAAS,WAAW,MAA0E;AAC5F,QAAM,CAAC,GAAG,GAAG,GAAG,CAAC,IAAI;AACrB,QAAM,WAAW,IAAI;AACrB,QAAM,WAAW,IAAI;AACrB,QAAM,WAAW,IAAI;AACrB,MAAI,GAAG,GAAG;AAEV,MAAI,MAAM,GAAG;AACX,QAAI,IAAI,IAAI;AAAA,EACd,OAAO;AACL,UAAM,UAAU,CAACA,IAAWC,IAAW,MAAc;AACnD,UAAI,IAAI,EAAG,MAAK;AAChB,UAAI,IAAI,EAAG,MAAK;AAChB,UAAI,IAAI,IAAI,EAAG,QAAOD,MAAKC,KAAID,MAAK,IAAI;AACxC,UAAI,IAAI,IAAI,EAAG,QAAOC;AACtB,UAAI,IAAI,IAAI,EAAG,QAAOD,MAAKC,KAAID,OAAM,IAAI,IAAI,KAAK;AAClD,aAAOA;AAAA,IACT;AAEA,UAAM,IAAI,WAAW,MAAM,YAAY,IAAI,YAAY,WAAW,WAAW,WAAW;AACxF,UAAM,IAAI,IAAI,WAAW;AACzB,QAAI,QAAQ,GAAG,GAAG,WAAW,IAAI,CAAC;AAClC,QAAI,QAAQ,GAAG,GAAG,QAAQ;AAC1B,QAAI,QAAQ,GAAG,GAAG,WAAW,IAAI,CAAC;AAAA,EACpC;AAEA,SAAO,CAAC,GAAG,GAAG,GAAG,CAAC;AACpB;AAEO,MAAM,QAAQ,CAAC,GAAW,KAAa,QAAwB,KAAK,IAAI,KAAK,IAAI,GAAG,GAAG,GAAG,GAAG;AAEpG,MAAM,gBAAgB,CAAC,KAAK,KAAK,KAAK,CAAC;", + "names": ["p", "q"] +} diff --git a/public/vendor/paper-shaders/get-shader-noise-texture.d.ts b/public/vendor/paper-shaders/get-shader-noise-texture.d.ts new file mode 100644 index 0000000..35661e3 --- /dev/null +++ b/public/vendor/paper-shaders/get-shader-noise-texture.d.ts @@ -0,0 +1 @@ +export declare function getShaderNoiseTexture(): HTMLImageElement | undefined; diff --git a/public/vendor/paper-shaders/get-shader-noise-texture.js b/public/vendor/paper-shaders/get-shader-noise-texture.js new file mode 100644 index 0000000..dedc3ec --- /dev/null +++ b/public/vendor/paper-shaders/get-shader-noise-texture.js @@ -0,0 +1,18 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Paper Shaders * + * https://github.com/paper-design/shaders * + * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +function getShaderNoiseTexture() { + if (typeof window === "undefined") { + return void 0; + } + const img = new Image(); + img.src = noiseSrc; + return img; +} +const noiseSrc = "data:image/png;base64,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"; +export { + getShaderNoiseTexture +}; +//# sourceMappingURL=get-shader-noise-texture.js.map diff --git a/public/vendor/paper-shaders/get-shader-noise-texture.js.map b/public/vendor/paper-shaders/get-shader-noise-texture.js.map new file mode 100644 index 0000000..5128cdc --- /dev/null +++ b/public/vendor/paper-shaders/get-shader-noise-texture.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../src/get-shader-noise-texture.ts"], + "sourcesContent": ["export function getShaderNoiseTexture(): HTMLImageElement | undefined {\n if (typeof window === 'undefined') {\n return undefined;\n }\n\n const img = new Image();\n img.src = noiseSrc;\n return img;\n}\n\nconst noiseSrc =\n 'data:image/png;base64,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';\n"], + "mappings": ";;;;;AAAO,SAAS,wBAAsD;AACpE,MAAI,OAAO,WAAW,aAAa;AACjC,WAAO;AAAA,EACT;AAEA,QAAM,MAAM,IAAI,MAAM;AACtB,MAAI,MAAM;AACV,SAAO;AACT;AAEA,MAAM,WACJ;", + "names": [] +} diff --git a/public/vendor/paper-shaders/index.d.ts b/public/vendor/paper-shaders/index.d.ts new file mode 100644 index 0000000..f438002 --- /dev/null +++ b/public/vendor/paper-shaders/index.d.ts @@ -0,0 +1,68 @@ +/** The core Shader Mount class. Pass it a parent element and a fragment shader to get started. */ +export { ShaderMount, isPaperShaderElement } from './shader-mount.js'; +export type { PaperShaderElement, ShaderMotionParams, ShaderMountUniforms, ShaderPreset, ImageShaderPreset, } from './shader-mount.js'; +/** Shader sizing options and uniforms */ +export { defaultObjectSizing, defaultPatternSizing, ShaderFitOptions, type ShaderFit, type ShaderSizingParams, type ShaderSizingUniforms, } from './shader-sizing.js'; +/** A flowing interplay of color spots, moving along distinct trajectories and transformed by organic distortion */ +export { meshGradientFragmentShader, meshGradientMeta, type MeshGradientParams, type MeshGradientUniforms, } from './shaders/mesh-gradient.js'; +/** Radial multi-colored gradient shaped with layered noise for a natural, smoky aesthetic */ +export { smokeRingMeta, smokeRingFragmentShader, type SmokeRingParams, type SmokeRingUniforms, } from './shaders/smoke-ring.js'; +/** A glowing, web-like structure of fluid lines and soft intersections. Great for creating atmospheric, organic-yet-futuristic visuals */ +export { neuroNoiseFragmentShader, type NeuroNoiseParams, type NeuroNoiseUniforms } from './shaders/neuro-noise.js'; +/** Animated multi-color dots pattern with each dot orbiting around its cell center. Supports up to 40 colors and various shape and motion controls. Great for playful, dynamic backgrounds and UI textures */ +export { dotOrbitMeta, dotOrbitFragmentShader, type DotOrbitParams, type DotOrbitUniforms, } from './shaders/dot-orbit.js'; +/** Static grid pattern made of circles, diamonds, squares or triangles */ +export { dotGridFragmentShader, DotGridShapes, type DotGridShape, type DotGridParams, type DotGridUniforms, } from './shaders/dot-grid.js'; +/** A multi-color gradient mapped into smooth, animated curves, delivering a sleek, futuristic visual */ +export { simplexNoiseMeta, simplexNoiseFragmentShader, type SimplexNoiseParams, type SimplexNoiseUniforms, } from './shaders/simplex-noise.js'; +/** Up to 20 gooey blobs moving around the center and merging into smooth organic shapes */ +export { metaballsMeta, metaballsFragmentShader, type MetaballsParams, type MetaballsUniforms, } from './shaders/metaballs.js'; +/** Animated 3D Perlin noise with exposed controls */ +export { perlinNoiseFragmentShader, type PerlinNoiseParams, type PerlinNoiseUniforms } from './shaders/perlin-noise.js'; +/** Anti-aliased animated Voronoi pattern with smooth and customizable edges */ +export { voronoiMeta, voronoiFragmentShader, type VoronoiParams, type VoronoiUniforms } from './shaders/voronoi.js'; +/** Static line pattern configurable into textures ranging from sharp zigzags to smooth flowing waves */ +export { wavesFragmentShader, type WavesParams, type WavesUniforms } from './shaders/waves.js'; +/** Animated color fields warped by noise and swirls, applied over base patterns (checks, stripes, or split edge). Blends up to 10 colors with adjustable distribution, softness, distortion, and swirl. Great for fluid, smoky, or marbled effects */ +export { warpMeta, warpFragmentShader, WarpPatterns, type WarpParams, type WarpUniforms, type WarpPattern, } from './shaders/warp.js'; +/** Animated rays of light radiating from the center, blended with up to 5 colors. The rays are adjustable by size, density, brightness and center glow. Great for dramatic backgrounds, logo reveals, and VFX like energy bursts or sun shafts */ +export { godRaysMeta, godRaysFragmentShader, type GodRaysParams, type GodRaysUniforms } from './shaders/god-rays.js'; +/** A single-colored animated spiral that morphs across a wide range of shapes - from crisp, thin-lined geometry to flowing whirlpool forms and wavy, abstract rings */ +export { spiralFragmentShader, type SpiralParams, type SpiralUniforms } from './shaders/spiral.js'; +/** Animated bands of color twisting and bending, producing spirals, arcs, and flowing circular patterns */ +export { swirlMeta, swirlFragmentShader, type SwirlParams, type SwirlUniforms } from './shaders/swirl.js'; +/** Animated 2-color dithering over with multiple pattern sources (noise, warp, dots, waves, ripple, swirl, sphere) */ +export { ditheringFragmentShader, DitheringShapes, DitheringTypes, type DitheringParams, type DitheringUniforms, type DitheringShape, type DitheringType, } from './shaders/dithering.js'; +/** Multi-color gradients with grainy, noise-textured distortion available in 7 animated abstract forms */ +export { grainGradientFragmentShader, grainGradientMeta, GrainGradientShapes, type GrainGradientParams, type GrainGradientUniforms, type GrainGradientShape, } from './shaders/grain-gradient.js'; +/** Luminous trails of color merging into a glowing gradient frame */ +export { pulsingBorderMeta, pulsingBorderFragmentShader, PulsingBorderAspectRatios, type PulsingBorderParams, type PulsingBorderUniforms, type PulsingBorderAspectRatio, } from './shaders/pulsing-border.js'; +/** Glowing translucent 3D panels rotating around a central axis */ +export { colorPanelsFragmentShader, colorPanelsMeta, type ColorPanelsParams, type ColorPanelsUniforms, } from './shaders/color-panels.js'; +/** Multi-point mesh gradients with up to 10 color spots, enhanced by two-direction warping, adjustable blend sharpness, and grain controls. Perfect for elegant wallpapers and atmospheric backdrops */ +export { staticMeshGradientFragmentShader, staticMeshGradientMeta, type StaticMeshGradientParams, type StaticMeshGradientUniforms, } from './shaders/static-mesh-gradient.js'; +/** Radial gradient with up to 10 blended colors, featuring advanced focal point control, shape distortion, and grain effects */ +export { staticRadialGradientFragmentShader, staticRadialGradientMeta, type StaticRadialGradientParams, type StaticRadialGradientUniforms, } from './shaders/static-radial-gradient.js'; +/** A static texture built from multiple noise layers, usable for a realistic paper and cardboard surfaces or generating abstract patterns. Can be used as a image filter or as a texture */ +export { paperTextureFragmentShader, type PaperTextureParams, type PaperTextureUniforms, } from './shaders/paper-texture.js'; +/** Water-like surface distortion with natural caustic realism. Works as an image filter or animated texture without image */ +export { waterFragmentShader, type WaterParams, type WaterUniforms } from './shaders/water.js'; +/** Fluted glass image filter transforms an image into streaked, ribbed distortions, giving a mix of clarity and obscurity */ +export { flutedGlassFragmentShader, GlassDistortionShapes, GlassGridShapes, type GlassDistortionShape, type GlassGridShape, type FlutedGlassParams, type FlutedGlassUniforms, } from './shaders/fluted-glass.js'; +/** A dithering image filter with support for 4 dithering modes and multiple color palettes (2-color, 3-color, and multicolor options, using either predefined colors or ones sampled directly from the original image) */ +export { imageDitheringFragmentShader, type ImageDitheringParams, type ImageDitheringUniforms, } from './shaders/image-dithering.js'; +/** Lens Distortion image filter that separates an image into shifting color layers, recreating the chromatic aberration of a lens, and warps the image geometry with barrel or pincushion curvature */ +export { lensDistortionFragmentShader, lensDistortionMeta, type LensDistortionParams, type LensDistortionUniforms } from './shaders/lens-distortion.js'; +/** A glowing gradient of colors flowing through an input image. The effect creates a smoothly animated wave of intensity across the image */ +export { heatmapMeta, heatmapFragmentShader, toProcessedHeatmap, type HeatmapParams, type HeatmapUniforms, } from './shaders/heatmap.js'; +/** Futuristic liquid metal material applied to uploaded logo or one of pre-defined abstract shape */ +export { liquidMetalFragmentShader, LiquidMetalShapes, toProcessedLiquidMetal, type LiquidMetalShape, type LiquidMetalParams, type LiquidMetalUniforms, } from './shaders/liquid-metal.js'; +/** A halftone-dot image filter featuring customizable grids, color palettes, and dot styles */ +export { HalftoneDotsTypes, HalftoneDotsGrids, halftoneDotsFragmentShader, type HalftoneDotsParams, type HalftoneDotsUniforms, type HalftoneDotsType, type HalftoneDotsGrid, } from './shaders/halftone-dots.js'; +/** A halftone CMYK classic algo */ +export { HalftoneCmykTypes, halftoneCmykFragmentShader, type HalftoneCmykParams, type HalftoneCmykUniforms, type HalftoneCmykType, } from './shaders/halftone-cmyk.js'; +/** Animated color fields running around a glassy logo shape */ +export { gemSmokeMeta, gemSmokeFragmentShader, toProcessedGemSmoke, GemSmokeShapes, type GemSmokeShape, type GemSmokeParams, type GemSmokeUniforms, } from './shaders/gem-smoke.js'; +export { getShaderColorFromString } from './get-shader-color-from-string.js'; +export { getShaderNoiseTexture } from './get-shader-noise-texture.js'; +export { emptyPixel } from './empty-pixel.js'; diff --git a/public/vendor/paper-shaders/index.js b/public/vendor/paper-shaders/index.js new file mode 100644 index 0000000..fc9e21b --- /dev/null +++ b/public/vendor/paper-shaders/index.js @@ -0,0 +1,189 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Paper Shaders * + * https://github.com/paper-design/shaders * + * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +import { ShaderMount, isPaperShaderElement } from "./shader-mount.js"; +import { + defaultObjectSizing, + defaultPatternSizing, + ShaderFitOptions +} from "./shader-sizing.js"; +import { + meshGradientFragmentShader, + meshGradientMeta +} from "./shaders/mesh-gradient.js"; +import { + smokeRingMeta, + smokeRingFragmentShader +} from "./shaders/smoke-ring.js"; +import { neuroNoiseFragmentShader } from "./shaders/neuro-noise.js"; +import { + dotOrbitMeta, + dotOrbitFragmentShader +} from "./shaders/dot-orbit.js"; +import { + dotGridFragmentShader, + DotGridShapes +} from "./shaders/dot-grid.js"; +import { + simplexNoiseMeta, + simplexNoiseFragmentShader +} from "./shaders/simplex-noise.js"; +import { + metaballsMeta, + metaballsFragmentShader +} from "./shaders/metaballs.js"; +import { perlinNoiseFragmentShader } from "./shaders/perlin-noise.js"; +import { voronoiMeta, voronoiFragmentShader } from "./shaders/voronoi.js"; +import { wavesFragmentShader } from "./shaders/waves.js"; +import { + warpMeta, + warpFragmentShader, + WarpPatterns +} from "./shaders/warp.js"; +import { godRaysMeta, godRaysFragmentShader } from "./shaders/god-rays.js"; +import { spiralFragmentShader } from "./shaders/spiral.js"; +import { swirlMeta, swirlFragmentShader } from "./shaders/swirl.js"; +import { + ditheringFragmentShader, + DitheringShapes, + DitheringTypes +} from "./shaders/dithering.js"; +import { + grainGradientFragmentShader, + grainGradientMeta, + GrainGradientShapes +} from "./shaders/grain-gradient.js"; +import { + pulsingBorderMeta, + pulsingBorderFragmentShader, + PulsingBorderAspectRatios +} from "./shaders/pulsing-border.js"; +import { + colorPanelsFragmentShader, + colorPanelsMeta +} from "./shaders/color-panels.js"; +import { + staticMeshGradientFragmentShader, + staticMeshGradientMeta +} from "./shaders/static-mesh-gradient.js"; +import { + staticRadialGradientFragmentShader, + staticRadialGradientMeta +} from "./shaders/static-radial-gradient.js"; +import { + paperTextureFragmentShader +} from "./shaders/paper-texture.js"; +import { waterFragmentShader } from "./shaders/water.js"; +import { + flutedGlassFragmentShader, + GlassDistortionShapes, + GlassGridShapes +} from "./shaders/fluted-glass.js"; +import { + imageDitheringFragmentShader +} from "./shaders/image-dithering.js"; +import { lensDistortionFragmentShader, lensDistortionMeta } from "./shaders/lens-distortion.js"; +import { + heatmapMeta, + heatmapFragmentShader, + toProcessedHeatmap +} from "./shaders/heatmap.js"; +import { + liquidMetalFragmentShader, + LiquidMetalShapes, + toProcessedLiquidMetal +} from "./shaders/liquid-metal.js"; +import { + HalftoneDotsTypes, + HalftoneDotsGrids, + halftoneDotsFragmentShader +} from "./shaders/halftone-dots.js"; +import { + HalftoneCmykTypes, + halftoneCmykFragmentShader +} from "./shaders/halftone-cmyk.js"; +import { + gemSmokeMeta, + gemSmokeFragmentShader, + toProcessedGemSmoke, + GemSmokeShapes +} from "./shaders/gem-smoke.js"; +import { getShaderColorFromString } from "./get-shader-color-from-string.js"; +import { getShaderNoiseTexture } from "./get-shader-noise-texture.js"; +import { emptyPixel } from "./empty-pixel.js"; +export { + DitheringShapes, + DitheringTypes, + DotGridShapes, + GemSmokeShapes, + GlassDistortionShapes, + GlassGridShapes, + GrainGradientShapes, + HalftoneCmykTypes, + HalftoneDotsGrids, + HalftoneDotsTypes, + LiquidMetalShapes, + PulsingBorderAspectRatios, + ShaderFitOptions, + ShaderMount, + WarpPatterns, + colorPanelsFragmentShader, + colorPanelsMeta, + defaultObjectSizing, + defaultPatternSizing, + ditheringFragmentShader, + dotGridFragmentShader, + dotOrbitFragmentShader, + dotOrbitMeta, + emptyPixel, + flutedGlassFragmentShader, + gemSmokeFragmentShader, + gemSmokeMeta, + getShaderColorFromString, + getShaderNoiseTexture, + godRaysFragmentShader, + godRaysMeta, + grainGradientFragmentShader, + grainGradientMeta, + halftoneCmykFragmentShader, + halftoneDotsFragmentShader, + heatmapFragmentShader, + heatmapMeta, + imageDitheringFragmentShader, + isPaperShaderElement, + lensDistortionFragmentShader, + lensDistortionMeta, + liquidMetalFragmentShader, + meshGradientFragmentShader, + meshGradientMeta, + metaballsFragmentShader, + metaballsMeta, + neuroNoiseFragmentShader, + paperTextureFragmentShader, + perlinNoiseFragmentShader, + pulsingBorderFragmentShader, + pulsingBorderMeta, + simplexNoiseFragmentShader, + simplexNoiseMeta, + smokeRingFragmentShader, + smokeRingMeta, + spiralFragmentShader, + staticMeshGradientFragmentShader, + staticMeshGradientMeta, + staticRadialGradientFragmentShader, + staticRadialGradientMeta, + swirlFragmentShader, + swirlMeta, + toProcessedGemSmoke, + toProcessedHeatmap, + toProcessedLiquidMetal, + voronoiFragmentShader, + voronoiMeta, + warpFragmentShader, + warpMeta, + waterFragmentShader, + wavesFragmentShader +}; +//# sourceMappingURL=index.js.map diff --git a/public/vendor/paper-shaders/index.js.map b/public/vendor/paper-shaders/index.js.map new file mode 100644 index 0000000..a23db2b --- /dev/null +++ b/public/vendor/paper-shaders/index.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../src/index.ts"], + "sourcesContent": ["/** The core Shader Mount class. Pass it a parent element and a fragment shader to get started. */\nexport { ShaderMount, isPaperShaderElement } from './shader-mount.js';\nexport type {\n PaperShaderElement,\n ShaderMotionParams,\n ShaderMountUniforms,\n ShaderPreset,\n ImageShaderPreset,\n} from './shader-mount.js';\n\n/** Shader sizing options and uniforms */\nexport {\n defaultObjectSizing,\n defaultPatternSizing,\n ShaderFitOptions,\n type ShaderFit,\n type ShaderSizingParams,\n type ShaderSizingUniforms,\n} from './shader-sizing.js';\n\n/** A flowing interplay of color spots, moving along distinct trajectories and transformed by organic distortion */\nexport {\n meshGradientFragmentShader,\n meshGradientMeta,\n type MeshGradientParams,\n type MeshGradientUniforms,\n} from './shaders/mesh-gradient.js';\n\n/** Radial multi-colored gradient shaped with layered noise for a natural, smoky aesthetic */\nexport {\n smokeRingMeta,\n smokeRingFragmentShader,\n type SmokeRingParams,\n type SmokeRingUniforms,\n} from './shaders/smoke-ring.js';\n\n/** A glowing, web-like structure of fluid lines and soft intersections. Great for creating atmospheric, organic-yet-futuristic visuals */\nexport { neuroNoiseFragmentShader, type NeuroNoiseParams, type NeuroNoiseUniforms } from './shaders/neuro-noise.js';\n\n/** Animated multi-color dots pattern with each dot orbiting around its cell center. Supports up to 40 colors and various shape and motion controls. Great for playful, dynamic backgrounds and UI textures */\nexport {\n dotOrbitMeta,\n dotOrbitFragmentShader,\n type DotOrbitParams,\n type DotOrbitUniforms,\n} from './shaders/dot-orbit.js';\n\n/** Static grid pattern made of circles, diamonds, squares or triangles */\nexport {\n dotGridFragmentShader,\n DotGridShapes,\n type DotGridShape,\n type DotGridParams,\n type DotGridUniforms,\n} from './shaders/dot-grid.js';\n\n/** A multi-color gradient mapped into smooth, animated curves, delivering a sleek, futuristic visual */\nexport {\n simplexNoiseMeta,\n simplexNoiseFragmentShader,\n type SimplexNoiseParams,\n type SimplexNoiseUniforms,\n} from './shaders/simplex-noise.js';\n\n/** Up to 20 gooey blobs moving around the center and merging into smooth organic shapes */\nexport {\n metaballsMeta,\n metaballsFragmentShader,\n type MetaballsParams,\n type MetaballsUniforms,\n} from './shaders/metaballs.js';\n\n/** Animated 3D Perlin noise with exposed controls */\nexport { perlinNoiseFragmentShader, type PerlinNoiseParams, type PerlinNoiseUniforms } from './shaders/perlin-noise.js';\n\n/** Anti-aliased animated Voronoi pattern with smooth and customizable edges */\nexport { voronoiMeta, voronoiFragmentShader, type VoronoiParams, type VoronoiUniforms } from './shaders/voronoi.js';\n\n/** Static line pattern configurable into textures ranging from sharp zigzags to smooth flowing waves */\nexport { wavesFragmentShader, type WavesParams, type WavesUniforms } from './shaders/waves.js';\n\n/** Animated color fields warped by noise and swirls, applied over base patterns (checks, stripes, or split edge). Blends up to 10 colors with adjustable distribution, softness, distortion, and swirl. Great for fluid, smoky, or marbled effects */\nexport {\n warpMeta,\n warpFragmentShader,\n WarpPatterns,\n type WarpParams,\n type WarpUniforms,\n type WarpPattern,\n} from './shaders/warp.js';\n\n/** Animated rays of light radiating from the center, blended with up to 5 colors. The rays are adjustable by size, density, brightness and center glow. Great for dramatic backgrounds, logo reveals, and VFX like energy bursts or sun shafts */\nexport { godRaysMeta, godRaysFragmentShader, type GodRaysParams, type GodRaysUniforms } from './shaders/god-rays.js';\n\n/** A single-colored animated spiral that morphs across a wide range of shapes - from crisp, thin-lined geometry to flowing whirlpool forms and wavy, abstract rings */\nexport { spiralFragmentShader, type SpiralParams, type SpiralUniforms } from './shaders/spiral.js';\n\n/** Animated bands of color twisting and bending, producing spirals, arcs, and flowing circular patterns */\nexport { swirlMeta, swirlFragmentShader, type SwirlParams, type SwirlUniforms } from './shaders/swirl.js';\n\n/** Animated 2-color dithering over with multiple pattern sources (noise, warp, dots, waves, ripple, swirl, sphere) */\nexport {\n ditheringFragmentShader,\n DitheringShapes,\n DitheringTypes,\n type DitheringParams,\n type DitheringUniforms,\n type DitheringShape,\n type DitheringType,\n} from './shaders/dithering.js';\n\n/** Multi-color gradients with grainy, noise-textured distortion available in 7 animated abstract forms */\nexport {\n grainGradientFragmentShader,\n grainGradientMeta,\n GrainGradientShapes,\n type GrainGradientParams,\n type GrainGradientUniforms,\n type GrainGradientShape,\n} from './shaders/grain-gradient.js';\n\n/** Luminous trails of color merging into a glowing gradient frame */\nexport {\n pulsingBorderMeta,\n pulsingBorderFragmentShader,\n PulsingBorderAspectRatios,\n type PulsingBorderParams,\n type PulsingBorderUniforms,\n type PulsingBorderAspectRatio,\n} from './shaders/pulsing-border.js';\n\n/** Glowing translucent 3D panels rotating around a central axis */\nexport {\n colorPanelsFragmentShader,\n colorPanelsMeta,\n type ColorPanelsParams,\n type ColorPanelsUniforms,\n} from './shaders/color-panels.js';\n\n/** Multi-point mesh gradients with up to 10 color spots, enhanced by two-direction warping, adjustable blend sharpness, and grain controls. Perfect for elegant wallpapers and atmospheric backdrops */\nexport {\n staticMeshGradientFragmentShader,\n staticMeshGradientMeta,\n type StaticMeshGradientParams,\n type StaticMeshGradientUniforms,\n} from './shaders/static-mesh-gradient.js';\n\n/** Radial gradient with up to 10 blended colors, featuring advanced focal point control, shape distortion, and grain effects */\nexport {\n staticRadialGradientFragmentShader,\n staticRadialGradientMeta,\n type StaticRadialGradientParams,\n type StaticRadialGradientUniforms,\n} from './shaders/static-radial-gradient.js';\n\n/** A static texture built from multiple noise layers, usable for a realistic paper and cardboard surfaces or generating abstract patterns. Can be used as a image filter or as a texture */\nexport {\n paperTextureFragmentShader,\n type PaperTextureParams,\n type PaperTextureUniforms,\n} from './shaders/paper-texture.js';\n\n/** Water-like surface distortion with natural caustic realism. Works as an image filter or animated texture without image */\nexport { waterFragmentShader, type WaterParams, type WaterUniforms } from './shaders/water.js';\n\n/** Fluted glass image filter transforms an image into streaked, ribbed distortions, giving a mix of clarity and obscurity */\nexport {\n flutedGlassFragmentShader,\n GlassDistortionShapes,\n GlassGridShapes,\n type GlassDistortionShape,\n type GlassGridShape,\n type FlutedGlassParams,\n type FlutedGlassUniforms,\n} from './shaders/fluted-glass.js';\n\n/** A dithering image filter with support for 4 dithering modes and multiple color palettes (2-color, 3-color, and multicolor options, using either predefined colors or ones sampled directly from the original image) */\nexport {\n imageDitheringFragmentShader,\n type ImageDitheringParams,\n type ImageDitheringUniforms,\n} from './shaders/image-dithering.js';\n\n/** Lens Distortion image filter that separates an image into shifting color layers, recreating the chromatic aberration of a lens, and warps the image geometry with barrel or pincushion curvature */\nexport { lensDistortionFragmentShader, lensDistortionMeta, type LensDistortionParams, type LensDistortionUniforms } from './shaders/lens-distortion.js';\n\n/** A glowing gradient of colors flowing through an input image. The effect creates a smoothly animated wave of intensity across the image */\nexport {\n heatmapMeta,\n heatmapFragmentShader,\n toProcessedHeatmap,\n type HeatmapParams,\n type HeatmapUniforms,\n} from './shaders/heatmap.js';\n\n/** Futuristic liquid metal material applied to uploaded logo or one of pre-defined abstract shape */\nexport {\n liquidMetalFragmentShader,\n LiquidMetalShapes,\n toProcessedLiquidMetal,\n type LiquidMetalShape,\n type LiquidMetalParams,\n type LiquidMetalUniforms,\n} from './shaders/liquid-metal.js';\n\n/** A halftone-dot image filter featuring customizable grids, color palettes, and dot styles */\nexport {\n HalftoneDotsTypes,\n HalftoneDotsGrids,\n halftoneDotsFragmentShader,\n type HalftoneDotsParams,\n type HalftoneDotsUniforms,\n type HalftoneDotsType,\n type HalftoneDotsGrid,\n} from './shaders/halftone-dots.js';\n\n/** A halftone CMYK classic algo */\nexport {\n HalftoneCmykTypes,\n halftoneCmykFragmentShader,\n type HalftoneCmykParams,\n type HalftoneCmykUniforms,\n type HalftoneCmykType,\n} from './shaders/halftone-cmyk.js';\n\n/** Animated color fields running around a glassy logo shape */\nexport {\n gemSmokeMeta,\n gemSmokeFragmentShader,\n toProcessedGemSmoke,\n GemSmokeShapes,\n type GemSmokeShape,\n type GemSmokeParams,\n type GemSmokeUniforms,\n} from './shaders/gem-smoke.js';\n\n// ----- Utils ----- //\nexport { getShaderColorFromString } from './get-shader-color-from-string.js';\nexport { getShaderNoiseTexture } from './get-shader-noise-texture.js';\nexport { emptyPixel } from './empty-pixel.js';\n"], + "mappings": ";;;;;AACA,SAAS,aAAa,4BAA4B;AAUlD;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAIK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAGP,SAAS,gCAAgF;AAGzF;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,OAIK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAGP,SAAS,iCAAmF;AAG5F,SAAS,aAAa,6BAAuE;AAG7F,SAAS,2BAAiE;AAG1E;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAIK;AAGP,SAAS,aAAa,6BAAuE;AAG7F,SAAS,4BAAoE;AAG7E,SAAS,WAAW,2BAAiE;AAGrF;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAKK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAIK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAIK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAGP;AAAA,EACE;AAAA,OAGK;AAGP,SAAS,2BAAiE;AAG1E;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAKK;AAGP;AAAA,EACE;AAAA,OAGK;AAGP,SAAS,8BAA8B,0BAAkF;AAGzH;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAIK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAKK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,OAIK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAIK;AAGP,SAAS,gCAAgC;AACzC,SAAS,6BAA6B;AACtC,SAAS,kBAAkB;", + "names": [] +} diff --git a/public/vendor/paper-shaders/shader-color-spaces.d.ts b/public/vendor/paper-shaders/shader-color-spaces.d.ts new file mode 100644 index 0000000..99aab8a --- /dev/null +++ b/public/vendor/paper-shaders/shader-color-spaces.d.ts @@ -0,0 +1,6 @@ +export declare const ShaderColorSpaces: { + readonly rgb: 0; + readonly oklch: 1; +}; +export type ShaderColorSpace = keyof typeof ShaderColorSpaces; +export declare const declareOklchTransforms = "\n\n// magic numbers (and magic could be better tbh)\n#define OKLCH_CHROMA_THRESHOLD .001\n#define OKLCH_HUE_NEUTRALIZER - 2.\n\nvec3 srgbToLinear(vec3 srgb) {\n return pow(srgb, vec3(2.2));\n}\n\nvec3 linearToSrgb(vec3 linear) {\n return pow(linear, vec3(1.0 / 2.2));\n}\n\nvec3 LrgbToOklab(vec3 rgb) {\n float L = pow(0.4122214708 * rgb.r + 0.5363325363 * rgb.g + 0.0514459929 * rgb.b, 1.0 / 3.0);\n float M = pow(0.2119034982 * rgb.r + 0.6806995451 * rgb.g + 0.1073969566 * rgb.b, 1.0 / 3.0);\n float S = pow(0.0883024619 * rgb.r + 0.2817188376 * rgb.g + 0.6299787005 * rgb.b, 1.0 / 3.0);\n return vec3(\n 0.2104542553 * L + 0.793617785 * M - 0.0040720468 * S,\n 1.9779984951 * L - 2.428592205 * M + 0.4505937099 * S,\n 0.0259040371 * L + 0.7827717662 * M - 0.808675766 * S\n );\n}\n\nvec3 OklabToLrgb(vec3 oklab) {\n float L = oklab.x;\n float a = oklab.y;\n float b = oklab.z;\n\n float l_ = L + 0.3963377774 * a + 0.2158037573 * b;\n float m_ = L - 0.1055613458 * a - 0.0638541728 * b;\n float s_ = L - 0.0894841775 * a - 1.291485548 * b;\n\n float l = l_ * l_ * l_;\n float m = m_ * m_ * m_;\n float s = s_ * s_ * s_;\n\n return vec3(\n 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s,\n -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s,\n -0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s\n );\n}\n\nvec3 oklabToOklch(vec3 oklab) {\n float C = length(oklab.yz);\n float H = atan(oklab.z, oklab.y);\n if (C < OKLCH_CHROMA_THRESHOLD) {\n H = OKLCH_HUE_NEUTRALIZER;\n }\n return vec3(oklab.x, C, H);\n}\n\nvec3 oklchToOklab(vec3 oklch) {\n float a = oklch.y * cos(oklch.z);\n float b = oklch.y * sin(oklch.z);\n return vec3(oklch.x, a, b);\n}\n\nfloat mixHue(float h1, float h2, float mixer) {\n float delta = mod(h2 - h1 + PI, TWO_PI) - PI;\n return h1 + mixer * delta;\n}\n\nvec3 srgbToOklab(vec3 rgb) {\n return oklabToOklch(LrgbToOklab(srgbToLinear(rgb)));\n}\n\nvec3 oklabToSrgb(vec3 oklab) {\n return linearToSrgb(OklabToLrgb(oklchToOklab(oklab)));\n}\n\nvec3 mixOklabVector(vec3 color1, vec3 color2, float mixer) {\n color1.x = mix(color1.x, color2.x, mixer);\n color1.y = mix(color1.y, color2.y, mixer);\n if (color1.y > OKLCH_CHROMA_THRESHOLD && color2.y > OKLCH_CHROMA_THRESHOLD) {\n color1.z = mixHue(color1.z, color2.z, mixer);\n }\n return color1;\n}\n"; diff --git a/public/vendor/paper-shaders/shader-color-spaces.js b/public/vendor/paper-shaders/shader-color-spaces.js new file mode 100644 index 0000000..7ad1dd1 --- /dev/null +++ b/public/vendor/paper-shaders/shader-color-spaces.js @@ -0,0 +1,96 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Paper Shaders * + * https://github.com/paper-design/shaders * + * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +const ShaderColorSpaces = { + rgb: 0, + oklch: 1 +}; +const declareOklchTransforms = ` + +// magic numbers (and magic could be better tbh) +#define OKLCH_CHROMA_THRESHOLD .001 +#define OKLCH_HUE_NEUTRALIZER - 2. + +vec3 srgbToLinear(vec3 srgb) { + return pow(srgb, vec3(2.2)); +} + +vec3 linearToSrgb(vec3 linear) { + return pow(linear, vec3(1.0 / 2.2)); +} + +vec3 LrgbToOklab(vec3 rgb) { + float L = pow(0.4122214708 * rgb.r + 0.5363325363 * rgb.g + 0.0514459929 * rgb.b, 1.0 / 3.0); + float M = pow(0.2119034982 * rgb.r + 0.6806995451 * rgb.g + 0.1073969566 * rgb.b, 1.0 / 3.0); + float S = pow(0.0883024619 * rgb.r + 0.2817188376 * rgb.g + 0.6299787005 * rgb.b, 1.0 / 3.0); + return vec3( + 0.2104542553 * L + 0.793617785 * M - 0.0040720468 * S, + 1.9779984951 * L - 2.428592205 * M + 0.4505937099 * S, + 0.0259040371 * L + 0.7827717662 * M - 0.808675766 * S + ); +} + +vec3 OklabToLrgb(vec3 oklab) { + float L = oklab.x; + float a = oklab.y; + float b = oklab.z; + + float l_ = L + 0.3963377774 * a + 0.2158037573 * b; + float m_ = L - 0.1055613458 * a - 0.0638541728 * b; + float s_ = L - 0.0894841775 * a - 1.291485548 * b; + + float l = l_ * l_ * l_; + float m = m_ * m_ * m_; + float s = s_ * s_ * s_; + + return vec3( + 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s, + -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s, + -0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s + ); +} + +vec3 oklabToOklch(vec3 oklab) { + float C = length(oklab.yz); + float H = atan(oklab.z, oklab.y); + if (C < OKLCH_CHROMA_THRESHOLD) { + H = OKLCH_HUE_NEUTRALIZER; + } + return vec3(oklab.x, C, H); +} + +vec3 oklchToOklab(vec3 oklch) { + float a = oklch.y * cos(oklch.z); + float b = oklch.y * sin(oklch.z); + return vec3(oklch.x, a, b); +} + +float mixHue(float h1, float h2, float mixer) { + float delta = mod(h2 - h1 + PI, TWO_PI) - PI; + return h1 + mixer * delta; +} + +vec3 srgbToOklab(vec3 rgb) { + return oklabToOklch(LrgbToOklab(srgbToLinear(rgb))); +} + +vec3 oklabToSrgb(vec3 oklab) { + return linearToSrgb(OklabToLrgb(oklchToOklab(oklab))); +} + +vec3 mixOklabVector(vec3 color1, vec3 color2, float mixer) { + color1.x = mix(color1.x, color2.x, mixer); + color1.y = mix(color1.y, color2.y, mixer); + if (color1.y > OKLCH_CHROMA_THRESHOLD && color2.y > OKLCH_CHROMA_THRESHOLD) { + color1.z = mixHue(color1.z, color2.z, mixer); + } + return color1; +} +`; +export { + ShaderColorSpaces, + declareOklchTransforms +}; +//# sourceMappingURL=shader-color-spaces.js.map diff --git a/public/vendor/paper-shaders/shader-color-spaces.js.map b/public/vendor/paper-shaders/shader-color-spaces.js.map new file mode 100644 index 0000000..0b5106e --- /dev/null +++ b/public/vendor/paper-shaders/shader-color-spaces.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../src/shader-color-spaces.ts"], + "sourcesContent": ["export const ShaderColorSpaces = {\n rgb: 0,\n oklch: 1,\n} as const;\n\nexport type ShaderColorSpace = keyof typeof ShaderColorSpaces;\n\nexport const declareOklchTransforms = `\n\n// magic numbers (and magic could be better tbh)\n#define OKLCH_CHROMA_THRESHOLD .001\n#define OKLCH_HUE_NEUTRALIZER - 2.\n\nvec3 srgbToLinear(vec3 srgb) {\n return pow(srgb, vec3(2.2));\n}\n\nvec3 linearToSrgb(vec3 linear) {\n return pow(linear, vec3(1.0 / 2.2));\n}\n\nvec3 LrgbToOklab(vec3 rgb) {\n float L = pow(0.4122214708 * rgb.r + 0.5363325363 * rgb.g + 0.0514459929 * rgb.b, 1.0 / 3.0);\n float M = pow(0.2119034982 * rgb.r + 0.6806995451 * rgb.g + 0.1073969566 * rgb.b, 1.0 / 3.0);\n float S = pow(0.0883024619 * rgb.r + 0.2817188376 * rgb.g + 0.6299787005 * rgb.b, 1.0 / 3.0);\n return vec3(\n 0.2104542553 * L + 0.793617785 * M - 0.0040720468 * S,\n 1.9779984951 * L - 2.428592205 * M + 0.4505937099 * S,\n 0.0259040371 * L + 0.7827717662 * M - 0.808675766 * S\n );\n}\n\nvec3 OklabToLrgb(vec3 oklab) {\n float L = oklab.x;\n float a = oklab.y;\n float b = oklab.z;\n\n float l_ = L + 0.3963377774 * a + 0.2158037573 * b;\n float m_ = L - 0.1055613458 * a - 0.0638541728 * b;\n float s_ = L - 0.0894841775 * a - 1.291485548 * b;\n\n float l = l_ * l_ * l_;\n float m = m_ * m_ * m_;\n float s = s_ * s_ * s_;\n\n return vec3(\n 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s,\n -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s,\n -0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s\n );\n}\n\nvec3 oklabToOklch(vec3 oklab) {\n float C = length(oklab.yz);\n float H = atan(oklab.z, oklab.y);\n if (C < OKLCH_CHROMA_THRESHOLD) {\n H = OKLCH_HUE_NEUTRALIZER;\n }\n return vec3(oklab.x, C, H);\n}\n\nvec3 oklchToOklab(vec3 oklch) {\n float a = oklch.y * cos(oklch.z);\n float b = oklch.y * sin(oklch.z);\n return vec3(oklch.x, a, b);\n}\n\nfloat mixHue(float h1, float h2, float mixer) {\n float delta = mod(h2 - h1 + PI, TWO_PI) - PI;\n return h1 + mixer * delta;\n}\n\nvec3 srgbToOklab(vec3 rgb) {\n return oklabToOklch(LrgbToOklab(srgbToLinear(rgb)));\n}\n\nvec3 oklabToSrgb(vec3 oklab) {\n return linearToSrgb(OklabToLrgb(oklchToOklab(oklab)));\n}\n\nvec3 mixOklabVector(vec3 color1, vec3 color2, float mixer) {\n color1.x = mix(color1.x, color2.x, mixer);\n color1.y = mix(color1.y, color2.y, mixer);\n if (color1.y > OKLCH_CHROMA_THRESHOLD && color2.y > OKLCH_CHROMA_THRESHOLD) {\n color1.z = mixHue(color1.z, color2.z, mixer);\n }\n return color1;\n}\n`;\n"], + "mappings": ";;;;;AAAO,MAAM,oBAAoB;AAAA,EAC/B,KAAK;AAAA,EACL,OAAO;AACT;AAIO,MAAM,yBAAyB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;", + "names": [] +} diff --git a/public/vendor/paper-shaders/shader-mount.d.ts b/public/vendor/paper-shaders/shader-mount.d.ts new file mode 100644 index 0000000..5983e8a --- /dev/null +++ b/public/vendor/paper-shaders/shader-mount.d.ts @@ -0,0 +1,140 @@ +export declare class ShaderMount { + parentElement: PaperShaderElement; + canvasElement: HTMLCanvasElement; + private gl; + private program; + private uniformLocations; + /** The fragment shader that we are using */ + private fragmentShader; + /** Stores the RAF for the render loop */ + private rafId; + /** Time of the last rendered frame */ + private lastRenderTime; + /** Total time that we have played any animation, passed as a uniform to the shader for time-based VFX */ + private currentFrame; + /** The speed that we progress through animation time (multiplies by delta time every update). Allows negatives to play in reverse. If set to 0, rAF will stop entirely so static shaders have no recurring performance costs */ + private speed; + /** Actual speed used that accounts for visibility: we pause the shader if the tab is hidden or the element out of the viewport */ + private currentSpeed; + /** Uniforms that are provided by the user for the specific shader being mounted (not including uniforms that this Mount adds, like time and resolution) */ + private providedUniforms; + /** Names of the uniforms that should have mipmaps generated for them */ + private mipmaps; + /** Just a sanity check to make sure frames don't run after we're disposed */ + private hasBeenDisposed; + /** If the resolution of the canvas has changed since the last render */ + private resolutionChanged; + /** Store textures that are provided by the user */ + private textures; + private minPixelRatio; + private maxPixelCount; + private isSafari; + private uniformCache; + private textureUnitMap; + private ownerDocument; + constructor( + /** The div you'd like to mount the shader to. The shader will match its size. */ + parentElement: HTMLElement, fragmentShader: string, uniforms: ShaderMountUniforms, webGlContextAttributes?: WebGLContextAttributes, + /** The speed of the animation, or 0 to stop it. Supports negative values to play in reverse. */ + speed?: number, + /** Pass a frame to offset the starting u_time value and give deterministic results*/ + frame?: number, + /** + * The minimum pixel ratio to render at, defaults to 2. + * May be reduced to improve performance or increased together with `maxPixelCount` to improve antialiasing. + */ + minPixelRatio?: number, + /** + * The maximum amount of physical device pixels to render for the shader, + * by default it's 1920 * 1080 * 2x dpi (per each side) = 8,294,400 pixels of a 4K screen. + * Actual DOM size of the canvas can be larger, it will just lose quality after this. + * + * May be reduced to improve performance or increased to improve quality on high-resolution screens. + */ + maxPixelCount?: number, + /** Names of the uniforms that should have mipmaps generated for them */ + mipmaps?: string[]); + private initProgram; + private setupPositionAttribute; + private setupUniforms; + /** + * The scale that we should render at. + * - Used to target 2x rendering even on 1x screens for better antialiasing + * - Prevents the virtual resolution from going beyond the maximum resolution + * - Accounts for the page zoom level so we render in physical device pixels rather than CSS pixels + */ + private renderScale; + private parentWidth; + private parentHeight; + private parentDevicePixelWidth; + private parentDevicePixelHeight; + private devicePixelsSupported; + private intersectionObserver; + private isInViewport; + private resizeObserver; + private setupResizeObserver; + private setupIntersectionObserver; + private handleVisualViewportChange; + /** Resize handler for when the container div changes size or the max pixel count changes and we want to resize our canvas to match */ + private handleResize; + private render; + private requestRender; + /** Creates a texture from an image and sets it into a uniform value */ + private setTextureUniform; + /** Utility: recursive equality test for all the uniforms */ + private areUniformValuesEqual; + /** Sets the provided uniform values into the WebGL program, can be a partial list of uniforms that have changed */ + private setUniformValues; + /** Gets the current total animation time from 0ms */ + getCurrentFrame: () => number; + /** Set a frame to get a deterministic result, frames are literally just milliseconds from zero since the animation started */ + setFrame: (newFrame: number) => void; + /** Set an animation speed (or 0 to stop animation) */ + setSpeed: (newSpeed?: number) => void; + /** Apply the target speed, pausing (0) while the tab is hidden or the element is out of the viewport */ + private updateCurrentSpeed; + private setCurrentSpeed; + /** Set the maximum pixel count for the shader, this will limit the number of pixels that will be rendered */ + setMaxPixelCount: (newMaxPixelCount?: number) => void; + /** Set the minimum pixel ratio for the shader */ + setMinPixelRatio: (newMinPixelRatio?: number) => void; + /** Update the uniforms that are provided by the outside shader, can be a partial set with only the uniforms that have changed */ + setUniforms: (newUniforms: ShaderMountUniforms) => void; + private handleDocumentVisibilityChange; + /** Dispose of the shader mount, cleaning up all of the WebGL resources */ + dispose: () => void; +} +/** The parent `

    +wJm5{j{z&V(xBmt+F*1@$m3-GRC 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

  • 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%0AE2`OU5 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