TV Power Off
End a scene the way a tube does — the picture collapses into a glowing line, pinches to a phosphor dot, and the frame is left dead black
This filter re-reads the real pixels of the scene it wraps through the experimental html-in-canvas browser API. The preview above shows the true effect in Chrome 149+ with chrome://flags/#canvas-draw-element enabled (nested canvases need 152.0.7944.0+). Every other browser — Safari, Firefox, Chrome without the flag — falls back to a CSS approximation, so the page and your video still play.
Rendering is supported through the CLI, Studio, Lambda and SSR with --gl=angle, or --gl=swangle on a machine without a GPU. Chrome may change or discontinue the API; the fallback is what keeps your composition renderable if that happens.
Installation
$ pnpm dlx shadcn@latest add @remocn/tv-power-offUsage
Wrap a scene and, on the frame you point it at, its power is cut. The picture squashes toward the centre line while the light it loses is pushed into what is left, so the last few rows are a blown-out band rather than a squashed thumbnail. The band pinches to a dot, the dot decays, and the frame is black.
import { TvPowerOff } from "@/components/remocn/tv-power-off";
export const MyScene = () => (
<TvPowerOff delay={25}>
<Outro />
</TvPowerOff>
);Timing it
delay is counted from the start of the enclosing Sequence, so the scene
plays untouched for delay frames and the collapse runs for the next
durationInFrames. Budget both: a Sequence that ends before
delay + durationInFrames cuts away mid-collapse.
The default 18 frames is a hard power cut. Stretch it toward 30 and the line hangs long enough to read as a tube giving up rather than being switched.
<TvPowerOff delay={60} durationInFrames={26}>
<Scene />
</TvPowerOff>Props
| Prop | Type | Default | Description |
|---|---|---|---|
durationInFrames | number | 18 | How long the whole collapse takes. The first 60% is the vertical squash, the next 22% pinches the line to a dot, and the rest is the dot decaying. |
delay | number | 0 | Frames of untouched scene before the collapse starts, counted from the enclosing Sequence. |
gain | number | 1 | How hard the picture brightens as it is squashed. At 1 the light lost to the collapse is pushed back into the remaining rows, which is what blows the line out to white. At 0 the picture simply shrinks. |
afterglow | number | 1 | Reach of the phosphor bleed — the glow that spills above and below the line, and the halo around the dot. At 0 the collapse is geometry only. |
phosphor | string | "#d8ecff" | Colour of that glow. The cool white of a monochrome tube by default; warm it toward amber for an older terminal. |
children | React.ReactNode | — | The scene being switched off. |
Notes
The squash is an integral, not a scale. Every output row averages the source rows that collapse into it, so text does not alias into stripes on the way down and the line keeps the horizontal colour of the columns above it — that is why the last frames of the band still carry the scene rather than a grey smear.
Once the collapse begins the frame behind the picture is opaque black, and it stays black after the dot is gone. That is a dead screen rather than a hole, so do not expect a backdrop to show through afterwards.
Nothing is carried between frames: progress is a pure function of the current frame, so parallel and server-side renders produce identical pixels.