egaki 0.6.0 → 0.7.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 (271) hide show
  1. package/CHANGELOG.md +140 -9
  2. package/dist/cli/cache-utils.d.ts +33 -0
  3. package/dist/cli/cache-utils.d.ts.map +1 -0
  4. package/dist/cli/cache-utils.js +157 -0
  5. package/dist/cli/cached-generate.d.ts +105 -0
  6. package/dist/cli/cached-generate.d.ts.map +1 -0
  7. package/dist/cli/cached-generate.js +208 -0
  8. package/dist/cli/cached-generate.test.d.ts +11 -0
  9. package/dist/cli/cached-generate.test.d.ts.map +1 -0
  10. package/dist/cli/cached-generate.test.js +431 -0
  11. package/dist/cli/cartesia-provider.d.ts +16 -0
  12. package/dist/cli/cartesia-provider.d.ts.map +1 -0
  13. package/dist/cli/cartesia-provider.js +184 -0
  14. package/dist/cli/chatgpt-auth.d.ts.map +1 -0
  15. package/dist/cli/cli.d.ts +4 -0
  16. package/dist/cli/cli.d.ts.map +1 -0
  17. package/dist/{cli.js → cli/cli.js} +626 -600
  18. package/dist/cli/clone-generate.d.ts +26 -0
  19. package/dist/cli/clone-generate.d.ts.map +1 -0
  20. package/dist/cli/clone-generate.js +148 -0
  21. package/dist/cli/credentials.d.ts.map +1 -0
  22. package/dist/{credentials.js → cli/credentials.js} +20 -0
  23. package/dist/cli/elevenlabs-speech-provider.d.ts +26 -0
  24. package/dist/cli/elevenlabs-speech-provider.d.ts.map +1 -0
  25. package/dist/cli/elevenlabs-speech-provider.js +199 -0
  26. package/dist/cli/generate.d.ts +140 -0
  27. package/dist/cli/generate.d.ts.map +1 -0
  28. package/dist/cli/generate.js +604 -0
  29. package/dist/cli/generate.test.d.ts +2 -0
  30. package/dist/cli/generate.test.d.ts.map +1 -0
  31. package/dist/cli/generate.test.js +131 -0
  32. package/dist/cli/login.d.ts.map +1 -0
  33. package/dist/cli/main.d.ts +3 -0
  34. package/dist/cli/main.d.ts.map +1 -0
  35. package/dist/cli/main.js +7 -0
  36. package/dist/{model-catalog.d.ts → cli/model-catalog.d.ts} +6 -0
  37. package/dist/cli/model-catalog.d.ts.map +1 -0
  38. package/dist/{model-catalog.js → cli/model-catalog.js} +714 -4
  39. package/dist/{models.d.ts → cli/models.d.ts} +12 -5
  40. package/dist/cli/models.d.ts.map +1 -0
  41. package/dist/{models.js → cli/models.js} +58 -57
  42. package/dist/cli/open-browser.d.ts.map +1 -0
  43. package/dist/cli/openai-speech-provider.d.ts +3 -0
  44. package/dist/cli/openai-speech-provider.d.ts.map +1 -0
  45. package/dist/cli/openai-speech-provider.js +28 -0
  46. package/dist/cli/separation-generate.d.ts +34 -0
  47. package/dist/cli/separation-generate.d.ts.map +1 -0
  48. package/dist/cli/separation-generate.js +117 -0
  49. package/dist/cli/speech-catalog.d.ts +35 -0
  50. package/dist/cli/speech-catalog.d.ts.map +1 -0
  51. package/dist/cli/speech-catalog.js +195 -0
  52. package/dist/cli/speech-generate.d.ts +86 -0
  53. package/dist/cli/speech-generate.d.ts.map +1 -0
  54. package/dist/cli/speech-generate.js +156 -0
  55. package/dist/cli/speech-models.d.ts +8 -0
  56. package/dist/cli/speech-models.d.ts.map +1 -0
  57. package/dist/cli/speech-models.js +109 -0
  58. package/dist/cli/speech-provider.test.d.ts +2 -0
  59. package/dist/cli/speech-provider.test.d.ts.map +1 -0
  60. package/dist/cli/speech-provider.test.js +197 -0
  61. package/dist/cli/subscription.d.ts.map +1 -0
  62. package/dist/cli/transcription-catalog.d.ts +35 -0
  63. package/dist/cli/transcription-catalog.d.ts.map +1 -0
  64. package/dist/cli/transcription-catalog.js +192 -0
  65. package/dist/cli/transcription-generate.d.ts +62 -0
  66. package/dist/cli/transcription-generate.d.ts.map +1 -0
  67. package/dist/cli/transcription-generate.js +144 -0
  68. package/dist/cli/transcription-models.d.ts +9 -0
  69. package/dist/cli/transcription-models.d.ts.map +1 -0
  70. package/dist/cli/transcription-models.js +100 -0
  71. package/dist/cli/transcription-providers.d.ts +22 -0
  72. package/dist/cli/transcription-providers.d.ts.map +1 -0
  73. package/dist/cli/transcription-providers.js +290 -0
  74. package/dist/cli/video-model-catalog.d.ts.map +1 -0
  75. package/dist/cli/xai-auth.d.ts.map +1 -0
  76. package/dist/{xai-auth.js → cli/xai-auth.js} +1 -1
  77. package/dist/vite/angled-screen.d.ts +57 -0
  78. package/dist/vite/angled-screen.d.ts.map +1 -0
  79. package/dist/vite/angled-screen.js +115 -0
  80. package/dist/vite/app.d.ts +51 -0
  81. package/dist/vite/app.d.ts.map +1 -0
  82. package/dist/vite/app.js +150 -0
  83. package/dist/vite/bands-shader.d.ts +47 -0
  84. package/dist/vite/bands-shader.d.ts.map +1 -0
  85. package/dist/vite/bands-shader.js +267 -0
  86. package/dist/vite/code-block.d.ts +107 -0
  87. package/dist/vite/code-block.d.ts.map +1 -0
  88. package/dist/vite/code-block.js +641 -0
  89. package/dist/vite/components.d.ts +36 -0
  90. package/dist/vite/components.d.ts.map +1 -0
  91. package/dist/vite/components.js +113 -0
  92. package/dist/vite/dispersion-rings-shader.d.ts +44 -0
  93. package/dist/vite/dispersion-rings-shader.d.ts.map +1 -0
  94. package/dist/vite/dispersion-rings-shader.js +282 -0
  95. package/dist/vite/easing-curves.d.ts +129 -0
  96. package/dist/vite/easing-curves.d.ts.map +1 -0
  97. package/dist/vite/easing-curves.js +584 -0
  98. package/dist/vite/easing-curves.test.d.ts +2 -0
  99. package/dist/vite/easing-curves.test.d.ts.map +1 -0
  100. package/dist/vite/easing-curves.test.js +200 -0
  101. package/dist/vite/generated-media-client.d.ts +35 -0
  102. package/dist/vite/generated-media-client.d.ts.map +1 -0
  103. package/dist/vite/generated-media-client.js +76 -0
  104. package/dist/vite/keyframes.d.ts +129 -0
  105. package/dist/vite/keyframes.d.ts.map +1 -0
  106. package/dist/vite/keyframes.js +194 -0
  107. package/dist/vite/layout-editor.d.ts +45 -0
  108. package/dist/vite/layout-editor.d.ts.map +1 -0
  109. package/dist/vite/layout-editor.js +587 -0
  110. package/dist/vite/layout-transition.d.ts +136 -0
  111. package/dist/vite/layout-transition.d.ts.map +1 -0
  112. package/dist/vite/layout-transition.js +581 -0
  113. package/dist/vite/liquid-gradient-shader.d.ts +62 -0
  114. package/dist/vite/liquid-gradient-shader.d.ts.map +1 -0
  115. package/dist/vite/liquid-gradient-shader.js +413 -0
  116. package/dist/vite/mdx-client.d.ts +15 -0
  117. package/dist/vite/mdx-client.d.ts.map +1 -0
  118. package/dist/vite/mdx-client.js +265 -0
  119. package/dist/vite/mdx-parse.d.ts +102 -0
  120. package/dist/vite/mdx-parse.d.ts.map +1 -0
  121. package/dist/vite/mdx-parse.js +251 -0
  122. package/dist/vite/mdx-provided-components.d.ts +18 -0
  123. package/dist/vite/mdx-provided-components.d.ts.map +1 -0
  124. package/dist/vite/mdx-provided-components.js +14 -0
  125. package/dist/vite/mdx-video.d.ts +327 -0
  126. package/dist/vite/mdx-video.d.ts.map +1 -0
  127. package/dist/vite/mdx-video.js +596 -0
  128. package/dist/vite/mdx-video.test.d.ts +9 -0
  129. package/dist/vite/mdx-video.test.d.ts.map +1 -0
  130. package/dist/vite/mdx-video.test.js +1945 -0
  131. package/dist/vite/media-components.d.ts +45 -0
  132. package/dist/vite/media-components.d.ts.map +1 -0
  133. package/dist/vite/media-components.js +355 -0
  134. package/dist/vite/media-duration-store.d.ts +66 -0
  135. package/dist/vite/media-duration-store.d.ts.map +1 -0
  136. package/dist/vite/media-duration-store.js +204 -0
  137. package/dist/vite/player-page.d.ts +35 -0
  138. package/dist/vite/player-page.d.ts.map +1 -0
  139. package/dist/vite/player-page.js +720 -0
  140. package/dist/vite/render-client.d.ts +18 -0
  141. package/dist/vite/render-client.d.ts.map +1 -0
  142. package/dist/vite/render-client.js +67 -0
  143. package/dist/vite/sdk.d.ts +221 -0
  144. package/dist/vite/sdk.d.ts.map +1 -0
  145. package/dist/vite/sdk.js +355 -0
  146. package/dist/vite/server-components.d.ts +55 -0
  147. package/dist/vite/server-components.d.ts.map +1 -0
  148. package/dist/vite/server-components.js +156 -0
  149. package/dist/vite/server-mdx.d.ts +74 -0
  150. package/dist/vite/server-mdx.d.ts.map +1 -0
  151. package/dist/vite/server-mdx.js +259 -0
  152. package/dist/vite/shader-renderer.d.ts +48 -0
  153. package/dist/vite/shader-renderer.d.ts.map +1 -0
  154. package/dist/vite/shader-renderer.js +411 -0
  155. package/dist/vite/store-hooks.d.ts +12 -0
  156. package/dist/vite/store-hooks.d.ts.map +1 -0
  157. package/dist/vite/store-hooks.js +93 -0
  158. package/dist/vite/store.d.ts +75 -0
  159. package/dist/vite/store.d.ts.map +1 -0
  160. package/dist/vite/store.js +52 -0
  161. package/dist/vite/store.test.d.ts +6 -0
  162. package/dist/vite/store.test.d.ts.map +1 -0
  163. package/dist/vite/store.test.js +172 -0
  164. package/dist/vite/tweakpane-hook.d.ts +94 -0
  165. package/dist/vite/tweakpane-hook.d.ts.map +1 -0
  166. package/dist/vite/tweakpane-hook.js +450 -0
  167. package/dist/vite/vite-plugin.d.ts +28 -0
  168. package/dist/vite/vite-plugin.d.ts.map +1 -0
  169. package/dist/vite/vite-plugin.js +538 -0
  170. package/dist/vite/wave-gradient-shader.d.ts +41 -0
  171. package/dist/vite/wave-gradient-shader.d.ts.map +1 -0
  172. package/dist/vite/wave-gradient-shader.js +207 -0
  173. package/package.json +101 -24
  174. package/skills/egaki/SKILL.md +162 -1
  175. package/src/cli/cache-utils.ts +169 -0
  176. package/src/cli/cached-generate.test.ts +531 -0
  177. package/src/cli/cached-generate.ts +348 -0
  178. package/src/cli/cartesia-provider.ts +249 -0
  179. package/src/{cli.ts → cli/cli.ts} +836 -884
  180. package/src/cli/clone-generate.ts +202 -0
  181. package/src/{credentials.ts → cli/credentials.ts} +20 -0
  182. package/src/cli/elevenlabs-speech-provider.ts +243 -0
  183. package/src/cli/generate.test.ts +166 -0
  184. package/src/cli/generate.ts +912 -0
  185. package/src/cli/main.ts +8 -0
  186. package/src/{model-catalog.ts → cli/model-catalog.ts} +787 -58
  187. package/src/{models.ts → cli/models.ts} +65 -86
  188. package/src/cli/openai-speech-provider.ts +34 -0
  189. package/src/cli/separation-generate.ts +187 -0
  190. package/src/cli/speech-catalog.ts +253 -0
  191. package/src/cli/speech-generate.ts +275 -0
  192. package/src/cli/speech-models.ts +146 -0
  193. package/src/cli/speech-provider.test.ts +226 -0
  194. package/src/cli/transcription-catalog.ts +250 -0
  195. package/src/cli/transcription-generate.ts +214 -0
  196. package/src/cli/transcription-models.ts +136 -0
  197. package/src/cli/transcription-providers.ts +427 -0
  198. package/src/{xai-auth.ts → cli/xai-auth.ts} +1 -1
  199. package/src/vite/angled-screen.tsx +214 -0
  200. package/src/vite/app.tsx +197 -0
  201. package/src/vite/bands-shader.tsx +319 -0
  202. package/src/vite/code-block.tsx +939 -0
  203. package/src/vite/components.tsx +278 -0
  204. package/src/vite/dispersion-rings-shader.tsx +331 -0
  205. package/src/vite/easing-curves.test.ts +232 -0
  206. package/src/vite/easing-curves.ts +743 -0
  207. package/src/vite/generated-media-client.tsx +121 -0
  208. package/src/vite/keyframes.tsx +347 -0
  209. package/src/vite/layout-editor.tsx +709 -0
  210. package/src/vite/layout-transition.tsx +706 -0
  211. package/src/vite/liquid-gradient-shader.tsx +474 -0
  212. package/src/vite/mdx-client.tsx +420 -0
  213. package/src/vite/mdx-parse.ts +343 -0
  214. package/src/vite/mdx-provided-components.ts +19 -0
  215. package/src/vite/mdx-video.test.tsx +2219 -0
  216. package/src/vite/mdx-video.tsx +976 -0
  217. package/src/vite/media-components.tsx +473 -0
  218. package/src/vite/media-duration-store.ts +225 -0
  219. package/src/vite/motion-timing.ts +194 -0
  220. package/src/vite/player-page.tsx +1107 -0
  221. package/src/vite/render-client.ts +84 -0
  222. package/src/vite/sdk.ts +598 -0
  223. package/src/vite/server-components.tsx +241 -0
  224. package/src/vite/server-mdx.ts +285 -0
  225. package/src/vite/shader-renderer.tsx +535 -0
  226. package/src/vite/store-hooks.ts +117 -0
  227. package/src/vite/store.test.ts +202 -0
  228. package/src/vite/store.ts +115 -0
  229. package/src/vite/styles.css +21 -0
  230. package/src/vite/tweakpane-hook.tsx +593 -0
  231. package/src/vite/virtual-modules.d.ts +30 -0
  232. package/src/vite/vite-plugin.ts +584 -0
  233. package/src/vite/wave-gradient-shader.tsx +253 -0
  234. package/README.md +0 -370
  235. package/dist/antigravity-auth.d.ts +0 -15
  236. package/dist/antigravity-auth.d.ts.map +0 -1
  237. package/dist/antigravity-auth.js +0 -544
  238. package/dist/antigravity-image.d.ts +0 -11
  239. package/dist/antigravity-image.d.ts.map +0 -1
  240. package/dist/antigravity-image.js +0 -285
  241. package/dist/chatgpt-auth.d.ts.map +0 -1
  242. package/dist/cli.d.ts +0 -3
  243. package/dist/cli.d.ts.map +0 -1
  244. package/dist/credentials.d.ts.map +0 -1
  245. package/dist/gateway-model-candidates.generated.d.ts +0 -11
  246. package/dist/gateway-model-candidates.generated.d.ts.map +0 -1
  247. package/dist/gateway-model-candidates.generated.js +0 -64
  248. package/dist/login.d.ts.map +0 -1
  249. package/dist/model-catalog.d.ts.map +0 -1
  250. package/dist/models.d.ts.map +0 -1
  251. package/dist/open-browser.d.ts.map +0 -1
  252. package/dist/subscription.d.ts.map +0 -1
  253. package/dist/video-model-catalog.d.ts.map +0 -1
  254. package/dist/xai-auth.d.ts.map +0 -1
  255. /package/dist/{chatgpt-auth.d.ts → cli/chatgpt-auth.d.ts} +0 -0
  256. /package/dist/{chatgpt-auth.js → cli/chatgpt-auth.js} +0 -0
  257. /package/dist/{credentials.d.ts → cli/credentials.d.ts} +0 -0
  258. /package/dist/{login.d.ts → cli/login.d.ts} +0 -0
  259. /package/dist/{login.js → cli/login.js} +0 -0
  260. /package/dist/{open-browser.d.ts → cli/open-browser.d.ts} +0 -0
  261. /package/dist/{open-browser.js → cli/open-browser.js} +0 -0
  262. /package/dist/{subscription.d.ts → cli/subscription.d.ts} +0 -0
  263. /package/dist/{subscription.js → cli/subscription.js} +0 -0
  264. /package/dist/{video-model-catalog.d.ts → cli/video-model-catalog.d.ts} +0 -0
  265. /package/dist/{video-model-catalog.js → cli/video-model-catalog.js} +0 -0
  266. /package/dist/{xai-auth.d.ts → cli/xai-auth.d.ts} +0 -0
  267. /package/src/{chatgpt-auth.ts → cli/chatgpt-auth.ts} +0 -0
  268. /package/src/{login.ts → cli/login.ts} +0 -0
  269. /package/src/{open-browser.ts → cli/open-browser.ts} +0 -0
  270. /package/src/{subscription.ts → cli/subscription.ts} +0 -0
  271. /package/src/{video-model-catalog.ts → cli/video-model-catalog.ts} +0 -0
