# A holographic material built from three ideas

> How the holographic material for Three.js and React Three Fiber works: screen-space scanlines, a Fresnel rim, a flicker and additive blending, and its limits.

Canonical page: https://andersonmancini.dev/blog/holographic-material

Published: 2026-10-03 · 3 min read · Tags: three.js, react-three-fiber, shaders, glsl, open-source

A hologram in a movie is mostly three things: horizontal lines moving across it, a bright rim where the surface turns away from you, and a slight, irregular flicker. None of them needs a texture or a special model. They are all functions of where a pixel is on the screen and which way its surface faces.

The holographic material I published in December 2023 is exactly those three ideas in one shader, for Three.js and React Three Fiber. The fragment shader is about 50 lines.

![A blue hologram of a tall figure with scanlines, standing on a projector pad](https://andersonmancini.dev/blog/holographic-material/cover.webp)

## Using it

```jsx
<mesh>
  <sphereGeometry />
  <HolographicMaterial hologramColor="#51a4de" scanlineSize={8} signalSpeed={0.45} />
</mesh>
```

Every prop has a default, so the first line is enough. The ones you will change are the color, the size and speed of the scanlines, the brightness, how strong the Fresnel rim is and whether the blinking is on. The material is MIT licensed.

## Scanlines that belong to the screen

The first decision is where the lines live. If they were in the model's UV space, they would need clean UVs, they would stretch with the mesh and they would turn with it. A hologram should look like a projection, so the lines belong to the **screen**.

```glsl
vec2 vCoords = vPos.xy;          // clip-space position of the fragment
vCoords /= vPos.w;
vCoords = vCoords * 0.5 + 0.5;   // 0..1 across the screen
vec2 myUV = fract( vCoords );
```

The lines are then a sine wave in `myUV.y`, moved by time and gated by a `smoothstep`, so only some of them are bright at any moment. A small random value, different per channel, is added to the color so the lines are slightly noisy instead of perfectly clean.

Because the lines only need the position on the screen, they do not depend on the model's UVs and work on any mesh, a sphere or a character.

## The rim

The glow that appears where a surface turns away from the camera is a Fresnel term:

```glsl
vec3 viewDirectionW = normalize(cameraPosition - vPositionW);
float fresnelEffect = dot(viewDirectionW, vNormalW) * (1.6 - fresnelOpacity / 2.);
fresnelEffect = clamp(fresnelAmount - fresnelEffect, 0., fresnelOpacity);
```

When the surface faces the camera, the dot product is near 1 and the rim is 0. When it turns away, the dot product falls and the rim grows. `fresnelAmount` decides where the rim starts and `fresnelOpacity` how strong it gets, so a small amount gives a thin edge and a big one fills most of the model.

## The flicker

The blink is a hash of time:

```glsl
float flicker( float amt, float time ) {
  return clamp( fract( cos( time ) * 43758.5453123 ), amt, 1.0 );
}
```

`fract(cos(t) * large number)` is a cheap pseudo-random value that changes in jumps, and clamping it to a minimum keeps the model from disappearing entirely. By default it only affects the Fresnel rim (`blinkFresnelOnly`), which is the part that reads as an unstable projection, and the body keeps steady.

## Additive blending, and bloom

The material is drawn with additive blending by default, so the hologram adds light to whatever is behind it instead of replacing it, which is why it looks like it is emitting. It does not need post-processing, but it is much better with a bloom pass: overexposed areas turn into a glow.

## What is not there

The README lists what I wanted to add and did not: a glitch effect, a vertex shader distortion, video textures as hologram planes, and baking the shader into a texture at runtime for a lower cost. It is a GLSL `ShaderMaterial` for WebGL, so it is not a TSL material and does not run on the WebGPU renderer as is.

There are two versions of the code: a React Three Fiber component in [this repository](https://github.com/ektogamat/threejs-holographic-material) and a vanilla Three.js version in [another one](https://github.com/ektogamat/threejs-vanilla-holographic-material). The [project page](https://andersonmancini.dev/projects/holographic-material.md) here has the demo video.

## Related projects

- [Holographic material](https://andersonmancini.dev/projects/holographic-material.md) — An easy-to-use holographic material
