Hologram

Play a scene as a projection — ghost double, emission lines, only the bright parts carrying

Experimental — html-in-canvas

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/hologram

Usage

Hologram is a wrapper. Put a scene inside it and it plays as projected light: a ghost double shimmers off the image, emission lines structure it, a travelling crest runs up the frame, and the whole thing leans toward its tint. Only what is bright enough in the scene carries; the rest sinks into the dark volume the projection hangs in.

import { Hologram } from "@/components/remocn/hologram";
 
export const MyScene = () => (
  <Hologram>
    <Scene />
  </Hologram>
);

What to reach for it for

Put it in a console

The filter is only the light. What makes a shot read as a projection is what the light is coming out of — so build the chrome as ordinary DOM, put your scene inside it, and wrap the whole thing. The frame's thin lines are exactly what the edge emission has to work with, which is why a HUD gains far more from this filter than a flat panel does.

<Hologram>
  <HudFrame>
    <Scene />
  </HudFrame>
</Hologram>

Boot the projection

A projector that snaps on perfectly is a screen. Let the doubling and the flicker start wide and settle over the first second and it reads as something being established rather than switched on.

import { interpolate, useCurrentFrame } from "remotion";
import { Hologram } from "@/components/remocn/hologram";
 
export const Opening = () => {
  const frame = useCurrentFrame();
  const unstable = interpolate(frame, [0, 34], [1, 0], {
    extrapolateRight: "clamp",
  });
 
  return (
    <Hologram ghost={1 + unstable * 3.6} flicker={1 + unstable * 2.6}>
      <Scene />
    </Hologram>
  );
};

To hand the shot back to reality afterwards, cut intensity to 0 — the scene returns exactly as it was, in one frame.

Props

PropTypeDefaultDescription
tint
string"#63e8ff"Colour of the projected light. Almost everything you see is this colour driven by the scene's brightness, so it sets the whole character.
glow
number1Emission strength — both the light that comes off the edges of shapes and the halo bright areas throw into what surrounds them. This is what makes it read as light rather than as a tint.
ghost
number1How unstable the projection is: how far the doubled image sits from the original, and how far individual scanlines slip sideways. Raise it and the projection struggles to hold.
flicker
number1Depth of the brightness pulse, on a 15-frame cycle with a per-frame jitter on top.
intensity
number1Master amount. Read every frame, so cutting it to 0 hands the untouched scene back in a single frame.
children
React.ReactNodeThe scene the filter wraps and re-reads every frame.

Notes

Put your backdrop inside the wrapper. A hologram wants to be translucent light, but this filter cannot be transparent: the untouched scene sits on a layer directly beneath the output, so anywhere the projection thinned to nothing the original interface would show through at full strength — which reads as a bug, not as light. Instead the projection hangs in a dark tinted volume that the filter paints itself, and what is too dim in the scene sinks into it. Visually it is the same picture; structurally it means the wrapper owns the background.

That also makes contrast the thing to design for. Only what is bright enough carries, so a scene of thin bright lines on black — a HUD, a wireframe, mono type — comes through far better than large filled panels.

The only motion is the flicker and the per-line slip, both on fixed frame cycles of 15 and one frame respectively, so nothing drifts and parallel renders match.

In browsers without html-in-canvas the scene keeps the tint and the line structure but loses the edge emission, the halo and the doubling. CSS can colour a frame; it cannot read what is next to a pixel, which is where three of the four signatures here come from.