@basementstudio/shader-lab 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (261) hide show
  1. package/.biome/plugins/README.md +21 -0
  2. package/.biome/plugins/no-anchor-element.grit +12 -0
  3. package/.biome/plugins/no-relative-parent-imports.grit +10 -0
  4. package/.biome/plugins/no-unnecessary-forwardref.grit +9 -0
  5. package/.changeset/README.md +17 -0
  6. package/.changeset/config.json +11 -0
  7. package/.editorconfig +40 -0
  8. package/.env.example +81 -0
  9. package/.gitattributes +19 -0
  10. package/.github/workflows/canary.yml +80 -0
  11. package/.github/workflows/ci.yml +37 -0
  12. package/.github/workflows/release.yml +56 -0
  13. package/.tldrignore +84 -0
  14. package/.vscode/extensions.json +20 -0
  15. package/.vscode/settings.json +105 -0
  16. package/README.md +119 -0
  17. package/biome.json +249 -0
  18. package/bun.lock +1224 -0
  19. package/next.config.ts +131 -0
  20. package/package.json +73 -0
  21. package/packages/shader-lab-react/CHANGELOG.md +9 -0
  22. package/packages/shader-lab-react/README.md +119 -0
  23. package/packages/shader-lab-react/assets/patterns/bars/1.svg +3 -0
  24. package/packages/shader-lab-react/assets/patterns/bars/2.svg +3 -0
  25. package/packages/shader-lab-react/assets/patterns/bars/3.svg +3 -0
  26. package/packages/shader-lab-react/assets/patterns/bars/4.svg +3 -0
  27. package/packages/shader-lab-react/assets/patterns/bars/5.svg +3 -0
  28. package/packages/shader-lab-react/assets/patterns/bars/6.svg +3 -0
  29. package/packages/shader-lab-react/assets/patterns/candles/1.svg +3 -0
  30. package/packages/shader-lab-react/assets/patterns/candles/2.svg +3 -0
  31. package/packages/shader-lab-react/assets/patterns/candles/3.svg +3 -0
  32. package/packages/shader-lab-react/assets/patterns/candles/4.svg +3 -0
  33. package/packages/shader-lab-react/assets/patterns/shapes/1.svg +3 -0
  34. package/packages/shader-lab-react/assets/patterns/shapes/2.svg +3 -0
  35. package/packages/shader-lab-react/assets/patterns/shapes/3.svg +3 -0
  36. package/packages/shader-lab-react/assets/patterns/shapes/4.svg +4 -0
  37. package/packages/shader-lab-react/assets/patterns/shapes/5.svg +3 -0
  38. package/packages/shader-lab-react/assets/patterns/shapes/6.svg +4 -0
  39. package/packages/shader-lab-react/assets/textures/blue-noise.png +0 -0
  40. package/packages/shader-lab-react/package.json +36 -0
  41. package/packages/shader-lab-react/scripts/fix-esm-specifiers.mjs +57 -0
  42. package/packages/shader-lab-react/scripts/prepare-dist.mjs +4 -0
  43. package/packages/shader-lab-react/src/ambient/three-tsl.d.ts +146 -0
  44. package/packages/shader-lab-react/src/ambient/three-webgpu.d.ts +51 -0
  45. package/packages/shader-lab-react/src/easings.ts +4 -0
  46. package/packages/shader-lab-react/src/index.ts +35 -0
  47. package/packages/shader-lab-react/src/lib/editor/custom-shader/shared.ts +2 -0
  48. package/packages/shader-lab-react/src/renderer/ascii-atlas.ts +83 -0
  49. package/packages/shader-lab-react/src/renderer/ascii-pass.ts +416 -0
  50. package/packages/shader-lab-react/src/renderer/asset-url.ts +3 -0
  51. package/packages/shader-lab-react/src/renderer/blend-modes.ts +229 -0
  52. package/packages/shader-lab-react/src/renderer/contracts.ts +54 -0
  53. package/packages/shader-lab-react/src/renderer/create-webgpu-renderer.ts +48 -0
  54. package/packages/shader-lab-react/src/renderer/crt-pass.ts +1040 -0
  55. package/packages/shader-lab-react/src/renderer/custom-shader-pass.ts +108 -0
  56. package/packages/shader-lab-react/src/renderer/custom-shader-runtime.ts +309 -0
  57. package/packages/shader-lab-react/src/renderer/dither-textures.ts +99 -0
  58. package/packages/shader-lab-react/src/renderer/dithering-pass.ts +322 -0
  59. package/packages/shader-lab-react/src/renderer/gradient-pass.ts +521 -0
  60. package/packages/shader-lab-react/src/renderer/halftone-pass.ts +932 -0
  61. package/packages/shader-lab-react/src/renderer/ink-pass.ts +802 -0
  62. package/packages/shader-lab-react/src/renderer/live-pass.ts +194 -0
  63. package/packages/shader-lab-react/src/renderer/media-pass.ts +187 -0
  64. package/packages/shader-lab-react/src/renderer/media-texture.ts +66 -0
  65. package/packages/shader-lab-react/src/renderer/particle-grid-pass.ts +389 -0
  66. package/packages/shader-lab-react/src/renderer/pass-node.ts +209 -0
  67. package/packages/shader-lab-react/src/renderer/pattern-atlas.ts +133 -0
  68. package/packages/shader-lab-react/src/renderer/pattern-pass.ts +552 -0
  69. package/packages/shader-lab-react/src/renderer/pipeline-manager.ts +369 -0
  70. package/packages/shader-lab-react/src/renderer/pixel-sorting-pass.ts +277 -0
  71. package/packages/shader-lab-react/src/renderer/shaders/tsl/color/tonemapping.ts +87 -0
  72. package/packages/shader-lab-react/src/renderer/shaders/tsl/cosine-palette.ts +9 -0
  73. package/packages/shader-lab-react/src/renderer/shaders/tsl/noise/common.ts +31 -0
  74. package/packages/shader-lab-react/src/renderer/shaders/tsl/noise/curl-noise-3d.ts +36 -0
  75. package/packages/shader-lab-react/src/renderer/shaders/tsl/noise/curl-noise-4d.ts +36 -0
  76. package/packages/shader-lab-react/src/renderer/shaders/tsl/noise/fbm.ts +13 -0
  77. package/packages/shader-lab-react/src/renderer/shaders/tsl/noise/perlin-noise-3d.ts +96 -0
  78. package/packages/shader-lab-react/src/renderer/shaders/tsl/noise/ridge-noise.ts +24 -0
  79. package/packages/shader-lab-react/src/renderer/shaders/tsl/noise/simplex-noise-3d.ts +79 -0
  80. package/packages/shader-lab-react/src/renderer/shaders/tsl/noise/simplex-noise-4d.ts +89 -0
  81. package/packages/shader-lab-react/src/renderer/shaders/tsl/noise/turbulence.ts +56 -0
  82. package/packages/shader-lab-react/src/renderer/shaders/tsl/noise/value-noise-3d.ts +32 -0
  83. package/packages/shader-lab-react/src/renderer/shaders/tsl/noise/voronoi-noise-3d.ts +60 -0
  84. package/packages/shader-lab-react/src/renderer/shaders/tsl/patterns/bloom-edge-pattern.ts +15 -0
  85. package/packages/shader-lab-react/src/renderer/shaders/tsl/patterns/bloom.ts +11 -0
  86. package/packages/shader-lab-react/src/renderer/shaders/tsl/patterns/canvas-weave-pattern.ts +24 -0
  87. package/packages/shader-lab-react/src/renderer/shaders/tsl/patterns/grain-texture-pattern.ts +9 -0
  88. package/packages/shader-lab-react/src/renderer/shaders/tsl/patterns/repeating-pattern.ts +11 -0
  89. package/packages/shader-lab-react/src/renderer/shaders/tsl/utils/atan2.ts +9 -0
  90. package/packages/shader-lab-react/src/renderer/shaders/tsl/utils/complex-conj.ts +9 -0
  91. package/packages/shader-lab-react/src/renderer/shaders/tsl/utils/complex-cos.ts +10 -0
  92. package/packages/shader-lab-react/src/renderer/shaders/tsl/utils/complex-div.ts +11 -0
  93. package/packages/shader-lab-react/src/renderer/shaders/tsl/utils/complex-log.ts +7 -0
  94. package/packages/shader-lab-react/src/renderer/shaders/tsl/utils/complex-mobius.ts +12 -0
  95. package/packages/shader-lab-react/src/renderer/shaders/tsl/utils/complex-mul.ts +9 -0
  96. package/packages/shader-lab-react/src/renderer/shaders/tsl/utils/complex-pow.ts +16 -0
  97. package/packages/shader-lab-react/src/renderer/shaders/tsl/utils/complex-sin.ts +10 -0
  98. package/packages/shader-lab-react/src/renderer/shaders/tsl/utils/complex-sqrt.ts +18 -0
  99. package/packages/shader-lab-react/src/renderer/shaders/tsl/utils/complex-tan.ts +12 -0
  100. package/packages/shader-lab-react/src/renderer/shaders/tsl/utils/complex-to-polar.ts +10 -0
  101. package/packages/shader-lab-react/src/renderer/shaders/tsl/utils/hyperbolic.ts +20 -0
  102. package/packages/shader-lab-react/src/renderer/shaders/tsl/utils/index.ts +48 -0
  103. package/packages/shader-lab-react/src/renderer/shaders/tsl/utils/rotate.ts +15 -0
  104. package/packages/shader-lab-react/src/renderer/shaders/tsl/utils/screen-aspect-uv.ts +15 -0
  105. package/packages/shader-lab-react/src/renderer/shaders/tsl/utils/sd-box-2d.ts +6 -0
  106. package/packages/shader-lab-react/src/renderer/shaders/tsl/utils/sd-diamond.ts +6 -0
  107. package/packages/shader-lab-react/src/renderer/shaders/tsl/utils/sd-rhombus.ts +27 -0
  108. package/packages/shader-lab-react/src/renderer/shaders/tsl/utils/sd-sphere.ts +6 -0
  109. package/packages/shader-lab-react/src/renderer/shaders/tsl/utils/smax.ts +7 -0
  110. package/packages/shader-lab-react/src/renderer/shaders/tsl/utils/smin.ts +7 -0
  111. package/packages/shader-lab-react/src/renderer/text-pass.ts +176 -0
  112. package/packages/shader-lab-react/src/runtime-clock.ts +42 -0
  113. package/packages/shader-lab-react/src/runtime-frame.ts +29 -0
  114. package/packages/shader-lab-react/src/shader-lab-composition.tsx +163 -0
  115. package/packages/shader-lab-react/src/timeline.ts +283 -0
  116. package/packages/shader-lab-react/src/types/editor.ts +5 -0
  117. package/packages/shader-lab-react/src/types.ts +141 -0
  118. package/packages/shader-lab-react/tsconfig.build.json +8 -0
  119. package/packages/shader-lab-react/tsconfig.json +21 -0
  120. package/postcss.config.mjs +5 -0
  121. package/public/assets/fonts/msdf/geist-mono/GeistMono-Regular-msdf-atlas.png +0 -0
  122. package/public/assets/fonts/msdf/geist-mono/GeistMono-Regular-msdf.json +1412 -0
  123. package/public/assets/patterns/bars/1.svg +3 -0
  124. package/public/assets/patterns/bars/2.svg +3 -0
  125. package/public/assets/patterns/bars/3.svg +3 -0
  126. package/public/assets/patterns/bars/4.svg +3 -0
  127. package/public/assets/patterns/bars/5.svg +3 -0
  128. package/public/assets/patterns/bars/6.svg +3 -0
  129. package/public/assets/patterns/candles/1.svg +3 -0
  130. package/public/assets/patterns/candles/2.svg +3 -0
  131. package/public/assets/patterns/candles/3.svg +3 -0
  132. package/public/assets/patterns/candles/4.svg +3 -0
  133. package/public/assets/patterns/shapes/1.svg +3 -0
  134. package/public/assets/patterns/shapes/2.svg +3 -0
  135. package/public/assets/patterns/shapes/3.svg +3 -0
  136. package/public/assets/patterns/shapes/4.svg +4 -0
  137. package/public/assets/patterns/shapes/5.svg +3 -0
  138. package/public/assets/patterns/shapes/6.svg +4 -0
  139. package/public/fonts/geist/Geist-Mono.woff2 +0 -0
  140. package/public/textures/blue-noise.png +0 -0
  141. package/public/textures/crt-mask.png +0 -0
  142. package/src/app/design/page.tsx +398 -0
  143. package/src/app/favicon.ico +0 -0
  144. package/src/app/globals.css +280 -0
  145. package/src/app/layout.tsx +89 -0
  146. package/src/app/page.tsx +20 -0
  147. package/src/app/robots.ts +13 -0
  148. package/src/app/sitemap.ts +13 -0
  149. package/src/components/editor/editor-canvas-viewport.tsx +116 -0
  150. package/src/components/editor/editor-export-dialog.tsx +1177 -0
  151. package/src/components/editor/editor-timeline-overlay.tsx +983 -0
  152. package/src/components/editor/editor-topbar.tsx +287 -0
  153. package/src/components/editor/layer-sidebar.tsx +738 -0
  154. package/src/components/editor/properties-sidebar-content.tsx +574 -0
  155. package/src/components/editor/properties-sidebar-fields.tsx +389 -0
  156. package/src/components/editor/properties-sidebar-utils.ts +178 -0
  157. package/src/components/editor/properties-sidebar.tsx +421 -0
  158. package/src/components/ui/button/index.tsx +57 -0
  159. package/src/components/ui/color-picker/index.tsx +358 -0
  160. package/src/components/ui/glass-panel/index.tsx +45 -0
  161. package/src/components/ui/icon-button/index.tsx +46 -0
  162. package/src/components/ui/select/index.tsx +136 -0
  163. package/src/components/ui/slider/index.tsx +192 -0
  164. package/src/components/ui/toggle/index.tsx +34 -0
  165. package/src/components/ui/typography/index.tsx +61 -0
  166. package/src/components/ui/xy-pad/index.tsx +160 -0
  167. package/src/features/editor/components/editor-export-dialog.module.css +271 -0
  168. package/src/hooks/use-editor-renderer.ts +182 -0
  169. package/src/lib/app.ts +6 -0
  170. package/src/lib/cn.ts +7 -0
  171. package/src/lib/easings.ts +240 -0
  172. package/src/lib/editor/config/layer-registry.ts +2434 -0
  173. package/src/lib/editor/custom-shader/shared.ts +28 -0
  174. package/src/lib/editor/export.ts +420 -0
  175. package/src/lib/editor/history.ts +71 -0
  176. package/src/lib/editor/layers.ts +76 -0
  177. package/src/lib/editor/parameter-schema.ts +75 -0
  178. package/src/lib/editor/project-file.ts +145 -0
  179. package/src/lib/editor/shader-export-snippet.ts +37 -0
  180. package/src/lib/editor/shader-export.ts +315 -0
  181. package/src/lib/editor/timeline/evaluate.ts +252 -0
  182. package/src/lib/editor/view-transform.ts +58 -0
  183. package/src/lib/fonts.ts +28 -0
  184. package/src/renderer/ascii-atlas.ts +83 -0
  185. package/src/renderer/ascii-pass.ts +416 -0
  186. package/src/renderer/blend-modes.ts +229 -0
  187. package/src/renderer/contracts.ts +161 -0
  188. package/src/renderer/create-webgpu-renderer.ts +48 -0
  189. package/src/renderer/crt-pass.ts +1040 -0
  190. package/src/renderer/custom-shader-pass.ts +117 -0
  191. package/src/renderer/custom-shader-runtime.ts +309 -0
  192. package/src/renderer/dither-textures.ts +99 -0
  193. package/src/renderer/dithering-pass.ts +322 -0
  194. package/src/renderer/gradient-pass.ts +520 -0
  195. package/src/renderer/halftone-pass.ts +932 -0
  196. package/src/renderer/ink-pass.ts +683 -0
  197. package/src/renderer/live-pass.ts +194 -0
  198. package/src/renderer/media-pass.ts +187 -0
  199. package/src/renderer/media-texture.ts +66 -0
  200. package/src/renderer/particle-grid-pass.ts +389 -0
  201. package/src/renderer/pass-node-factory.ts +33 -0
  202. package/src/renderer/pass-node.ts +209 -0
  203. package/src/renderer/pattern-atlas.ts +97 -0
  204. package/src/renderer/pattern-pass.ts +552 -0
  205. package/src/renderer/pipeline-manager.ts +343 -0
  206. package/src/renderer/pixel-sorting-pass.ts +277 -0
  207. package/src/renderer/project-clock.ts +57 -0
  208. package/src/renderer/shaders/tsl/color/tonemapping.ts +86 -0
  209. package/src/renderer/shaders/tsl/cosine-palette.ts +8 -0
  210. package/src/renderer/shaders/tsl/noise/common.ts +30 -0
  211. package/src/renderer/shaders/tsl/noise/curl-noise-3d.ts +35 -0
  212. package/src/renderer/shaders/tsl/noise/curl-noise-4d.ts +35 -0
  213. package/src/renderer/shaders/tsl/noise/fbm.ts +12 -0
  214. package/src/renderer/shaders/tsl/noise/perlin-noise-3d.ts +97 -0
  215. package/src/renderer/shaders/tsl/noise/ridge-noise.ts +23 -0
  216. package/src/renderer/shaders/tsl/noise/simplex-noise-3d.ts +78 -0
  217. package/src/renderer/shaders/tsl/noise/simplex-noise-4d.ts +88 -0
  218. package/src/renderer/shaders/tsl/noise/turbulence.ts +55 -0
  219. package/src/renderer/shaders/tsl/noise/value-noise-3d.ts +31 -0
  220. package/src/renderer/shaders/tsl/noise/voronoi-noise-3d.ts +59 -0
  221. package/src/renderer/shaders/tsl/patterns/bloom-edge-pattern.ts +14 -0
  222. package/src/renderer/shaders/tsl/patterns/bloom.ts +10 -0
  223. package/src/renderer/shaders/tsl/patterns/canvas-weave-pattern.ts +23 -0
  224. package/src/renderer/shaders/tsl/patterns/grain-texture-pattern.ts +8 -0
  225. package/src/renderer/shaders/tsl/patterns/repeating-pattern.ts +10 -0
  226. package/src/renderer/shaders/tsl/utils/atan2.ts +8 -0
  227. package/src/renderer/shaders/tsl/utils/complex-conj.ts +8 -0
  228. package/src/renderer/shaders/tsl/utils/complex-cos.ts +9 -0
  229. package/src/renderer/shaders/tsl/utils/complex-div.ts +10 -0
  230. package/src/renderer/shaders/tsl/utils/complex-log.ts +6 -0
  231. package/src/renderer/shaders/tsl/utils/complex-mobius.ts +11 -0
  232. package/src/renderer/shaders/tsl/utils/complex-mul.ts +8 -0
  233. package/src/renderer/shaders/tsl/utils/complex-pow.ts +15 -0
  234. package/src/renderer/shaders/tsl/utils/complex-sin.ts +9 -0
  235. package/src/renderer/shaders/tsl/utils/complex-sqrt.ts +17 -0
  236. package/src/renderer/shaders/tsl/utils/complex-tan.ts +11 -0
  237. package/src/renderer/shaders/tsl/utils/complex-to-polar.ts +9 -0
  238. package/src/renderer/shaders/tsl/utils/hyperbolic.ts +19 -0
  239. package/src/renderer/shaders/tsl/utils/index.ts +47 -0
  240. package/src/renderer/shaders/tsl/utils/rotate.ts +14 -0
  241. package/src/renderer/shaders/tsl/utils/screen-aspect-uv.ts +14 -0
  242. package/src/renderer/shaders/tsl/utils/sd-box-2d.ts +5 -0
  243. package/src/renderer/shaders/tsl/utils/sd-diamond.ts +5 -0
  244. package/src/renderer/shaders/tsl/utils/sd-rhombus.ts +26 -0
  245. package/src/renderer/shaders/tsl/utils/sd-sphere.ts +5 -0
  246. package/src/renderer/shaders/tsl/utils/smax.ts +7 -0
  247. package/src/renderer/shaders/tsl/utils/smin.ts +6 -0
  248. package/src/renderer/text-pass.ts +176 -0
  249. package/src/store/asset-store.ts +193 -0
  250. package/src/store/editor-store.ts +223 -0
  251. package/src/store/history-store.ts +172 -0
  252. package/src/store/index.ts +31 -0
  253. package/src/store/layer-store.ts +675 -0
  254. package/src/store/timeline-store.ts +572 -0
  255. package/src/types/assets.d.ts +6 -0
  256. package/src/types/css.d.ts +21 -0
  257. package/src/types/editor.ts +357 -0
  258. package/src/types/react.d.ts +15 -0
  259. package/src/types/three-tsl.d.ts +146 -0
  260. package/src/types/three-webgpu.d.ts +51 -0
  261. package/tsconfig.json +49 -0
