Components / Animations / Channel Switch
Channel Switch
Content changes the way a CRT changes channel. The picture collapses to a bright line as the vertical deflection fails, then to a dot; the new content goes in while the tube is dark, opens out of a line, and rolls until the vertical hold locks by a damped oscillator. The glow is a real phosphor feedback buffer — each frame keeps the last at e^(−Δt/τ), and the beam lights it at least as bright as it drives it — while the picture itself stays live, accessible DOM. Change channel again mid-switch and it carries on from wherever the picture is.
Usage
import ChannelSwitch from '@/components/channel-switch'
<ChannelSwitch channel={tab}>
{panel}
</ChannelSwitch>Installation
npx shadcn@latest add https://morphiq.prathampatel.design/r/channel-switch.jsonModel
glow ← max(glow·e^(−Δt/τ), beam), ÿ = −ω²y − 2ζωẏτ phosphor persistence · y the vertical hold offset, ζ 0.7, ω = 8.5/duration
Props
| Property | Type | Default | Description |
|---|---|---|---|
channel | string | number | — | Changing this switches channel. The new children go in while the tube is dark. A change mid-switch carries on from wherever the picture is; one back to the channel still on show reopens it with nothing swapped. |
duration | number | 900 | Off and on again, ms, never under 200: about a third going off, a fifth dark, the rest coming on. The vertical hold locks a moment after. |
color | string | '#d9f1ff' | Phosphor colour. Any colour a canvas can parse — not currentColor or a var(); one that does not parse falls back to the default. |
persistence | number | 0.18 | Phosphor decay constant τ, seconds. Longer leaves more afterglow. |
roll | number | 1 | How far out of vertical hold the new picture arrives. 0 locks at once. |
onSwitched | () => void | — | Called as the new content goes in — once per swap, at once under reduced motion. |
children | ReactNode | — | What is showing on the current channel. New children go in while the tube is dark. |