@toriistudio/shader-ui 0.0.5 → 0.0.6

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.
package/dist/index.d.mts CHANGED
@@ -224,4 +224,14 @@ declare const WANDY_HAND_DEFAULTS: {
224
224
  };
225
225
  declare function WandyHand({ text, fontUrl, fontSize, durationMs, strokeWidth, penOpacity, strokeColor, lineCap, lineJoin, samplesPerCurve, strokeMode, canvasPadding, backgroundColor, imperfectionsEnabled, size, animate, onDrawn, }: WandyHandProps): react_jsx_runtime.JSX.Element;
226
226
 
227
- export { AnimatedDrawingSVG, EFECTO_ASCII_COMPONENT_DEFAULTS, EFECTO_ASCII_POST_PROCESSING_DEFAULTS, Efecto, type EfectoAsciiColorPalette, type EfectoAsciiStyle, type PublicPostProcessingSettings as EfectoPublicAsciiPostProcessingSettings, FractalFlower, MenuGlitch, type MenuGlitchUniforms, OranoParticles, type OranoParticlesUniforms, ShaderArt, type ShaderArtUniforms, Snow, WANDY_HAND_DEFAULTS, WandyHand };
227
+ type RippleWaveProps = {
228
+ width?: string | number;
229
+ height?: string | number;
230
+ intensity?: number;
231
+ zoom?: number;
232
+ speed?: number;
233
+ hexColors?: string[];
234
+ };
235
+ declare function RippleWave({ width, height, intensity, zoom, speed, hexColors, }: RippleWaveProps): react_jsx_runtime.JSX.Element;
236
+
237
+ export { AnimatedDrawingSVG, EFECTO_ASCII_COMPONENT_DEFAULTS, EFECTO_ASCII_POST_PROCESSING_DEFAULTS, Efecto, type EfectoAsciiColorPalette, type EfectoAsciiStyle, type PublicPostProcessingSettings as EfectoPublicAsciiPostProcessingSettings, FractalFlower, MenuGlitch, type MenuGlitchUniforms, OranoParticles, type OranoParticlesUniforms, RippleWave, ShaderArt, type ShaderArtUniforms, Snow, WANDY_HAND_DEFAULTS, WandyHand };
package/dist/index.d.ts CHANGED
@@ -224,4 +224,14 @@ declare const WANDY_HAND_DEFAULTS: {
224
224
  };
225
225
  declare function WandyHand({ text, fontUrl, fontSize, durationMs, strokeWidth, penOpacity, strokeColor, lineCap, lineJoin, samplesPerCurve, strokeMode, canvasPadding, backgroundColor, imperfectionsEnabled, size, animate, onDrawn, }: WandyHandProps): react_jsx_runtime.JSX.Element;
226
226
 
