Custom Framer Component · Free, unlicensed
Liquid Glass (Cosmic Background)
Liquid glass cards floating over an animated WebGL shader backdrop. Imports three and @react-three/fiber — confirm Framer resolves these before shipping.
This is a standalone Framer Code File — not installed with the CLI, not gated behind a subscription. Copy the whole file and paste it into Framer via Assets → Code → Create Code File.
Property controls
These are Framer's own addPropertyControls fields,
which show up as the right-hand properties panel once this is pasted into Framer. They are
not React props and have nothing to do with this site's licensed component API.
This component takes no property controls — paste it in as-is.
Component source
The complete, unmodified file — copy the whole thing.
"use client";
/**
* CAVEAT — READ BEFORE PASTING INTO FRAMER
*
* This component imports `three` and `@react-three/fiber`. A single-file
* Framer Code File paste does NOT automatically resolve npm packages the
* same way a local dev build does. Framer has its own package-resolution
* behaviour for Code Files, and it has not been verified live in a Framer
* project as part of building this catalogue entry. Before relying on this
* component in a real project: paste it into a scratch Framer file first and
* confirm `three` / `@react-three/fiber` actually resolve there. Don't treat
* this as a guaranteed one-paste-and-done component the way TestimonialsSlider
* and LiquidGlass are.
*/
import React, { useRef, useMemo } from "react"
import { motion } from "framer-motion"
import { Canvas, useFrame } from "@react-three/fiber"
import * as THREE from "three"
/**
* META — read by scripts/gen-framer-components.mjs to build
* src/data/framer-components.json. Keep this a plain object literal: string
* and string-array values only, no function calls, no template interpolation.
*/
export const META = {
slug: "liquid-glass-cosmic",
title: "Liquid Glass (Cosmic Background)",
description:
"Liquid glass cards floating over an animated WebGL shader backdrop. Imports three and @react-three/fiber — confirm Framer resolves these before shipping.",
tags: ["glassmorphism", "webgl", "shader", "background", "three.js"],
category: "custom-framer",
}
interface CosmicDiscsShadersProps {
speed?: number
intensity?: number
ringCount?: number
arcWidth?: number
colorShift?: number
className?: string
}
function CosmicShaderMaterial({ speed = 1.0, intensity = 1.0, ringCount = 1.0, arcWidth = 0.6, colorShift = 1.0 }) {
const materialRef = useRef<THREE.ShaderMaterial>(null!)
const vertexShader = `
void main() {
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`
const fragmentShader = `
uniform float iTime;
uniform vec2 iResolution;
uniform float u_speed;
uniform float u_intensity;
uniform float u_ringCount;
uniform float u_arcWidth;
uniform float u_colorShift;
void main() {
vec4 O = vec4(0.0);
vec2 I = gl_FragCoord.xy;
vec2 r = iResolution.xy;
vec2 p = (I - r * 0.6) * mat2(1, -1, 2, 2);
for(float i = 0.0; i < 30.0; i++) {
if(i >= 30.0 * u_ringCount) break;
vec2 coords = p / (r + r - p).y;
float ringDist = length(coords) * 80.0;
float ringAttenuation = abs(ringDist - i) + 40.0 / r.y;
float a = atan(coords.y, coords.x) * ceil(i * 0.1) + iTime * sin(i * i) * u_speed + i * i;
float arcMask = clamp(cos(a), 0.0, u_arcWidth);
vec4 color = cos(a - i + vec4(0, 1, 2, 0) * u_colorShift) + 1.0;
O += (0.2 * u_intensity / ringAttenuation) * arcMask * color;
}
gl_FragColor = O;
}
`
const uniforms = useMemo(() => ({
iTime: { value: 0 },
iResolution: { value: new THREE.Vector2(window.innerWidth, window.innerHeight) },
u_speed: { value: speed },
u_intensity: { value: intensity },
u_ringCount: { value: ringCount },
u_arcWidth: { value: arcWidth },
u_colorShift: { value: colorShift },
}), [speed, intensity, ringCount, arcWidth, colorShift])
useFrame((state) => {
if (materialRef.current) {
materialRef.current.uniforms.iTime.value = state.clock.elapsedTime
}
})
return (
<shaderMaterial
ref={materialRef}
vertexShader={vertexShader}
fragmentShader={fragmentShader}
uniforms={uniforms}
/>
)
}
function CosmicDiscsShaders({ speed = 1.0, intensity = 1.0, ringCount = 1.0, arcWidth = 0.6, colorShift = 1.0, className }: CosmicDiscsShadersProps) {
return (
<div className={className} style={{ width: '100%', height: '100%' }}>
<Canvas style={{ width: '100%', height: '100%' }}>
<mesh>
<planeGeometry args={[2, 2]} />
<CosmicShaderMaterial
speed={speed}
intensity={intensity}
ringCount={ringCount}
arcWidth={arcWidth}
colorShift={colorShift}
/>
</mesh>
</Canvas>
</div>
)
}
interface LiquidGlassCardProps {
tint: string
blur: number
opacity: number
title: string
description: string
delay?: number
}
function LiquidGlassCard({ tint, blur, opacity, title, description, delay = 0 }: LiquidGlassCardProps) {
return (
<motion.div
style={{
position: "relative",
padding: 24,
borderRadius: 20,
background: `linear-gradient(135deg, ${tint}20, ${tint}10)`,
backdropFilter: `blur(${blur}px)`,
WebkitBackdropFilter: `blur(${blur}px)`,
border: `1px solid ${tint}30`,
boxShadow: `
0 8px 32px rgba(0, 0, 0, 0.12),
inset 0 1px 0 rgba(255, 255, 255, 0.2)
`,
opacity: opacity,
overflow: "hidden",
width: 300,
height: 200,
}}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
whileHover={{
scale: 1.02,
transition: { duration: 0.3, ease: "easeOut" }
}}
transition={{ duration: 0.6, ease: "easeOut", delay }}
>
<motion.div
style={{
position: "absolute",
top: 0,
left: 0,
right: 0,
bottom: 0,
background: `radial-gradient(circle at 50% 0%, ${tint}15, transparent 70%)`,
pointerEvents: "none",
}}
animate={{
opacity: [0.3, 0.7, 0.3],
}}
transition={{
duration: 4,
repeat: Infinity,
ease: "easeInOut"
}}
/>
<div style={{ position: "relative", zIndex: 1 }}>
<h2 style={{ margin: 0, marginBottom: 12, color: "#ffffff", fontSize: 18, fontWeight: 600 }}>
{title}
</h2>
<p style={{ margin: 0, color: "#ffffff90", fontSize: 14, lineHeight: 1.4 }}>
{description}
</p>
</div>
</motion.div>
)
}
/**
* @framerSupportedLayoutWidth any
* @framerSupportedLayoutHeight any
*/
export default function LiquidGlassCosmic() {
const cards = [
{
tint: "#09F",
title: "Innovation",
description: "Cutting-edge technology that pushes the boundaries of what's possible."
},
{
tint: "#F09",
title: "Design",
description: "Beautiful interfaces that create meaningful connections with users."
},
{
tint: "#90F",
title: "Performance",
description: "Lightning-fast experiences that deliver results when it matters most."
}
]
return (
<div style={{ position: "relative", width: "100%", height: "100vh", overflow: "hidden" }}>
{/* Cosmic Background */}
<div style={{ position: "absolute", inset: 0, zIndex: 0 }}>
<CosmicDiscsShaders
speed={1.0}
intensity={1.2}
ringCount={0.8}
arcWidth={0.6}
colorShift={1.0}
className="h-full w-full"
/>
</div>
{/* Liquid Glass Cards */}
<div
style={{
position: "relative",
zIndex: 1,
display: "flex",
alignItems: "center",
justifyContent: "center",
height: "100%",
gap: 32,
padding: 32,
flexWrap: "wrap"
}}
>
{cards.map((card, index) => (
<LiquidGlassCard
key={index}
tint={card.tint}
blur={10}
opacity={0.9}
title={card.title}
description={card.description}
delay={index * 0.2}
/>
))}
</div>
</div>
)
}
- 1. In Framer: Assets → Code → Create Code File.
- 2. Delete the placeholder and paste this entire file — it already carries its default export and addPropertyControls.