Textured glass
Textured glass with image depth, mouse parallax, and adjustable focus.
Preview
stay.jpeg
Glass
More settings
Installation
bunx shadcn@latest add @modulo/textured-glassRequires an active Modulo key and a project configured for shadcn.
Registry setup
Set MODULO_REGISTRY_KEY to your key. Add this registry entry to components.json.
{
"registries": {
"@modulo": {
"url": "<registry-url>/r/{name}.json",
"headers": {
"Authorization": "Bearer ${MODULO_REGISTRY_KEY}"
}
}
}
}Usage
import { TexturedGlass } from "@/components/textured-glass/TexturedGlass";
export default function Example() {
return (
<TexturedGlass
src="/photo.jpg"
alt="Portrait through textured glass"
roughness={0.68}
distortion={0.012}
/>
);
}React, Three.js, and Transformers.js. All six source files install together. Give the component an image URL and a bounded container.
Registry JSONDownload thumbnailDownload preview GIFDownload preview videoInteraction
Move the pointer across the image to change the camera angle and light. An estimated depth map shapes the photograph into a mesh behind the glass. Closer objects move differently from distant ones. Focus the image and use the arrow keys for keyboard control.
Focus depth ranges from distant objects at 0 to nearby objects at 1. Focus blur softens objects outside that depth. Object depth controls the mesh relief. Depth map displays the estimate, with brighter areas closer to you.
Uploads stay in your browser. The first upload downloads Depth Anything V2 Small and analyzes the image in a worker. Later uploads reuse the model. The default image uses its precomputed depth map. The demo accepts images up to 20 MB. Use default restores stay.jpeg. Save PNG captures the current view.
Depth is estimated from one photograph. Large movements can stretch object boundaries where hidden image content is unavailable.
Pause freezes the camera and light. Hidden tabs and offscreen previews stop rendering. Reduced motion keeps a still view while image uploads and settings remain available.
Reconstructed from Neilson Koerner-Safrata's video. The original shader is unpublished, so exact fidelity has not been verified.
API
| Prop | Type | Default |
|---|---|---|
srcImage URL, including a browser object URL. Remote images need CORS access. Images larger than 4096 pixels are resized for the GPU. | string | Required |
altAccessible description of the image. | string | Required |
depthMapPrecomputed depth image URL. White is near, black is far. Skips automatic analysis. | string | Optional |
estimateDepthEstimate image depth locally with Depth Anything V2 Small in a worker. The first analysis downloads the model. | boolean | true |
roughnessGlass normal strength from 0 to 2. | number | 0.68 |
distortionRefraction distance from 0 to 0.08, relative to image height. | number | 0.012 |
blurImage blur radius from 0 to 30 CSS pixels. | number | 5 |
textureScaleGlass texture repetitions from 0.25 to 8. | number | 2.4 |
gridWire grid opacity from 0 to 1. | number | 0.65 |
gridSizeSquare grid cells across image height, from 10 to 200. | number | 90 |
lightIntensityReflected light intensity from 0 to 2. | number | 0.75 |
lightSizeHighlight radius from 0.1 to 1.5, relative to image height. | number | 0.5 |
speedAutomatic light speed from 0 to 3. | number | 0.45 |
depthDistance between the image and glass plane, from 0 to 2 world units. | number | 0.55 |
parallaxPointer camera movement from 0 to 1.5 world units. | number | 0.7 |
depthStrengthDepth-map displacement from 0 to 2 world units. Zero flattens the image mesh. | number | 0.8 |
focusDepthFocus distance from 0 for far objects to 1 for near objects. | number | 1 |
focusBlurBlur away from the focus depth, from 0 to 30 CSS pixels. | number | 12 |
showDepthDisplay the estimated depth map. | boolean | false |
animateMove the light automatically. The pointer takes control while over the image. | boolean | true |
enabledTurn off the glass to display the original image. | boolean | true |
pausedFreeze light movement. Settings still apply. | boolean | false |
classNameClass names for the container. | string | "" |
onReadyController after image loading, null on unmount. | (controller | null) => void | Optional |
onFrameTime, light position, visibility, pause, and reduced-motion status. | (GlassFrame) => void | Optional |
onErrorImage loading or WebGL initialization failure. | (Error) => void | Optional |
onDepthLocal depth loading progress, analysis, completion, or failure. | (DepthState) => void | Optional |
Controller methods
configure(settings) updates the effect. setImage(url) replaces the image without rebuilding the renderer. setLight(x, y) sets a normalized light position.
pause(), resume(), and reset() control the scene. estimateDepth() retries local image analysis. snapshot() reports camera position, depth-map status, settings and GPU resource counts. exportPNG() returns a PNG blob. The component calls destroy() on unmount.
Source
Checking source access...