227
- export { AnimatedDrawingSVG, EFECTO_ASCII_COMPONENT_DEFAULTS, EFECTO_ASCII_POST_PROCESSING_DEFAULTS, Efecto, type EfectoAsciiColorPalette, type EfectoAsciiStyle, type PublicPostProcessingSettings as EfectoPublicAsciiPostProcessingSettings, FractalFlower, MenuGlitch, type MenuGlitchUniforms, OranoParticles, type OranoParticlesUniforms, ShaderArt, type ShaderArtUniforms, Snow, WANDY_HAND_DEFAULTS, WandyHand };
227
+ type RippleWaveProps = {
228
+ width?: string | number;
229
+ height?: string | number;
230
+ intensity?: number;
231
+ zoom?: number;
232
+ speed?: number;
233
+ hexColors?: string[];
234
+ };
235
+ declare function RippleWave({ width, height, intensity, zoom, speed, hexColors, }: RippleWaveProps): react_jsx_runtime.JSX.Element;
236
+
237
+ export { AnimatedDrawingSVG, EFECTO_ASCII_COMPONENT_DEFAULTS, EFECTO_ASCII_POST_PROCESSING_DEFAULTS, Efecto, type EfectoAsciiColorPalette, type EfectoAsciiStyle, type PublicPostProcessingSettings as EfectoPublicAsciiPostProcessingSettings, FractalFlower, MenuGlitch, type MenuGlitchUniforms, OranoParticles, type OranoParticlesUniforms, RippleWave, ShaderArt, type ShaderArtUniforms, Snow, WANDY_HAND_DEFAULTS, WandyHand };
package/dist/index.js CHANGED
@@ -37,6 +37,7 @@ __export(src_exports, {
37
37
  FractalFlower: () => FractalFlower,
38
38
  MenuGlitch: () => MenuGlitch,
39
39
  OranoParticles: () => OranoParticles,
40
+ RippleWave: () => RippleWave,
40
41
  ShaderArt: () => ShaderArt,
41
42
  Snow: () => Snow,
42
43
  WANDY_HAND_DEFAULTS: () => WANDY_HAND_DEFAULTS,
@@ -3138,7 +3139,7 @@ var WANDY_HAND_DEFAULTS = {
3138
3139
  animate: true
3139
3140
  };
3140
3141
  function WandyHand({
3141
- text,
3142
+ text = "",
3142
3143
  fontUrl,
3143
3144
  fontSize,
3144
3145
  durationMs = WANDY_HAND_DEFAULTS.durationMs,
@@ -3236,7 +3237,8 @@ function WandyHand({
3236
3237
  }, [resolvedFontUrl]);
3237
3238
  const prepared = (0, import_react9.useMemo)(() => {
3238
3239
  if (!font) return null;
3239
- const safe = text.trim().length ? text : " ";
3240
+ const safeText = typeof text === "string" ? text : "";
3241
+ const safe = safeText.trim().length ? safeText : " ";
3240
3242
  return prepareText(font, safe, resolvedFontSize, resolvedSamplesPerCurve);
3241
3243
  }, [font, text, resolvedFontSize, resolvedSamplesPerCurve]);
3242
3244
  const aspectRatio = (0, import_react9.useMemo)(() => {
@@ -3247,7 +3249,8 @@ function WandyHand({
3247
3249
  }, [prepared]);
3248
3250
  const strokePlan = (0, import_react9.useMemo)(() => {
3249
3251
  if (!prepared) return null;
3250
- const safe = text.trim().length ? text : " ";
3252
+ const safeText = typeof text === "string" ? text : "";
3253
+ const safe = safeText.trim().length ? safeText : " ";
3251
3254
  return createStrokePlan(
3252
3255
  prepared.contours,
3253
3256
  prepared.totalLen,
@@ -3469,6 +3472,286 @@ function WandyHand({
3469
3472
  }
3470
3473
  );
3471
3474
  }
3475
+
3476
+ // src/components/RippleWave.tsx
3477
+ var import_react11 = require("react");
3478
+ var THREE9 = __toESM(require("three"));
3479
+
3480
+ // src/components/ShaderPass.tsx
3481
+ var import_react10 = require("react");
3482
+ var THREE8 = __toESM(require("three"));
3483
+ var import_jsx_runtime11 = require("react/jsx-runtime");
3484
+ var buildQuadGeometry = () => {
3485
+ const geom = new THREE8.BufferGeometry();
3486
+ const positions = new Float32Array([
3487
+ -1,
3488
+ -1,
3489
+ 0,
3490
+ 1,
3491
+ -1,
3492
+ 0,
3493
+ 1,
3494
+ 1,
3495
+ 0,
3496
+ -1,
3497
+ -1,
3498
+ 0,
3499
+ 1,
3500
+ 1,
3501
+ 0,
3502
+ -1,
3503
+ 1,
3504
+ 0
3505
+ ]);
3506
+ const uvs = new Float32Array([
3507
+ 0,
3508
+ 0,
3509
+ 1,
3510
+ 0,
3511
+ 1,
3512
+ 1,
3513
+ 0,
3514
+ 0,
3515
+ 1,
3516
+ 1,
3517
+ 0,
3518
+ 1
3519
+ ]);
3520
+ geom.setAttribute("position", new THREE8.BufferAttribute(positions, 3));
3521
+ geom.setAttribute("uv", new THREE8.BufferAttribute(uvs, 2));
3522
+ return geom;
3523
+ };
3524
+ function ShaderPass({
3525
+ vertexShader,
3526
+ fragmentShader,
3527
+ uniforms,
3528
+ inputUniform = "uTexture",
3529
+ inputTexture = null,
3530
+ target = null,
3531
+ clear = true,
3532
+ clearColor = 0,
3533
+ blending = THREE8.NoBlending,
3534
+ transparent = false,
3535
+ enabled = true,
3536
+ timeUniform,
3537
+ resolutionUniform,
3538
+ hexColors,
3539
+ priority: _priority,
3540
+ className,
3541
+ style,
3542
+ width,
3543
+ height,
3544
+ ...divProps
3545
+ }) {
3546
+ const assetsRef = (0, import_react10.useRef)(null);
3547
+ void _priority;
3548
+ const mixedPaletteColor = (0, import_react10.useMemo)(() => {
3549
+ if (!hexColors?.length) return null;
3550
+ const mixed = new THREE8.Color(0, 0, 0);
3551
+ hexColors.forEach((hex) => {
3552
+ const c = new THREE8.Color(hex);
3553
+ mixed.r += c.r;
3554
+ mixed.g += c.g;
3555
+ mixed.b += c.b;
3556
+ });
3557
+ mixed.r /= hexColors.length;
3558
+ mixed.g /= hexColors.length;
3559
+ mixed.b /= hexColors.length;
3560
+ return mixed;
3561
+ }, [hexColors]);
3562
+ (0, import_react10.useEffect)(() => {
3563
+ if (!uniforms.uPaletteColor) {
3564
+ uniforms.uPaletteColor = {
3565
+ value: mixedPaletteColor ?? new THREE8.Color(0, 0, 0)
3566
+ };
3567
+ } else {
3568
+ uniforms.uPaletteColor.value.copy(
3569
+ mixedPaletteColor ?? new THREE8.Color(0, 0, 0)
3570
+ );
3571
+ }
3572
+ if (!uniforms.uHasPalette) {
3573
+ uniforms.uHasPalette = { value: mixedPaletteColor ? 1 : 0 };
3574
+ } else {
3575
+ uniforms.uHasPalette.value = mixedPaletteColor ? 1 : 0;
3576
+ }
3577
+ if (assetsRef.current) {
3578
+ assetsRef.current.material.uniformsNeedUpdate = true;
3579
+ }
3580
+ }, [mixedPaletteColor, uniforms]);
3581
+ const handleCreate = (0, import_react10.useCallback)(() => {
3582
+ const scene = new THREE8.Scene();
3583
+ const camera = new THREE8.OrthographicCamera(-1, 1, 1, -1, 0, 1);
3584
+ const geometry = buildQuadGeometry();
3585
+ const material = new THREE8.ShaderMaterial({
3586
+ glslVersion: THREE8.GLSL3,
3587
+ vertexShader,
3588
+ fragmentShader,
3589
+ uniforms,
3590
+ blending,
3591
+ transparent,
3592
+ depthTest: false,
3593
+ depthWrite: false
3594
+ });
3595
+ const mesh = new THREE8.Mesh(geometry, material);
3596
+ mesh.frustumCulled = false;
3597
+ scene.add(mesh);
3598
+ assetsRef.current = { scene, camera, mesh, geometry, material };
3599
+ return () => {
3600
+ scene.remove(mesh);
3601
+ geometry.dispose();
3602
+ material.dispose();
3603
+ assetsRef.current = null;
3604
+ };
3605
+ }, [blending, fragmentShader, transparent, uniforms, vertexShader]);
3606
+ const handleRender = (0, import_react10.useCallback)(
3607
+ (context, delta) => {
3608
+ if (!enabled) return;
3609
+ const assets = assetsRef.current;
3610
+ if (!assets) return;
3611
+ if (timeUniform && uniforms[timeUniform]) {
3612
+ uniforms[timeUniform].value = (uniforms[timeUniform].value ?? 0) + delta;
3613
+ }
3614
+ if (resolutionUniform && uniforms[resolutionUniform]) {
3615
+ const v = uniforms[resolutionUniform].value;
3616
+ if (v?.set) v.set(context.size.width, context.size.height);
3617
+ }
3618
+ const prevTarget = context.renderer.getRenderTarget();
3619
+ const prevAutoClear = context.renderer.autoClear;
3620
+ context.renderer.autoClear = false;
3621
+ if (target) context.renderer.setRenderTarget(target);
3622
+ else context.renderer.setRenderTarget(null);
3623
+ if (clear) {
3624
+ const prevClear = context.renderer.getClearColor(new THREE8.Color());
3625
+ const prevAlpha = context.renderer.getClearAlpha();
3626
+ context.renderer.setClearColor(new THREE8.Color(clearColor), 1);
3627
+ context.renderer.clear(true, true, true);
3628
+ context.renderer.setClearColor(prevClear, prevAlpha);
3629
+ }
3630
+ context.renderer.render(assets.scene, assets.camera);
3631
+ context.renderer.setRenderTarget(prevTarget);
3632
+ context.renderer.autoClear = prevAutoClear;
3633
+ },
3634
+ [clear, clearColor, enabled, resolutionUniform, target, timeUniform, uniforms]
3635
+ );
3636
+ const { containerRef } = useScene({
3637
+ onCreate: handleCreate,
3638
+ onRender: handleRender,
3639
+ manualRender: true
3640
+ });
3641
+ (0, import_react10.useEffect)(() => {
3642
+ if (!inputTexture) return;
3643
+ const u = uniforms?.[inputUniform];
3644
+ if (u) u.value = inputTexture;
3645
+ }, [inputTexture, inputUniform, uniforms]);
3646
+ (0, import_react10.useEffect)(() => {
3647
+ const assets = assetsRef.current;
3648
+ if (!assets) return;
3649
+ assets.material.vertexShader = vertexShader;
3650
+ assets.material.fragmentShader = fragmentShader;
3651
+ assets.material.uniforms = uniforms;
3652
+ assets.material.needsUpdate = true;
3653
+ }, [fragmentShader, uniforms, vertexShader]);
3654
+ (0, import_react10.useEffect)(() => {
3655
+ const assets = assetsRef.current;
3656
+ if (!assets) return;
3657
+ assets.material.blending = blending;
3658
+ assets.material.transparent = transparent;
3659
+ assets.material.needsUpdate = true;
3660
+ }, [blending, transparent]);
3661
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3662
+ "div",
3663
+ {
3664
+ ref: containerRef,
3665
+ className,
3666
+ style: {
3667
+ width: width ?? "100%",
3668
+ height: height ?? "100%",
3669
+ ...style
3670
+ },
3671
+ ...divProps
3672
+ }
3673
+ );
3674
+ }
3675
+
3676
+ // src/shaders/ripple-wave/fragment.glsl
3677
+ var fragment_default8 = "precision highp float;\n\nin vec2 vUv;\nout vec4 FragColor;\n\nuniform float uTime;\nuniform vec2 uResolution;\nuniform float uIntensity;\nuniform float uZoom;\nuniform float uSpeed;\nuniform vec3 uPaletteA;\nuniform vec3 uPaletteB;\nuniform int uHasPalette;\n\nvoid main() {\n vec2 uv = vUv - 0.5;\n uv.x *= uResolution.x / max(uResolution.y, 1.0);\n uv *= uZoom;\n\n float t = uTime * uSpeed;\n float rings = sin(length(uv) * 8.0 - t * 1.5);\n float waves = sin((uv.x + uv.y) * 6.0 + t * 0.9);\n float glow = smoothstep(0.0, 1.0, rings * 0.5 + 0.5);\n\n vec3 base = mix(vec3(0.05, 0.1, 0.2), vec3(0.35, 0.8, 0.9), glow);\n if (uHasPalette == 1) {\n base = mix(uPaletteA, uPaletteB, glow);\n }\n vec3 color = base + waves * 0.12;\n color *= uIntensity;\n\n FragColor = vec4(color, 1.0);\n}\n";
3678
+
3679
+ // src/shaders/ripple-wave/vertex.glsl
3680
+ var vertex_default7 = "out vec2 vUv;\n\nvoid main() {\n vUv = uv;\n gl_Position = vec4(position, 1.0);\n}\n";
3681
+
3682
+ // src/components/RippleWave.tsx
3683
+ var import_jsx_runtime12 = require("react/jsx-runtime");
3684
+ function RippleWave({
3685
+ width,
3686
+ height,
3687
+ intensity = 0.85,
3688
+ zoom = 1.2,
3689
+ speed = 0.9,
3690
+ hexColors
3691
+ }) {
3692
+ const uniforms = (0, import_react11.useMemo)(
3693
+ () => ({
3694
+ uTime: { value: 0 },
3695
+ uResolution: { value: new THREE9.Vector2() },
3696
+ uIntensity: { value: intensity },
3697
+ uZoom: { value: zoom },
3698
+ uSpeed: { value: speed },
3699
+ uPaletteA: { value: new THREE9.Color(0, 0, 0) },
3700
+ uPaletteB: { value: new THREE9.Color(0, 0, 0) },
3701
+ uHasPalette: { value: 0 }
3702
+ }),
3703
+ // eslint-disable-next-line react-hooks/exhaustive-deps
3704
+ []
3705
+ );
3706
+ uniforms.uIntensity.value = intensity;
3707
+ uniforms.uZoom.value = zoom;
3708
+ uniforms.uSpeed.value = speed;
3709
+ const mixedPalette = (0, import_react11.useMemo)(() => {
3710
+ if (!hexColors?.length) return null;
3711
+ const midpoint = Math.ceil(hexColors.length / 2);
3712
+ const firstHalf = hexColors.slice(0, midpoint);
3713
+ const secondHalf = hexColors.slice(midpoint);
3714
+ const average = (colors) => {
3715
+ if (!colors.length) return new THREE9.Color(0, 0, 0);
3716
+ const mixed = new THREE9.Color(0, 0, 0);
3717
+ colors.forEach((hex) => {
3718
+ const c = new THREE9.Color(hex);
3719
+ mixed.r += c.r;
3720
+ mixed.g += c.g;
3721
+ mixed.b += c.b;
3722
+ });
3723
+ mixed.r /= colors.length;
3724
+ mixed.g /= colors.length;
3725
+ mixed.b /= colors.length;
3726
+ return mixed;
3727
+ };
3728
+ return {
3729
+ a: average(firstHalf),
3730
+ b: average(secondHalf.length ? secondHalf : firstHalf)
3731
+ };
3732
+ }, [hexColors]);
3733
+ if (mixedPalette) {
3734
+ uniforms.uPaletteA.value.copy(mixedPalette.a);
3735
+ uniforms.uPaletteB.value.copy(mixedPalette.b);
3736
+ uniforms.uHasPalette.value = 1;
3737
+ } else {
3738
+ uniforms.uHasPalette.value = 0;
3739
+ }
3740
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3741
+ ShaderPass,
3742
+ {
3743
+ vertexShader: vertex_default7,
3744
+ fragmentShader: fragment_default8,
3745
+ uniforms,
3746
+ clearColor: 396052,
3747
+ timeUniform: "uTime",
3748
+ resolutionUniform: "uResolution",
3749
+ priority: 1,
3750
+ width,
3751
+ height
3752
+ }
3753
+ );
3754
+ }
3472
3755
  // Annotate the CommonJS export names for ESM import in node:
3473
3756
  0 && (module.exports = {
3474
3757
  AnimatedDrawingSVG,
@@ -3478,6 +3761,7 @@ function WandyHand({
3478
3761
  FractalFlower,
3479
3762
  MenuGlitch,
3480
3763
  OranoParticles,
3764
+ RippleWave,
3481
3765
  ShaderArt,
3482
3766
  Snow,
3483
3767
  WANDY_HAND_DEFAULTS,
package/dist/index.mjs CHANGED
@@ -3113,7 +3113,7 @@ var WANDY_HAND_DEFAULTS = {
3113
3113
  animate: true
3114
3114
  };
3115
3115
  function WandyHand({
3116
- text,
3116
+ text = "",
3117
3117
  fontUrl,
3118
3118
  fontSize,
3119
3119
  durationMs = WANDY_HAND_DEFAULTS.durationMs,
@@ -3211,7 +3211,8 @@ function WandyHand({
3211
3211
  }, [resolvedFontUrl]);
3212
3212
  const prepared = useMemo4(() => {
3213
3213
  if (!font) return null;
3214
- const safe = text.trim().length ? text : " ";
3214
+ const safeText = typeof text === "string" ? text : "";
3215
+ const safe = safeText.trim().length ? safeText : " ";
3215
3216
  return prepareText(font, safe, resolvedFontSize, resolvedSamplesPerCurve);
3216
3217
  }, [font, text, resolvedFontSize, resolvedSamplesPerCurve]);
3217
3218
  const aspectRatio = useMemo4(() => {
@@ -3222,7 +3223,8 @@ function WandyHand({
3222
3223
  }, [prepared]);
3223
3224
  const strokePlan = useMemo4(() => {
3224
3225
  if (!prepared) return null;
3225
- const safe = text.trim().length ? text : " ";
3226
+ const safeText = typeof text === "string" ? text : "";
3227
+ const safe = safeText.trim().length ? safeText : " ";
3226
3228
  return createStrokePlan(
3227
3229
  prepared.contours,
3228
3230
  prepared.totalLen,
@@ -3444,6 +3446,286 @@ function WandyHand({
3444
3446
  }
3445
3447
  );
3446
3448
  }
3449
+
3450
+ // src/components/RippleWave.tsx
3451
+ import { useMemo as useMemo6 } from "react";
3452
+ import * as THREE9 from "three";
3453
+
3454
+ // src/components/ShaderPass.tsx
3455
+ import { useCallback as useCallback7, useEffect as useEffect10, useMemo as useMemo5, useRef as useRef10 } from "react";
3456
+ import * as THREE8 from "three";
3457
+ import { jsx as jsx11 } from "react/jsx-runtime";
3458
+ var buildQuadGeometry = () => {
3459
+ const geom = new THREE8.BufferGeometry();
3460
+ const positions = new Float32Array([
3461
+ -1,
3462
+ -1,
3463
+ 0,
3464
+ 1,
3465
+ -1,
3466
+ 0,
3467
+ 1,
3468
+ 1,
3469
+ 0,
3470
+ -1,
3471
+ -1,
3472
+ 0,
3473
+ 1,
3474
+ 1,
3475
+ 0,
3476
+ -1,
3477
+ 1,
3478
+ 0
3479
+ ]);
3480
+ const uvs = new Float32Array([
3481
+ 0,
3482
+ 0,
3483
+ 1,
3484
+ 0,
3485
+ 1,
3486
+ 1,
3487
+ 0,
3488
+ 0,
3489
+ 1,
3490
+ 1,
3491
+ 0,
3492
+ 1
3493
+ ]);
3494
+ geom.setAttribute("position", new THREE8.BufferAttribute(positions, 3));
3495
+ geom.setAttribute("uv", new THREE8.BufferAttribute(uvs, 2));
3496
+ return geom;
3497
+ };
3498
+ function ShaderPass({
3499
+ vertexShader,
3500
+ fragmentShader,
3501
+ uniforms,
3502
+ inputUniform = "uTexture",
3503
+ inputTexture = null,
3504
+ target = null,
3505
+ clear = true,
3506
+ clearColor = 0,
3507
+ blending = THREE8.NoBlending,
3508
+ transparent = false,
3509
+ enabled = true,
3510
+ timeUniform,
3511
+ resolutionUniform,
3512
+ hexColors,
3513
+ priority: _priority,
3514
+ className,
3515
+ style,
3516
+ width,
3517
+ height,
3518
+ ...divProps
3519
+ }) {
3520
+ const assetsRef = useRef10(null);
3521
+ void _priority;
3522
+ const mixedPaletteColor = useMemo5(() => {
3523
+ if (!hexColors?.length) return null;
3524
+ const mixed = new THREE8.Color(0, 0, 0);
3525
+ hexColors.forEach((hex) => {
3526
+ const c = new THREE8.Color(hex);
3527
+ mixed.r += c.r;
3528
+ mixed.g += c.g;
3529
+ mixed.b += c.b;
3530
+ });
3531
+ mixed.r /= hexColors.length;
3532
+ mixed.g /= hexColors.length;
3533
+ mixed.b /= hexColors.length;
3534
+ return mixed;
3535
+ }, [hexColors]);
3536
+ useEffect10(() => {
3537
+ if (!uniforms.uPaletteColor) {
3538
+ uniforms.uPaletteColor = {
3539
+ value: mixedPaletteColor ?? new THREE8.Color(0, 0, 0)
3540
+ };
3541
+ } else {
3542
+ uniforms.uPaletteColor.value.copy(
3543
+ mixedPaletteColor ?? new THREE8.Color(0, 0, 0)
3544
+ );
3545
+ }
3546
+ if (!uniforms.uHasPalette) {
3547
+ uniforms.uHasPalette = { value: mixedPaletteColor ? 1 : 0 };
3548
+ } else {
3549
+ uniforms.uHasPalette.value = mixedPaletteColor ? 1 : 0;
3550
+ }
3551
+ if (assetsRef.current) {
3552
+ assetsRef.current.material.uniformsNeedUpdate = true;
3553
+ }
3554
+ }, [mixedPaletteColor, uniforms]);
3555
+ const handleCreate = useCallback7(() => {
3556
+ const scene = new THREE8.Scene();
3557
+ const camera = new THREE8.OrthographicCamera(-1, 1, 1, -1, 0, 1);
3558
+ const geometry = buildQuadGeometry();
3559
+ const material = new THREE8.ShaderMaterial({
3560
+ glslVersion: THREE8.GLSL3,
3561
+ vertexShader,
3562
+ fragmentShader,
3563
+ uniforms,
3564
+ blending,
3565
+ transparent,
3566
+ depthTest: false,
3567
+ depthWrite: false
3568
+ });
3569
+ const mesh = new THREE8.Mesh(geometry, material);
3570
+ mesh.frustumCulled = false;
3571
+ scene.add(mesh);
3572
+ assetsRef.current = { scene, camera, mesh, geometry, material };
3573
+ return () => {
3574
+ scene.remove(mesh);
3575
+ geometry.dispose();
3576
+ material.dispose();
3577
+ assetsRef.current = null;
3578
+ };
3579
+ }, [blending, fragmentShader, transparent, uniforms, vertexShader]);
3580
+ const handleRender = useCallback7(
3581
+ (context, delta) => {
3582
+ if (!enabled) return;
3583
+ const assets = assetsRef.current;
3584
+ if (!assets) return;
3585
+ if (timeUniform && uniforms[timeUniform]) {
3586
+ uniforms[timeUniform].value = (uniforms[timeUniform].value ?? 0) + delta;
3587
+ }
3588
+ if (resolutionUniform && uniforms[resolutionUniform]) {
3589
+ const v = uniforms[resolutionUniform].value;
3590
+ if (v?.set) v.set(context.size.width, context.size.height);
3591
+ }
3592
+ const prevTarget = context.renderer.getRenderTarget();
3593
+ const prevAutoClear = context.renderer.autoClear;
3594
+ context.renderer.autoClear = false;
3595
+ if (target) context.renderer.setRenderTarget(target);
3596
+ else context.renderer.setRenderTarget(null);
3597
+ if (clear) {
3598
+ const prevClear = context.renderer.getClearColor(new THREE8.Color());
3599
+ const prevAlpha = context.renderer.getClearAlpha();
3600
+ context.renderer.setClearColor(new THREE8.Color(clearColor), 1);
3601
+ context.renderer.clear(true, true, true);
3602
+ context.renderer.setClearColor(prevClear, prevAlpha);
3603
+ }
3604
+ context.renderer.render(assets.scene, assets.camera);
3605
+ context.renderer.setRenderTarget(prevTarget);
3606
+ context.renderer.autoClear = prevAutoClear;
3607
+ },
3608
+ [clear, clearColor, enabled, resolutionUniform, target, timeUniform, uniforms]
3609
+ );
3610
+ const { containerRef } = useScene({
3611
+ onCreate: handleCreate,
3612
+ onRender: handleRender,
3613
+ manualRender: true
3614
+ });
3615
+ useEffect10(() => {
3616
+ if (!inputTexture) return;
3617
+ const u = uniforms?.[inputUniform];
3618
+ if (u) u.value = inputTexture;
3619
+ }, [inputTexture, inputUniform, uniforms]);
3620
+ useEffect10(() => {
3621
+ const assets = assetsRef.current;
3622
+ if (!assets) return;
3623
+ assets.material.vertexShader = vertexShader;
3624
+ assets.material.fragmentShader = fragmentShader;
3625
+ assets.material.uniforms = uniforms;
3626
+ assets.material.needsUpdate = true;
3627
+ }, [fragmentShader, uniforms, vertexShader]);
3628
+ useEffect10(() => {
3629
+ const assets = assetsRef.current;
3630
+ if (!assets) return;
3631
+ assets.material.blending = blending;
3632
+ assets.material.transparent = transparent;
3633
+ assets.material.needsUpdate = true;
3634
+ }, [blending, transparent]);
3635
+ return /* @__PURE__ */ jsx11(
3636
+ "div",
3637
+ {
3638
+ ref: containerRef,
3639
+ className,
3640
+ style: {
3641
+ width: width ?? "100%",
3642
+ height: height ?? "100%",
3643
+ ...style
3644
+ },
3645
+ ...divProps
3646
+ }
3647
+ );
3648
+ }
3649
+
3650
+ // src/shaders/ripple-wave/fragment.glsl
3651
+ var fragment_default8 = "precision highp float;\n\nin vec2 vUv;\nout vec4 FragColor;\n\nuniform float uTime;\nuniform vec2 uResolution;\nuniform float uIntensity;\nuniform float uZoom;\nuniform float uSpeed;\nuniform vec3 uPaletteA;\nuniform vec3 uPaletteB;\nuniform int uHasPalette;\n\nvoid main() {\n vec2 uv = vUv - 0.5;\n uv.x *= uResolution.x / max(uResolution.y, 1.0);\n uv *= uZoom;\n\n float t = uTime * uSpeed;\n float rings = sin(length(uv) * 8.0 - t * 1.5);\n float waves = sin((uv.x + uv.y) * 6.0 + t * 0.9);\n float glow = smoothstep(0.0, 1.0, rings * 0.5 + 0.5);\n\n vec3 base = mix(vec3(0.05, 0.1, 0.2), vec3(0.35, 0.8, 0.9), glow);\n if (uHasPalette == 1) {\n base = mix(uPaletteA, uPaletteB, glow);\n }\n vec3 color = base + waves * 0.12;\n color *= uIntensity;\n\n FragColor = vec4(color, 1.0);\n}\n";
3652
+
3653
+ // src/shaders/ripple-wave/vertex.glsl
3654
+ var vertex_default7 = "out vec2 vUv;\n\nvoid main() {\n vUv = uv;\n gl_Position = vec4(position, 1.0);\n}\n";
3655
+
3656
+ // src/components/RippleWave.tsx
3657
+ import { jsx as jsx12 } from "react/jsx-runtime";
3658
+ function RippleWave({
3659
+ width,
3660
+ height,
3661
+ intensity = 0.85,
3662
+ zoom = 1.2,
3663
+ speed = 0.9,
3664
+ hexColors
3665
+ }) {
3666
+ const uniforms = useMemo6(
3667
+ () => ({
3668
+ uTime: { value: 0 },
3669
+ uResolution: { value: new THREE9.Vector2() },
3670
+ uIntensity: { value: intensity },
3671
+ uZoom: { value: zoom },
3672
+ uSpeed: { value: speed },
3673
+ uPaletteA: { value: new THREE9.Color(0, 0, 0) },
3674
+ uPaletteB: { value: new THREE9.Color(0, 0, 0) },
3675
+ uHasPalette: { value: 0 }
3676
+ }),
3677
+ // eslint-disable-next-line react-hooks/exhaustive-deps
3678
+ []
3679
+ );
3680
+ uniforms.uIntensity.value = intensity;
3681
+ uniforms.uZoom.value = zoom;
3682
+ uniforms.uSpeed.value = speed;
3683
+ const mixedPalette = useMemo6(() => {
3684
+ if (!hexColors?.length) return null;
3685
+ const midpoint = Math.ceil(hexColors.length / 2);
3686
+ const firstHalf = hexColors.slice(0, midpoint);
3687
+ const secondHalf = hexColors.slice(midpoint);
3688
+ const average = (colors) => {
3689
+ if (!colors.length) return new THREE9.Color(0, 0, 0);
3690
+ const mixed = new THREE9.Color(0, 0, 0);
3691
+ colors.forEach((hex) => {
3692
+ const c = new THREE9.Color(hex);
3693
+ mixed.r += c.r;
3694
+ mixed.g += c.g;
3695
+ mixed.b += c.b;
3696
+ });
3697
+ mixed.r /= colors.length;
3698
+ mixed.g /= colors.length;
3699
+ mixed.b /= colors.length;
3700
+ return mixed;
3701
+ };
3702
+ return {
3703
+ a: average(firstHalf),
3704
+ b: average(secondHalf.length ? secondHalf : firstHalf)
3705
+ };
3706
+ }, [hexColors]);
3707
+ if (mixedPalette) {
3708
+ uniforms.uPaletteA.value.copy(mixedPalette.a);
3709
+ uniforms.uPaletteB.value.copy(mixedPalette.b);
3710
+ uniforms.uHasPalette.value = 1;
3711
+ } else {
3712
+ uniforms.uHasPalette.value = 0;
3713
+ }
3714
+ return /* @__PURE__ */ jsx12(
3715
+ ShaderPass,
3716
+ {
3717
+ vertexShader: vertex_default7,
3718
+ fragmentShader: fragment_default8,
3719
+ uniforms,
3720
+ clearColor: 396052,
3721
+ timeUniform: "uTime",
3722
+ resolutionUniform: "uResolution",
3723
+ priority: 1,
3724
+ width,
3725
+ height
3726
+ }
3727
+ );
3728
+ }
3447
3729
  export {
3448
3730
  AnimatedDrawingSVG,
3449
3731
  EFECTO_ASCII_COMPONENT_DEFAULTS,
@@ -3452,6 +3734,7 @@ export {
3452
3734
  FractalFlower,
3453
3735
  MenuGlitch,
3454
3736
  OranoParticles,
3737
+ RippleWave,
3455
3738
  ShaderArt,
3456
3739
  Snow,
3457
3740
  WANDY_HAND_DEFAULTS,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@toriistudio/shader-ui",
3
- "version": "0.0.5",
3
+ "version": "0.0.6",
4
4
  "description": "Shader components",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.mjs",