@medalsocial/meda
Version:
Shared Meda UI shell and runtime package.
3 lines (2 loc) • 8.52 kB
TypeScript
export declare const VERTEX_SHADER = "\nuniform float uTime;\nvarying vec2 vUv;\n\nvoid main() {\n vUv = uv;\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n}\n";
export declare const FRAGMENT_SHADER = "\n\nvec3 mod289_3(vec3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }\nvec4 mod289_4(vec4 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }\nvec4 permute(vec4 x) { return mod289_4(((x * 34.0) + 10.0) * x); }\nvec4 taylorInvSqrt(vec4 r) { return 1.79284291400159 - 0.85373472095314 * r; }\n\nfloat snoise(vec3 v) {\n const vec2 C = vec2(1.0/6.0, 1.0/3.0);\n const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);\n\n vec3 i = floor(v + dot(v, C.yyy));\n vec3 x0 = v - i + dot(i, C.xxx);\n\n vec3 g = step(x0.yzx, x0.xyz);\n vec3 l = 1.0 - g;\n vec3 i1 = min(g.xyz, l.zxy);\n vec3 i2 = max(g.xyz, l.zxy);\n\n vec3 x1 = x0 - i1 + C.xxx;\n vec3 x2 = x0 - i2 + C.yyy;\n vec3 x3 = x0 - D.yyy;\n\n i = mod289_3(i);\n vec4 p = permute(permute(permute(\n i.z + vec4(0.0, i1.z, i2.z, 1.0))\n + i.y + vec4(0.0, i1.y, i2.y, 1.0))\n + i.x + vec4(0.0, i1.x, i2.x, 1.0));\n\n float n_ = 0.142857142857;\n vec3 ns = n_ * D.wyz - D.xzx;\n\n vec4 j = p - 49.0 * floor(p * ns.z * ns.z);\n\n vec4 x_ = floor(j * ns.z);\n vec4 y_ = floor(j - 7.0 * x_);\n\n vec4 x = x_ * ns.x + ns.yyyy;\n vec4 y = y_ * ns.x + ns.yyyy;\n vec4 h = 1.0 - abs(x) - abs(y);\n\n vec4 b0 = vec4(x.xy, y.xy);\n vec4 b1 = vec4(x.zw, y.zw);\n\n vec4 s0 = floor(b0) * 2.0 + 1.0;\n vec4 s1 = floor(b1) * 2.0 + 1.0;\n vec4 sh = -step(h, vec4(0.0));\n\n vec4 a0 = b0.xzyw + s0.xzyw * sh.xxyy;\n vec4 a1 = b1.xzyw + s1.xzyw * sh.zzww;\n\n vec3 p0 = vec3(a0.xy, h.x);\n vec3 p1 = vec3(a0.zw, h.y);\n vec3 p2 = vec3(a1.xy, h.z);\n vec3 p3 = vec3(a1.zw, h.w);\n\n vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2,p2), dot(p3,p3)));\n p0 *= norm.x;\n p1 *= norm.y;\n p2 *= norm.z;\n p3 *= norm.w;\n\n vec4 m = max(0.5 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0);\n m = m * m;\n return 105.0 * dot(m * m, vec4(dot(p0,x0), dot(p1,x1), dot(p2,x2), dot(p3,x3)));\n}\n\n// Fractional Brownian Motion: stacked octaves of simplex noise\nfloat fbm(vec3 p) {\n float value = 0.0;\n float amplitude = 0.5;\n float frequency = 1.0;\n for (int i = 0; i < 4; i++) {\n value += amplitude * snoise(p * frequency);\n amplitude *= 0.5;\n frequency *= 2.0;\n }\n return value;\n}\n\n\nuniform float uTime;\nuniform float uAnimation;\nuniform float uInputVolume;\nuniform float uOutputVolume;\nuniform vec3 uColorA;\nuniform vec3 uColorB;\nuniform float uPhaseT;\nuniform float uErrorFlash;\nuniform float uPressed;\nuniform float uOpacity;\nuniform float uVariant; // 0 = metal, 1 = aurora\n\nconst vec3 ERROR_COLOR = vec3(0.85, 0.18, 0.18);\nconst float PI = 3.14159265358979323846;\n\nvarying vec2 vUv;\n\n// =============================================================================\n// METAL look \u2014 smooth chrome-like sphere with strong specular + depth shading.\n// Apple Siri / Vision Pro adjacent.\n// =============================================================================\nvec4 metalLook(vec2 uv, float r, vec3 cA, vec3 cB, float drive) {\n // Two octaves of noise for surface variation\n float n = fbm(vec3(uv * 1.4, uAnimation * 0.18)) * 0.5 + 0.5;\n float n2 = fbm(vec3(uv * 2.6 + 4.7, uAnimation * 0.10)) * 0.5 + 0.5;\n\n // Vertical light bias \u2014 top brighter than bottom (3D illusion)\n float topLight = smoothstep(-1.0, 1.0, uv.y * 0.6 + 0.4);\n float mixT = clamp(n * 0.55 + topLight * 0.45 + n2 * 0.08, 0.0, 1.0);\n\n // Light cream color for the highlight band \u2014 gives the chrome look.\n // Brightens cA toward white for the upper portion of the sphere.\n vec3 highlightTone = mix(cA, vec3(0.95, 0.92, 0.98), 0.55);\n vec3 deepTone = mix(cB, vec3(0.04, 0.02, 0.10), 0.55);\n\n // 4-stop ramp: cream highlight \u2192 cA \u2192 cB \u2192 deep core\n vec3 base;\n if (mixT > 0.66) {\n base = mix(cA, highlightTone, (mixT - 0.66) / 0.34);\n } else if (mixT > 0.33) {\n base = mix(cB, cA, (mixT - 0.33) / 0.33);\n } else {\n base = mix(deepTone, cB, mixT / 0.33);\n }\n\n // Specular: tight bright spot top-left\n vec2 specCenter = vec2(-0.35, 0.45);\n float spec = smoothstep(0.45, 0.0, length(uv - specCenter));\n base += vec3(1.0) * spec * 0.32;\n\n // Bottom shadow for depth\n float shadow = smoothstep(0.3, 1.0, -uv.y) * 0.35;\n base = mix(base, base * 0.55, shadow);\n\n // Inner glow on audio\n float glow = (1.0 - r) * (1.0 - r);\n base += cA * drive * glow * 0.5;\n\n return vec4(base, 1.0);\n}\n\n// =============================================================================\n// AURORA look \u2014 soft layered ribbons drifting across a translucent disc.\n// Northern-lights aesthetic. Calm, atmospheric.\n// =============================================================================\nvec4 auroraLook(vec2 uv, float r, vec3 cA, vec3 cB, float drive) {\n float t = uAnimation * 0.25;\n\n // Disc base \u2014 deep, translucent. cB darkened.\n vec3 baseColor = mix(cB * 0.25, cB * 0.55, smoothstep(1.0, 0.0, r));\n\n // Three drifting ribbons at different y-offsets, angles, and speeds.\n // Each ribbon is a horizontally-stretched soft band whose vertical position\n // oscillates with time + noise.\n\n // Ribbon 1 \u2014 upper, primary color\n float y1 = uv.y - (sin(t * 0.7 + uv.x * 1.5) * 0.18) - 0.15;\n float band1 = exp(-pow(y1 / 0.18, 2.0));\n float n1 = fbm(vec3(uv.x * 2.0 + t, uv.y * 0.8, t * 0.4)) * 0.5 + 0.5;\n vec3 ribbon1 = cA * band1 * n1 * 1.4;\n\n // Ribbon 2 \u2014 middle, accent color (cooler \u2014 shift cA toward cyan)\n vec3 cool = mix(cA, vec3(0.36, 0.83, 1.0), 0.45);\n float y2 = uv.y - (sin(t * 0.55 + uv.x * 2.2 + 1.7) * 0.22) + 0.05;\n float band2 = exp(-pow(y2 / 0.14, 2.0));\n float n2 = fbm(vec3(uv.x * 2.6 + t * 0.6 + 3.1, uv.y * 0.6, t * 0.3)) * 0.5 + 0.5;\n vec3 ribbon2 = cool * band2 * n2 * 1.0;\n\n // Ribbon 3 \u2014 lower, warm accent (shift cA toward pink)\n vec3 warm = mix(cA, vec3(1.0, 0.49, 0.83), 0.55);\n float y3 = uv.y - (sin(t * 0.4 + uv.x * 1.8 + 4.2) * 0.18) + 0.30;\n float band3 = exp(-pow(y3 / 0.16, 2.0));\n float n3 = fbm(vec3(uv.x * 2.2 + t * 0.45 + 7.9, uv.y * 0.7, t * 0.35)) * 0.5 + 0.5;\n vec3 ribbon3 = warm * band3 * n3 * 0.85;\n\n // Stack ribbons additively over the disc\n vec3 base = baseColor + ribbon1 + ribbon2 + ribbon3;\n\n // Audio drive intensifies all ribbons + brightens center\n base += (ribbon1 + ribbon2 + ribbon3) * drive * 0.6;\n float glow = (1.0 - r) * (1.0 - r);\n base += cA * drive * glow * 0.35;\n\n // Subtle inner rim accent for legibility against dark backgrounds\n float rim = smoothstep(0.82, 0.98, r);\n base += cA * rim * 0.22;\n\n return vec4(base, 1.0);\n}\n\nvoid main() {\n vec2 uv = vUv * 2.0 - 1.0;\n float r = length(uv);\n\n // Discard fragments outside the unit circle so the canvas stays clean.\n if (r > 1.0) {\n gl_FragColor = vec4(0.0);\n return;\n }\n\n // ---- Phase masks (0..1 for each phase) ---------------------------------\n // uPhaseT smoothly interpolates between numeric phases:\n // 0=idle, 1=listening, 2=thinking, 3=speaking, 4=error.\n float isListening = clamp(1.0 - abs(uPhaseT - 1.0), 0.0, 1.0);\n float isThinking = clamp(1.0 - abs(uPhaseT - 2.0), 0.0, 1.0);\n float isSpeaking = clamp(1.0 - abs(uPhaseT - 3.0), 0.0, 1.0);\n\n float inputDrive = uInputVolume * isListening;\n float outputDrive = uOutputVolume * isSpeaking;\n float thinkPulse = isThinking * (0.5 + 0.5 * sin(uTime * 2.0));\n float drive = max(inputDrive, max(outputDrive, thinkPulse * 0.4));\n\n // ---- Resolve effective colors with error tint --------------------------\n vec3 cA = mix(uColorA, ERROR_COLOR, uErrorFlash);\n vec3 cB = mix(uColorB, ERROR_COLOR * 0.55, uErrorFlash * 0.7);\n\n // ---- Pick variant ------------------------------------------------------\n vec4 result;\n if (uVariant > 0.5) {\n result = auroraLook(uv, r, cA, cB, drive);\n } else {\n result = metalLook(uv, r, cA, cB, drive);\n }\n\n vec3 base = result.rgb;\n\n // ---- Press: slight core brighten ---------------------------------------\n base = mix(base, base * 1.18, uPressed * (1.0 - smoothstep(0.0, 0.55, r)));\n\n // ---- Edge falloff: smooth alpha at the disc boundary -------------------\n float alpha = smoothstep(1.0, 0.92, r);\n\n gl_FragColor = vec4(base, alpha * uOpacity);\n}\n";