@@ -0,0 +1,474 @@
1
+ 'use client'
2
+
3
+ /**
4
+ * LiquidGradientShader — animated liquid turbulence gradient with Oklab color mixing.
5
+ *
6
+ * Port of Framer's LiquidGradient shader module for Remotion/egaki.
7
+ * Original source:
8
+ * https://framerusercontent.com/modules/QEytd7xyjUsL7yuVUzSs/O7s2vxltmhiskELYwyrY/LiquidGradient.js
9
+ *
10
+ * A multi-color gradient is warped through seed-dependent turbulence with
11
+ * configurable amplitude, frequency, and iteration count. Colors are mixed
12
+ * in Oklab/LCH perceptual color space for smooth, natural transitions.
13
+ * Post-processing includes soft gamut mapping, exposure, contrast, and
14
+ * saturation controls. Optional dithering (IGN smooth or grain noise)
15
+ * reduces banding artifacts.
16
+ */
17
+
18
+ import type { CSSProperties } from 'react'
19
+ import { defineShader } from './shader-renderer.tsx'
20
+
21
+ // ---------------------------------------------------------------------------
22
+ // Props
23
+ // ---------------------------------------------------------------------------
24
+
25
+ export interface LiquidGradientShaderProps {
26
+ /** Color palette for the gradient (max 8). Hex strings like "#2962FF". */
27
+ colors?: string[]
28
+ /** Seed for turbulence variation. Different seeds = different flow patterns. */
29
+ seed?: number
30
+ /** Animation speed multiplier. 0 = frozen, 0.3 = default, 2 = fast. */
31
+ speed?: number
32
+ /** Loop duration in seconds. 0 = no loop, >0 = seamless loop over that many seconds. */
33
+ loop?: number
34
+ /** UV scale of the turbulence field. Higher = more zoomed in. */
35
+ scale?: number
36
+ /** Turbulence amplitude. Controls how far the flow displaces colors. */
37
+ turbAmp?: number
38
+ /** Turbulence frequency. Controls the spacing of turbulence waves. */
39
+ turbFreq?: number
40
+ /** Turbulence iteration count. Higher = more detail, more GPU cost. */
41
+ turbIter?: number
42
+ /** Wave frequency for the final color band mapping. */
43
+ waveFreq?: number
44
+ /** Distribution bias. Shifts where color bands fall in the gradient. */
45
+ distBias?: number
46
+ /** Jellify mode (0 or 1). Squashes one axis for a jelly-like feel. */
47
+ jellify?: number
48
+ /** Dither mode: 0 = Off, 1 = Smooth (IGN), 2 = Grain (quick noise). */
49
+ ditherMode?: number
50
+ /** Dither amount. Higher = more visible noise to fight banding. */
51
+ dither?: number
52
+ /** Exposure multiplier. Brightens or darkens the overall output. */
53
+ exposure?: number
54
+ /** Contrast adjustment applied in Oklab space. */
55
+ contrast?: number
56
+ /** Saturation adjustment applied in Oklab space. */
57
+ saturation?: number
58
+ style?: CSSProperties
59
+ }
60
+
61
+ // ---------------------------------------------------------------------------
62
+ // Fragment shader body
63
+ // ---------------------------------------------------------------------------
64
+
65
+ /**
66
+ * Raw GLSL fragment body from LiquidGradient.js.
67
+ * The defineShader engine prepends #version, precision, v_uv, fragColor,
68
+ * uniform declarations, and built-in uniforms automatically.
69
+ *
70
+ * Algorithm overview:
71
+ * 1. PCG hash seeding: seed-derived offsets and rotation create a unique
72
+ * flow pattern per seed value
73
+ * 2. Turbulence: 4 ephemeral layers, each with up to 13 sine-wave
74
+ * iterations that warp UV coordinates through amplitude-modulated
75
+ * displacement. Optional jellify mode squashes one axis
76
+ * 3. Color mapping: turbulence value maps through paletteN() which
77
+ * interpolates user colors in Oklab LCH space for perceptually
78
+ * uniform, hue-preserving gradients
79
+ * 4. Dithering: IGN (smooth) or quick noise (grain) reduces banding
80
+ * 5. Post-processing: exposure, contrast/saturation in Oklab, and soft
81
+ * gamut mapping to clamp out-of-range colors gracefully
82
+ */
83
+ const FRAGMENT_SOURCE = `
84
+ // === CONSTANTS ===
85
+ const float GOLDEN_ANGLE = 2.3999632;
86
+ const float TAU = 6.28318530;
87
+
88
+ // === PCG hash - https://www.jcgt.org/published/0009/03/02/
89
+ uvec3 hash3(uvec3 v) {
90
+ v = v * 1664525u + 1013904223u;
91
+ v.x += v.y * v.z;
92
+ v.y += v.z * v.x;
93
+ v.z += v.x * v.y;
94
+ v ^= v >> 16u;
95
+ v.x += v.y * v.z;
96
+ v.y += v.z * v.x;
97
+ v.z += v.x * v.y;
98
+ return v;
99
+ }
100
+
101
+ // Seed
102
+ vec3 seedRandom(float seedVal) {
103
+ uvec3 s = uvec3(
104
+ floatBitsToUint(seedVal),
105
+ floatBitsToUint(seedVal * 1.5 + 7.31),
106
+ floatBitsToUint(seedVal * 2.7 + 13.37)
107
+ );
108
+ s = hash3(s);
109
+ return vec3(s) / float(0xFFFFFFFFu);
110
+ }
111
+
112
+ // === COLOR SPACE UTILITIES ===
113
+ vec3 toLinear(vec3 c) {
114
+ return pow(c, vec3(2.2));
115
+ }
116
+
117
+ vec3 toSrgb(vec3 c) {
118
+ return pow(clamp(c, 0.0, 1.0), vec3(0.4545));
119
+ }
120
+
121
+ vec3 linearToOklab(vec3 c) {
122
+ float l = 0.4122214708 * c.r + 0.5363325363 * c.g + 0.0514459929 * c.b;
123
+ float m = 0.2119034982 * c.r + 0.6806995451 * c.g + 0.1073969566 * c.b;
124
+ float s = 0.0883024619 * c.r + 0.2817188376 * c.g + 0.6299787005 * c.b;
125
+
126
+ l = pow(max(l, 0.0), 1.0/3.0);
127
+ m = pow(max(m, 0.0), 1.0/3.0);
128
+ s = pow(max(s, 0.0), 1.0/3.0);
129
+
130
+ return vec3(
131
+ 0.2104542553 * l + 0.7936177850 * m - 0.0040720468 * s,
132
+ 1.9779984951 * l - 2.4285922050 * m + 0.4505937099 * s,
133
+ 0.0259040371 * l + 0.7827717662 * m - 0.8086757660 * s
134
+ );
135
+ }
136
+
137
+ vec3 oklabToLinear(vec3 c) {
138
+ float l = c.x + 0.3963377774 * c.y + 0.2158037573 * c.z;
139
+ float m = c.x - 0.1055613458 * c.y - 0.0638541728 * c.z;
140
+ float s = c.x - 0.0894841775 * c.y - 1.2914855480 * c.z;
141
+
142
+ l = l * l * l;
143
+ m = m * m * m;
144
+ s = s * s * s;
145
+
146
+ return vec3(
147
+ +4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s,
148
+ -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s,
149
+ -0.0041960863 * l - 0.7034186147 * m + 1.7076147010 * s
150
+ );
151
+ }
152
+
153
+ vec3 oklabToLch(vec3 lab) {
154
+ return vec3(lab.x, length(lab.yz), atan(lab.z, lab.y));
155
+ }
156
+
157
+ vec3 lchToOklab(vec3 lch) {
158
+ return vec3(lch.x, lch.y * cos(lch.z), lch.y * sin(lch.z));
159
+ }
160
+
161
+ vec3 mixLch(vec3 lab0, vec3 lab1, float t) {
162
+ vec3 lch0 = oklabToLch(lab0);
163
+ vec3 lch1 = oklabToLch(lab1);
164
+
165
+ if (lch0.y < 0.05) lch0.z = lch1.z;
166
+ if (lch1.y < 0.05) lch1.z = lch0.z;
167
+
168
+ float dh = lch1.z - lch0.z;
169
+ if (dh > 3.14159265) dh -= 6.28318530;
170
+ if (dh < -3.14159265) dh += 6.28318530;
171
+
172
+ return lchToOklab(vec3(
173
+ mix(lch0.x, lch1.x, t),
174
+ mix(lch0.y, lch1.y, t),
175
+ lch0.z + dh * t
176
+ ));
177
+ }
178
+
179
+ // === PALETTE SAMPLING ===
180
+ vec3 getColor(int idx) {
181
+ if (u_colors_length < 1) return vec3(0.0);
182
+ int safeIdx = clamp(idx, 0, u_colors_length - 1);
183
+ return u_colors[safeIdx].rgb;
184
+ }
185
+
186
+ vec3 paletteN(float t, int count) {
187
+ if (count < 1) return vec3(0.0);
188
+ if (count < 2) return toLinear(getColor(0));
189
+
190
+ float segmentSize = 1.0 / float(count - 1);
191
+ t = clamp(t, 0.0, 1.0);
192
+ int idx = min(int(floor(t / segmentSize)), count - 2);
193
+ float localT = clamp((t - float(idx) * segmentSize) / segmentSize, 0.0, 1.0);
194
+
195
+ vec3 lab0 = linearToOklab(toLinear(getColor(idx)));
196
+ vec3 lab1 = linearToOklab(toLinear(getColor(idx + 1)));
197
+
198
+ return oklabToLinear(mixLch(lab0, lab1, localT));
199
+ }
200
+
201
+ // === DITHER ===
202
+ float IGN(vec2 uv) {
203
+ return fract(52.9829189 * fract(dot(uv, vec2(0.06711056, 0.00583715))));
204
+ }
205
+
206
+ float quickNoise(vec2 I) {
207
+ return fract(sin(dot(I, vec2(12.9898, 78.233))) * 43758.5453);
208
+ }
209
+
210
+ // Dither Mode: 0=Off, 1=IGN, 2=quickNoise
211
+ float getDither(vec2 I, float mode) {
212
+ if (mode < 0.5) return 0.5; // 0: Off
213
+ if (mode < 1.5) return IGN(I); // 1: Smooth
214
+ return quickNoise(I); // 2: Grain
215
+ }
216
+
217
+ // === POST-PROCESS ===
218
+ vec3 softGamutMap(vec3 linearRgb) {
219
+ float maxC = max(linearRgb.r, max(linearRgb.g, linearRgb.b));
220
+ float minC = min(linearRgb.r, min(linearRgb.g, linearRgb.b));
221
+
222
+ if (minC >= 0.0 && maxC <= 1.0) return linearRgb;
223
+
224
+ vec3 lab = linearToOklab(max(linearRgb, 0.0));
225
+ float L = clamp(lab.x, 0.0, 1.0);
226
+ float C = length(lab.yz);
227
+ float h = atan(lab.z, lab.y);
228
+
229
+ float maxChroma = 0.4 * (1.0 - pow(abs(2.0 * L - 1.0), 2.0));
230
+
231
+ if (C > maxChroma * 0.7) {
232
+ float knee = maxChroma * 0.7;
233
+ C = knee + (maxChroma - knee) * tanh((C - knee) / (maxChroma - knee + 0.001));
234
+ }
235
+
236
+ return clamp(oklabToLinear(vec3(L, C * cos(h), C * sin(h))), 0.0, 1.0);
237
+ }
238
+
239
+ vec3 applyContrastSaturation(vec3 linearRgb, float contrast, float saturation) {
240
+ vec3 lab = linearToOklab(linearRgb);
241
+ float C = length(lab.yz);
242
+ float h = atan(lab.z, lab.y);
243
+
244
+ lab.x = clamp((lab.x - 0.5) * contrast + 0.5, 0.0, 1.0);
245
+ C *= saturation;
246
+ lab.y = C * cos(h);
247
+ lab.z = C * sin(h);
248
+
249
+ return oklabToLinear(lab);
250
+ }
251
+
252
+ // === MAIN ===
253
+ void main() {
254
+ vec2 fragCoord = v_uv * u_resolution;
255
+ vec2 r = u_resolution;
256
+ vec2 p = (fragCoord * 2.0 - r) / r.y;
257
+
258
+ int colorCount = u_colors_length;
259
+
260
+ // Early out: no colors -> black
261
+ if (colorCount < 1) {
262
+ fragColor = vec4(0.0, 0.0, 0.0, 1.0);
263
+ return;
264
+ }
265
+
266
+ float t = u_time * 0.3;
267
+
268
+ // Map time onto a circle so animation seamlessly wraps.
269
+ float looping = step(0.5, u_loop);
270
+ float phase = TAU * u_time / max(u_loop, 0.01);
271
+ float radius = u_loop * u_speed * 0.3 / TAU;
272
+ float tA = sin(phase) * radius;
273
+ float tB = (1.0 - cos(phase)) * radius;
274
+
275
+ // Seed-based offsets
276
+ vec3 seedOffset = seedRandom(u_seed);
277
+ vec3 seedOffset2 = seedRandom(u_seed + 100.0);
278
+
279
+ // Golden angle rotation
280
+ float seedAngle = u_seed * GOLDEN_ANGLE;
281
+ vec2 seedPhase = (seedOffset2.xy - 0.5) * TAU;
282
+
283
+ // Seed-based rotation
284
+ float cs = cos(seedAngle);
285
+ float sn = sin(seedAngle);
286
+ p = mat2(cs, -sn, sn, cs) * p;
287
+
288
+ // Get dither value
289
+ float dither = getDither(floor(fragCoord / u_pixelRatio), u_ditherMode);
290
+
291
+ // === TURBULENCE ===
292
+ float totalVal = 0.0;
293
+ float totalWeight = 0.0;
294
+ int turbIter = int(u_turbIter);
295
+
296
+ float freq = 1.0 / max(u_turbFreq, 0.01);
297
+
298
+ for (float i = 0.0; i < 4.0; i++) {
299
+ float eph = i / 4.0;
300
+
301
+ vec2 q = p * u_scale;
302
+ float sq = eph * eph;
303
+
304
+ if (u_jellify > 0.5) {
305
+ q.yx *= mix(1.0, 0.5, 1.0 - exp(-sq));
306
+ }
307
+
308
+ float a = seedPhase.x;
309
+ float d = seedPhase.y;
310
+
311
+ for (int j = 2; j < 13; j++) {
312
+ if (j >= turbIter) break;
313
+ float fj = float(j);
314
+ // When looping, use circular time. Otherwise original t.
315
+ float t1 = mix(t * u_speed, tA, looping);
316
+ float t2 = mix(t * u_speed, tB, looping);
317
+ q += u_turbAmp * sin(q.yx / freq * fj + t1 + vec2(a, d) + seedOffset.xy * fj) / fj;
318
+ a += cos(fj + d * 1.2 + q.x * 2.0 - t1 + seedOffset2.z + t2 * 0.3 * looping);
319
+ d += sin(fj * q.y + a + seedOffset.z + t1 + seedOffset2.y + t2 * 0.3 * looping);
320
+ }
321
+
322
+ float v = 0.5 + 0.5 * sin(length(q.yx + vec2(a, d) * 0.2) * u_waveFreq + i * i + seedOffset.x);
323
+ float weight = smoothstep(0.0, 0.5, eph) * smoothstep(1.0, 0.5, eph);
324
+ totalVal += v * weight;
325
+ totalWeight += weight;
326
+ }
327
+
328
+ float val = totalVal / totalWeight;
329
+ val = clamp((val - 0.3) / 0.4, 0.0, 1.0);
330
+ val = pow(val, exp(-u_distBias));
331
+ val = clamp(val + (dither - 0.5) * u_dither, 0.0, 1.0);
332
+
333
+ vec3 col = paletteN(val, colorCount);
334
+ col *= u_exposure;
335
+ col = applyContrastSaturation(col, u_contrast, u_saturation);
336
+ col = softGamutMap(col);
337
+ col = toSrgb(col);
338
+
339
+ fragColor = vec4(col, 1.0);
340
+ }
341
+ `
342
+
343
+ // ---------------------------------------------------------------------------
344
+ // Component
345
+ // ---------------------------------------------------------------------------
346
+
347
+ /**
348
+ * Property controls matching the original Framer LiquidGradient module.
349
+ * Ranges, defaults, and step sizes are preserved from the original.
350
+ *
351
+ * Notes on type mapping:
352
+ * - `jellify` is a Framer Boolean; mapped to a number 0/1 toggle since
353
+ * defineShader only supports number controls. The GLSL uses `> 0.5`.
354
+ * - `ditherMode` is a Framer Enum [0,1,2]; mapped to a number with step 1.
355
+ * - `loop` default 0 means no looping; values > 0 set the loop duration.
356
+ */
357
+ export const LiquidGradientShader = defineShader({
358
+ title: 'LiquidGradientShader',
359
+ fragment: FRAGMENT_SOURCE,
360
+ propertyControls: {
361
+ colors: {
362
+ type: 'array',
363
+ control: { type: 'color' },
364
+ maxCount: 8,
365
+ maxVisible: 8,
366
+ defaultValue: ['#00001A', '#2962FF', '#40BCFF', '#FFB8B5', '#FFC14F'],
367
+ },
368
+ seed: {
369
+ type: 'number',
370
+ defaultValue: 648,
371
+ min: 0,
372
+ max: 1000,
373
+ step: 1,
374
+ },
375
+ speed: {
376
+ type: 'number',
377
+ defaultValue: 0.3,
378
+ min: 0,
379
+ max: 2,
380
+ step: 0.01,
381
+ },
382
+ loop: {
383
+ type: 'number',
384
+ defaultValue: 0,
385
+ min: 0,
386
+ max: 60,
387
+ step: 0.5,
388
+ },
389
+ scale: {
390
+ type: 'number',
391
+ defaultValue: 0.42,
392
+ min: 0.1,
393
+ max: 2,
394
+ step: 0.01,
395
+ },
396
+ turbAmp: {
397
+ type: 'number',
398
+ defaultValue: 0.6,
399
+ min: 0,
400
+ max: 1,
401
+ step: 0.01,
402
+ },
403
+ turbFreq: {
404
+ type: 'number',
405
+ defaultValue: 0.1,
406
+ min: 0.1,
407
+ max: 2,
408
+ step: 0.01,
409
+ },
410
+ turbIter: {
411
+ type: 'number',
412
+ defaultValue: 7,
413
+ min: 3,
414
+ max: 10,
415
+ step: 1,
416
+ },
417
+ waveFreq: {
418
+ type: 'number',
419
+ defaultValue: 3.8,
420
+ min: 0.1,
421
+ max: 5,
422
+ step: 0.1,
423
+ },
424
+ distBias: {
425
+ type: 'number',
426
+ defaultValue: 0,
427
+ min: -1,
428
+ max: 1,
429
+ step: 0.1,
430
+ },
431
+ jellify: {
432
+ type: 'number',
433
+ defaultValue: 0,
434
+ min: 0,
435
+ max: 1,
436
+ step: 1,
437
+ },
438
+ ditherMode: {
439
+ type: 'number',
440
+ defaultValue: 0,
441
+ min: 0,
442
+ max: 2,
443
+ step: 1,
444
+ },
445
+ dither: {
446
+ type: 'number',
447
+ defaultValue: 0.05,
448
+ min: 0,
449
+ max: 0.2,
450
+ step: 0.01,
451
+ },
452
+ exposure: {
453
+ type: 'number',
454
+ defaultValue: 1.1,
455
+ min: 0.5,
456
+ max: 2,
457
+ step: 0.1,
458
+ },
459
+ contrast: {
460
+ type: 'number',
461
+ defaultValue: 1.1,
462
+ min: 0.5,
463
+ max: 2,
464
+ step: 0.1,
465
+ },
466
+ saturation: {
467
+ type: 'number',
468
+ defaultValue: 1,
469
+ min: 0,
470
+ max: 2,
471
+ step: 0.1,
472
+ },
473
+ },
474
+ }) as React.FC<LiquidGradientShaderProps>