Files
lively/src/shaders/color-shift.ts
Mathis Pruvot 1d0b82f31c feat: add SkSL GPU shaders for wallpaper animations
Ken Burns (zoom+pan), Color Shift (HSL cycling), Particles
(snow/rain/bokeh overlay), Vignette Pulse, Glitch (RGB split),
and Depth Parallax (gyroscope-driven 2.5D via depth map).
2026-05-28 11:49:12 +00:00

83 lines
2.0 KiB
TypeScript

import { Skia } from "@shopify/react-native-skia";
// Color Shift: cyclic hue/saturation breathing effect
// Uniforms: time, intensity, speed
export const colorShiftShader = Skia.RuntimeEffect.Make(`
uniform shader image;
uniform float2 resolution;
uniform float time;
uniform float intensity;
uniform float speed;
// RGB to HSL conversion
float3 rgb2hsl(float3 c) {
float mx = max(c.r, max(c.g, c.b));
float mn = min(c.r, min(c.g, c.b));
float l = (mx + mn) * 0.5;
float s = 0.0;
float h = 0.0;
if (mx != mn) {
float d = mx - mn;
s = l > 0.5 ? d / (2.0 - mx - mn) : d / (mx + mn);
if (mx == c.r) {
h = (c.g - c.b) / d + (c.g < c.b ? 6.0 : 0.0);
} else if (mx == c.g) {
h = (c.b - c.r) / d + 2.0;
} else {
h = (c.r - c.g) / d + 4.0;
}
h /= 6.0;
}
return float3(h, s, l);
}
float hue2rgb(float p, float q, float t) {
float tt = t;
if (tt < 0.0) tt += 1.0;
if (tt > 1.0) tt -= 1.0;
if (tt < 1.0/6.0) return p + (q - p) * 6.0 * tt;
if (tt < 1.0/2.0) return q;
if (tt < 2.0/3.0) return p + (q - p) * (2.0/3.0 - tt) * 6.0;
return p;
}
float3 hsl2rgb(float3 hsl) {
float h = hsl.x;
float s = hsl.y;
float l = hsl.z;
if (s == 0.0) return float3(l);
float q = l < 0.5 ? l * (1.0 + s) : l + s - l * s;
float p = 2.0 * l - q;
return float3(
hue2rgb(p, q, h + 1.0/3.0),
hue2rgb(p, q, h),
hue2rgb(p, q, h - 1.0/3.0)
);
}
half4 main(float2 coord) {
half4 color = image.eval(coord);
float3 hsl = rgb2hsl(float3(color.rgb));
float t = time * speed * 0.15;
// Shift hue cyclically
hsl.x = fract(hsl.x + intensity * 0.1 * sin(t));
// Pulse saturation
hsl.y = clamp(hsl.y + intensity * 0.15 * sin(t * 1.3), 0.0, 1.0);
// Subtle luminance breathing
hsl.z = clamp(hsl.z + intensity * 0.03 * sin(t * 0.8), 0.0, 1.0);
float3 rgb = hsl2rgb(hsl);
return half4(half3(rgb), color.a);
}
`)!;