CRT Screen
Put a scene behind curved glass — barrel distortion, phosphor mask, scanlines and a falling-away rim
$ pnpm dlx shadcn@latest add @remocn/crt-screenUsage
CrtScreen is a wrapper. Put a scene inside it and every frame is re-read
through the geometry of a tube: the picture bulges outward so straight lines bow,
an RGB phosphor mask breaks the colour into stripes, scanlines follow the same
curve rather than lying flat across the frame, bright areas flood the mask around
them, and the corners run off the glass into darkness.
It has no duration of its own — it lasts exactly as long as the scene it wraps.
import { CrtScreen } from "@/components/remocn/crt-screen";
export const MyScene = () => (
<CrtScreen>
<Scene />
</CrtScreen>
);Keeping content on the glass
The warp pushes the corners of the frame outside the picture, which is what
produces the dark rim — and what will clip anything parked there. Give the scene
inside a generous margin, or drop curvature toward 0 for a flat-panel look that
keeps the mask and scanlines.
<CrtScreen curvature={0.35}>
<Scene />
</CrtScreen>Props5
| Prop | Type | Default |
|---|---|---|
| curvature | number1 How far the tube bulges. Bends the picture more across the vertical than the horizontal, the way a real tube is shaped. At 0 the frame stays flat and nothing is clipped at the corners. | |
| scanlines | number1 Strength of the horizontal line structure. The lines follow the curvature rather than lying flat, so they bow with the picture. | |
| maskScale | number2 Width in device pixels of one phosphor stripe, so a triad is three times this. Low values read as a fine aperture grille, high values as a coarse arcade tube. Measured in output pixels, so the mask gets finer relative to the frame as you render larger. | |
| vignette | number1 How hard the picture falls off toward the rim, where the glass curves away from the viewer. | |
| children | React.ReactNode— The scene the filter wraps and re-reads every frame. | |
- curvaturenumber
How far the tube bulges. Bends the picture more across the vertical than the horizontal, the way a real tube is shaped. At 0 the frame stays flat and nothing is clipped at the corners.
Default
1 - scanlinesnumber
Strength of the horizontal line structure. The lines follow the curvature rather than lying flat, so they bow with the picture.
Default
1 - maskScalenumber
Width in device pixels of one phosphor stripe, so a triad is three times this. Low values read as a fine aperture grille, high values as a coarse arcade tube. Measured in output pixels, so the mask gets finer relative to the frame as you render larger.
Default
2 - vignettenumber
How hard the picture falls off toward the rim, where the glass curves away from the viewer.
Default
1 - childrenReact.ReactNode
The scene the filter wraps and re-reads every frame.
Notes
Outside the tube the filter writes opaque black rather than nothing, so the rim is real darkness and not a hole showing the untouched scene through it. Inside the tube the scene's own transparency is preserved, so put a background within the wrapper rather than behind it.
The only thing that moves is a 1% brightness breath on a 60-frame cycle, which closes seamlessly on any loop that is a multiple of it. Everything else is fixed geometry, so two renders of the same frame produce the same pixels and the look holds for as long as the scene runs.