@@ -0,0 +1,521 @@
1
+ import {
2
+ clamp,
3
+ cos,
4
+ dot,
5
+ Fn,
6
+ float,
7
+ max,
8
+ mix,
9
+ pow,
10
+ select,
11
+ sin,
12
+ smoothstep,
13
+ type TSLNode,
14
+ uniform,
15
+ uv,
16
+ vec2,
17
+ vec3,
18
+ vec4,
19
+ } from "three/tsl"
20
+ import type { LayerParameterValues } from "../types/editor"
21
+ import { PassNode } from "./pass-node"
22
+ import {
23
+ acesTonemap,
24
+ cinematicTonemap,
25
+ reinhardTonemap,
26
+ totosTonemap,
27
+ } from "./shaders/tsl/color/tonemapping"
28
+ import { perlinNoise3d } from "./shaders/tsl/noise/perlin-noise-3d"
29
+ import { ridgeNoise } from "./shaders/tsl/noise/ridge-noise"
30
+ import { simplexNoise3d } from "./shaders/tsl/noise/simplex-noise-3d"
31
+ import { turbulence } from "./shaders/tsl/noise/turbulence"
32
+ import { valueNoise3d } from "./shaders/tsl/noise/value-noise-3d"
33
+ import { voronoiNoise3d } from "./shaders/tsl/noise/voronoi-noise-3d"
34
+ import { grainTexturePattern } from "./shaders/tsl/patterns/grain-texture-pattern"
35
+
36
+ type Node = TSLNode
37
+ type NoiseMode =
38
+ | "perlin"
39
+ | "ridge"
40
+ | "simplex"
41
+ | "turbulence"
42
+ | "value"
43
+ | "voronoi"
44
+ type TonemapMode = "aces" | "cinematic" | "none" | "reinhard" | "totos"
45
+
46
+ function hexToRgb(hex: string): [number, number, number] {
47
+ const normalized = hex.trim().replace("#", "")
48
+ const value =
49
+ normalized.length === 3
50
+ ? normalized
51
+ .split("")
52
+ .map((entry) => `${entry}${entry}`)
53
+ .join("")
54
+ : normalized.padEnd(6, "0").slice(0, 6)
55
+
56
+ return [
57
+ Number.parseInt(value.slice(0, 2), 16) / 255,
58
+ Number.parseInt(value.slice(2, 4), 16) / 255,
59
+ Number.parseInt(value.slice(4, 6), 16) / 255,
60
+ ]
61
+ }
62
+
63
+ export class GradientPass extends PassNode {
64
+ private readonly activePointsUniform: Node
65
+ private readonly animateUniform: Node
66
+ private readonly aspectUniform: Node
67
+ private readonly falloffUniform: Node
68
+ private readonly glowStrengthUniform: Node
69
+ private readonly glowThresholdUniform: Node
70
+ private readonly grainAmountUniform: Node
71
+ private readonly motionAmountUniform: Node
72
+ private readonly motionSpeedUniform: Node
73
+ private readonly pointColorUniforms: {
74
+ blue: Node
75
+ green: Node
76
+ red: Node
77
+ }[]
78
+ private readonly pointPositionUniforms: {
79
+ x: Node
80
+ y: Node
81
+ }[]
82
+ private readonly pointWeightUniforms: Node[]
83
+ private readonly timeUniform: Node
84
+ private readonly vignetteRadiusUniform: Node
85
+ private readonly vignetteSoftnessUniform: Node
86
+ private readonly vignetteStrengthUniform: Node
87
+ private noiseSeed = 0
88
+ private readonly vortexAmountUniform: Node
89
+ private readonly warpAmountUniform: Node
90
+ private readonly warpBiasUniform: Node
91
+ private readonly warpDecayUniform: Node
92
+ private readonly warpScaleUniform: Node
93
+
94
+ private isAnimated = true
95
+ private noiseMode: NoiseMode = "simplex"
96
+ private tonemapMode: TonemapMode = "aces"
97
+ private warpIterations = 1
98
+
99
+ constructor(layerId: string) {
100
+ super(layerId)
101
+ this.timeUniform = uniform(0)
102
+ this.animateUniform = uniform(1)
103
+ this.aspectUniform = uniform(1)
104
+ this.activePointsUniform = uniform(5)
105
+ this.warpAmountUniform = uniform(0.18)
106
+ this.warpBiasUniform = uniform(0.5)
107
+ this.warpDecayUniform = uniform(1)
108
+ this.warpScaleUniform = uniform(1.4)
109
+ this.vortexAmountUniform = uniform(0.12)
110
+ this.motionAmountUniform = uniform(0.18)
111
+ this.motionSpeedUniform = uniform(0.2)
112
+ this.falloffUniform = uniform(1.85)
113
+ this.glowStrengthUniform = uniform(0.18)
114
+ this.glowThresholdUniform = uniform(0.62)
115
+ this.grainAmountUniform = uniform(0.03)
116
+ this.vignetteStrengthUniform = uniform(0.18)
117
+ this.vignetteRadiusUniform = uniform(0.9)
118
+ this.vignetteSoftnessUniform = uniform(0.32)
119
+ this.pointColorUniforms = Array.from({ length: 5 }, () => ({
120
+ blue: uniform(1),
121
+ green: uniform(1),
122
+ red: uniform(1),
123
+ }))
124
+ this.pointPositionUniforms = Array.from({ length: 5 }, () => ({
125
+ x: uniform(0),
126
+ y: uniform(0),
127
+ }))
128
+ this.pointWeightUniforms = Array.from({ length: 5 }, () => uniform(1))
129
+ this.rebuildEffectNode()
130
+ }
131
+
132
+ override updateParams(params: LayerParameterValues): void {
133
+ const activePoints =
134
+ typeof params.activePoints === "number"
135
+ ? Math.max(2, Math.min(5, Math.round(params.activePoints)))
136
+ : 5
137
+ const noiseSeed =
138
+ typeof params.noiseSeed === "number" ? params.noiseSeed : 0
139
+ const warpAmount =
140
+ typeof params.warpAmount === "number"
141
+ ? Math.max(0, params.warpAmount)
142
+ : 0.18
143
+ const warpScale =
144
+ typeof params.warpScale === "number"
145
+ ? Math.max(0.05, params.warpScale)
146
+ : 1.4
147
+ const warpIterations =
148
+ typeof params.warpIterations === "number"
149
+ ? Math.max(1, Math.min(5, Math.round(params.warpIterations)))
150
+ : 1
151
+ const warpDecay =
152
+ typeof params.warpDecay === "number" ? Math.max(0.1, params.warpDecay) : 1
153
+ const warpBias =
154
+ typeof params.warpBias === "number"
155
+ ? Math.max(0, Math.min(1, params.warpBias))
156
+ : 0.5
157
+ const vortexAmount =
158
+ typeof params.vortexAmount === "number" ? params.vortexAmount : 0.12
159
+ const motionAmount =
160
+ typeof params.motionAmount === "number"
161
+ ? Math.max(0, params.motionAmount)
162
+ : 0.18
163
+ const motionSpeed =
164
+ typeof params.motionSpeed === "number"
165
+ ? Math.max(0, params.motionSpeed)
166
+ : 0.2
167
+ const animateEnabled = params.animate !== false
168
+ const falloff =
169
+ typeof params.falloff === "number" ? Math.max(0.25, params.falloff) : 1.85
170
+ const glowStrength =
171
+ typeof params.glowStrength === "number"
172
+ ? Math.max(0, params.glowStrength)
173
+ : 0.18
174
+ const glowThreshold =
175
+ typeof params.glowThreshold === "number"
176
+ ? Math.max(0, Math.min(1, params.glowThreshold))
177
+ : 0.62
178
+ const grainAmount =
179
+ typeof params.grainAmount === "number"
180
+ ? Math.max(0, params.grainAmount)
181
+ : 0.03
182
+ const vignetteStrength =
183
+ typeof params.vignetteStrength === "number"
184
+ ? Math.max(0, Math.min(1, params.vignetteStrength))
185
+ : 0.18
186
+ const vignetteRadius =
187
+ typeof params.vignetteRadius === "number"
188
+ ? Math.max(0.01, params.vignetteRadius)
189
+ : 0.9
190
+ const vignetteSoftness =
191
+ typeof params.vignetteSoftness === "number"
192
+ ? Math.max(0.01, params.vignetteSoftness)
193
+ : 0.32
194
+
195
+ this.activePointsUniform.value = activePoints
196
+ this.animateUniform.value = animateEnabled ? 1 : 0
197
+ this.warpAmountUniform.value = warpAmount
198
+ this.warpBiasUniform.value = warpBias
199
+ this.warpDecayUniform.value = warpDecay
200
+ this.warpScaleUniform.value = warpScale
201
+ this.vortexAmountUniform.value = vortexAmount
202
+ this.motionAmountUniform.value = motionAmount
203
+ this.motionSpeedUniform.value = motionSpeed
204
+ this.falloffUniform.value = falloff
205
+ this.glowStrengthUniform.value = glowStrength
206
+ this.glowThresholdUniform.value = glowThreshold
207
+ this.grainAmountUniform.value = grainAmount
208
+ this.vignetteStrengthUniform.value = vignetteStrength
209
+ this.vignetteRadiusUniform.value = vignetteRadius
210
+ this.vignetteSoftnessUniform.value = vignetteSoftness
211
+
212
+ for (let index = 0; index < 5; index += 1) {
213
+ const point = index + 1
214
+ const colorKey = `point${point}Color`
215
+ const positionKey = `point${point}Position`
216
+ const weightKey = `point${point}Weight`
217
+ const rgb = hexToRgb(
218
+ typeof params[colorKey] === "string" ? params[colorKey] : "#ffffff"
219
+ )
220
+ const position = Array.isArray(params[positionKey])
221
+ ? params[positionKey]
222
+ : [0, 0]
223
+
224
+ this.pointColorUniforms[index]!.red.value = rgb[0]
225
+ this.pointColorUniforms[index]!.green.value = rgb[1]
226
+ this.pointColorUniforms[index]!.blue.value = rgb[2]
227
+ this.pointPositionUniforms[index]!.x.value = position[0] ?? 0
228
+ this.pointPositionUniforms[index]!.y.value = position[1] ?? 0
229
+ this.pointWeightUniforms[index]!.value =
230
+ typeof params[weightKey] === "number"
231
+ ? Math.max(0, params[weightKey])
232
+ : 1
233
+ }
234
+
235
+ let nextTonemapMode: TonemapMode = "aces"
236
+ let nextNoiseMode: NoiseMode = "simplex"
237
+
238
+ switch (params.noiseType) {
239
+ case "perlin":
240
+ case "ridge":
241
+ case "turbulence":
242
+ case "value":
243
+ case "voronoi":
244
+ nextNoiseMode = params.noiseType
245
+ break
246
+ default:
247
+ nextNoiseMode = "simplex"
248
+ break
249
+ }
250
+
251
+ switch (params.tonemapMode) {
252
+ case "none":
253
+ case "reinhard":
254
+ case "totos":
255
+ case "cinematic":
256
+ nextTonemapMode = params.tonemapMode
257
+ break
258
+ case "uncharted2":
259
+ nextTonemapMode = "totos"
260
+ break
261
+ default:
262
+ nextTonemapMode = "aces"
263
+ break
264
+ }
265
+
266
+ this.isAnimated =
267
+ animateEnabled && motionSpeed > 0 && (motionAmount > 0 || warpAmount > 0)
268
+
269
+ let needsRebuild = false
270
+
271
+ if (nextNoiseMode !== this.noiseMode) {
272
+ this.noiseMode = nextNoiseMode
273
+ needsRebuild = true
274
+ }
275
+
276
+ if (nextTonemapMode !== this.tonemapMode) {
277
+ this.tonemapMode = nextTonemapMode
278
+ needsRebuild = true
279
+ }
280
+
281
+ if (warpIterations !== this.warpIterations) {
282
+ this.warpIterations = warpIterations
283
+ needsRebuild = true
284
+ }
285
+
286
+ if (noiseSeed !== this.noiseSeed) {
287
+ this.noiseSeed = noiseSeed
288
+ needsRebuild = true
289
+ }
290
+
291
+ if (needsRebuild) {
292
+ this.rebuildEffectNode()
293
+ }
294
+ }
295
+
296
+ override resize(width: number, height: number): void {
297
+ this.aspectUniform.value = width / Math.max(height, 1)
298
+ }
299
+
300
+ override needsContinuousRender(): boolean {
301
+ return this.isAnimated
302
+ }
303
+
304
+ protected override beforeRender(time: number): void {
305
+ this.timeUniform.value = time
306
+ }
307
+
308
+ protected override buildEffectNode(): Node {
309
+ const hasRequiredUniforms =
310
+ this.timeUniform &&
311
+ this.aspectUniform &&
312
+ this.activePointsUniform &&
313
+ this.warpAmountUniform &&
314
+ this.warpBiasUniform &&
315
+ this.warpDecayUniform &&
316
+ this.warpScaleUniform &&
317
+ this.vortexAmountUniform &&
318
+ this.motionAmountUniform &&
319
+ this.motionSpeedUniform &&
320
+ this.falloffUniform &&
321
+ this.glowStrengthUniform &&
322
+ this.glowThresholdUniform &&
323
+ this.grainAmountUniform &&
324
+ this.vignetteStrengthUniform &&
325
+ this.vignetteRadiusUniform &&
326
+ this.vignetteSoftnessUniform
327
+
328
+ if (
329
+ !hasRequiredUniforms ||
330
+ this.pointColorUniforms.length === 0 ||
331
+ this.pointPositionUniforms.length === 0 ||
332
+ this.pointWeightUniforms.length === 0
333
+ ) {
334
+ return this.inputNode
335
+ }
336
+
337
+ return Fn(() => {
338
+ const baseUv = vec2(
339
+ uv().x.mul(2).sub(1).mul(this.aspectUniform),
340
+ float(1).sub(uv().y).mul(2).sub(1)
341
+ )
342
+ const vignetteUv = vec2(
343
+ uv().x.mul(2).sub(1),
344
+ float(1).sub(uv().y).mul(2).sub(1)
345
+ )
346
+ const time = this.timeUniform
347
+ .mul(this.motionSpeedUniform)
348
+ .mul(this.animateUniform)
349
+ const warpedUv = baseUv.toVar()
350
+ const biasX = this.warpBiasUniform.mul(2)
351
+ const biasY = float(1).sub(this.warpBiasUniform).mul(2)
352
+
353
+ for (let i = 1; i <= this.warpIterations; i += 1) {
354
+ const strength = this.warpAmountUniform.div(
355
+ pow(float(i), this.warpDecayUniform)
356
+ )
357
+ const warpInput = warpedUv
358
+ .mul(this.warpScaleUniform)
359
+ .add(float(this.noiseSeed).mul(73.7))
360
+ const timeOffsetX = time.mul(0.1).add(float(i * 100))
361
+ const timeOffsetY = time.mul(0.1).add(float(i * 200))
362
+ let noiseX: Node
363
+ let noiseY: Node
364
+
365
+ switch (this.noiseMode) {
366
+ case "perlin":
367
+ noiseX = perlinNoise3d(vec3(warpInput, timeOffsetX))
368
+ noiseY = perlinNoise3d(
369
+ vec3(warpInput.add(vec2(13.7, 7.1)), timeOffsetY)
370
+ )
371
+ break
372
+ case "value":
373
+ noiseX = valueNoise3d(vec3(warpInput, timeOffsetX))
374
+ noiseY = valueNoise3d(
375
+ vec3(warpInput.add(vec2(13.7, 7.1)), timeOffsetY)
376
+ )
377
+ break
378
+ case "voronoi":
379
+ noiseX = voronoiNoise3d(vec3(warpInput, timeOffsetX)).mul(2).sub(1)
380
+ noiseY = voronoiNoise3d(
381
+ vec3(warpInput.add(vec2(13.7, 7.1)), timeOffsetY)
382
+ )
383
+ .mul(2)
384
+ .sub(1)
385
+ break
386
+ case "ridge":
387
+ noiseX = ridgeNoise(vec3(warpInput, timeOffsetX)).mul(2).sub(1)
388
+ noiseY = ridgeNoise(
389
+ vec3(warpInput.add(vec2(13.7, 7.1)), timeOffsetY)
390
+ )
391
+ .mul(2)
392
+ .sub(1)
393
+ break
394
+ case "turbulence":
395
+ {
396
+ const disp = turbulence(warpInput, timeOffsetX.mul(20), {
397
+ _amp: 0.7,
398
+ _exp: 1.4,
399
+ _freq: 2,
400
+ _num: 10,
401
+ _speed: 0.3,
402
+ })
403
+ noiseX = disp.x
404
+ noiseY = disp.y
405
+ }
406
+ break
407
+ default:
408
+ noiseX = simplexNoise3d(vec3(warpInput, timeOffsetX))
409
+ noiseY = simplexNoise3d(
410
+ vec3(warpInput.add(vec2(13.7, 7.1)), timeOffsetY)
411
+ )
412
+ break
413
+ }
414
+
415
+ warpedUv.x.addAssign(strength.mul(noiseX).mul(biasX))
416
+ warpedUv.y.addAssign(strength.mul(noiseY).mul(biasY))
417
+ }
418
+
419
+ const distanceFromCenter = max(
420
+ dot(warpedUv, warpedUv),
421
+ float(1e-4)
422
+ ).sqrt()
423
+ const vortexAngle = distanceFromCenter.mul(this.vortexAmountUniform)
424
+ const rotatedUv = vec2(
425
+ warpedUv.x.mul(cos(vortexAngle)).sub(warpedUv.y.mul(sin(vortexAngle))),
426
+ warpedUv.x.mul(sin(vortexAngle)).add(warpedUv.y.mul(cos(vortexAngle)))
427
+ )
428
+
429
+ const finalColor = vec3(0).toVar()
430
+ const totalWeight = float(0).toVar()
431
+
432
+ for (let index = 0; index < 5; index += 1) {
433
+ const pointIndex = float(index + 1)
434
+ const active = select(
435
+ this.activePointsUniform.greaterThanEqual(pointIndex),
436
+ float(1),
437
+ float(0)
438
+ )
439
+ const pointPosition = vec2(
440
+ this.pointPositionUniforms[index]!.x.add(
441
+ sin(time.mul(pointIndex.mul(0.73)).add(pointIndex)).mul(
442
+ this.motionAmountUniform
443
+ )
444
+ ),
445
+ this.pointPositionUniforms[index]!.y.add(
446
+ cos(time.mul(pointIndex.mul(0.41)).add(pointIndex.mul(1.7))).mul(
447
+ this.motionAmountUniform
448
+ )
449
+ )
450
+ )
451
+ const delta = rotatedUv.sub(pointPosition)
452
+ const distance = max(dot(delta, delta), float(1e-4)).sqrt()
453
+ const baseWeight = float(1).div(
454
+ max(pow(distance, this.falloffUniform), float(1e-4))
455
+ )
456
+ const weighted = baseWeight
457
+ .mul(this.pointWeightUniforms[index]!)
458
+ .mul(active)
459
+ const color = vec3(
460
+ this.pointColorUniforms[index]!.red,
461
+ this.pointColorUniforms[index]!.green,
462
+ this.pointColorUniforms[index]!.blue
463
+ )
464
+
465
+ finalColor.addAssign(color.mul(weighted))
466
+ totalWeight.addAssign(weighted)
467
+ }
468
+
469
+ finalColor.assign(finalColor.div(max(totalWeight, float(1e-4))))
470
+
471
+ switch (this.tonemapMode) {
472
+ case "reinhard":
473
+ finalColor.assign(reinhardTonemap(finalColor))
474
+ break
475
+ case "totos":
476
+ finalColor.assign(totosTonemap(finalColor))
477
+ break
478
+ case "cinematic":
479
+ finalColor.assign(cinematicTonemap(finalColor))
480
+ break
481
+ case "none":
482
+ break
483
+ default:
484
+ finalColor.assign(acesTonemap(finalColor))
485
+ break
486
+ }
487
+
488
+ const luma = dot(finalColor, vec3(0.2126, 0.7152, 0.0722))
489
+ const glow = smoothstep(this.glowThresholdUniform, float(1), luma).mul(
490
+ this.glowStrengthUniform
491
+ )
492
+ finalColor.addAssign(vec3(glow, glow, glow))
493
+
494
+ const grain = grainTexturePattern(uv())
495
+ .sub(0.5)
496
+ .mul(this.grainAmountUniform)
497
+ finalColor.addAssign(vec3(grain, grain, grain))
498
+
499
+ const vignetteDistance = max(
500
+ dot(vignetteUv, vignetteUv),
501
+ float(1e-4)
502
+ ).sqrt()
503
+ const vignette = smoothstep(
504
+ this.vignetteRadiusUniform,
505
+ this.vignetteRadiusUniform.sub(this.vignetteSoftnessUniform),
506
+ vignetteDistance
507
+ )
508
+ const vignetteMix = mix(float(1), vignette, this.vignetteStrengthUniform)
509
+ finalColor.mulAssign(vignetteMix)
510
+
511
+ return vec4(
512
+ clamp(
513
+ finalColor,
514
+ vec3(float(0), float(0), float(0)),
515
+ vec3(float(1), float(1), float(1))
516
+ ),
517
+ float(1)
518
+ )
519
+ })()
520
+ }
521
+ }