Skip to content
animorio
IT
Back to the library

Letters full of film

3D, WebGL, HoverWebGLAdvancedCompressed weight: Demo 6.7 KBThree.js 174 KBFreeDownload the zip

Four cards with the letters of the word FILM: each letter is a solid turning slowly around two axes, and its outline is filled with the footage of its category, flat, as if the letter were a hole in the screen. Only the outline changes, the picture inside stays put and keeps playing.

The code

A folder that runs on its own: index.html, style.css, script.js and the libraries from a CDN. The React and Vue tabs hold the same demo as a ready component, which switches its animations off when it leaves the page.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Letters full of film</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/schibsted-grotesk@5.3.0/index.css">
  <link rel="stylesheet" href="style.css">
  <script type="importmap">
    { "imports": {
      "three": "https://cdn.jsdelivr.net/npm/three@0.178.0/build/three.module.min.js"
    } }
  </script>
</head>
<body>
  <!-- the reels of a made-up film studio, one per letter of its word: each letter is a solid that turns slowly in 3D,
       and its outline is filled with that reel's footage, flat, as if the letter were a hole cut in a screen -->
  <main class="sala">
    <header class="sala__testa">
      <p class="sala__etichetta">Mango Pictures</p>
      <h1 class="sala__titolo">Four reels, one word.</h1>
    </header>
    <div class="griglia" data-griglia>
      <canvas class="griglia__tela" data-tela aria-hidden="true"></canvas>
      <a class="carta" href="#" data-carta data-lettera="F" aria-label="Fashion, 12 films">
        <span class="carta__lettera" data-lettera-box><canvas class="carta__film" data-film aria-hidden="true"></canvas></span>
        <span class="carta__riga"><span>Fashion</span><span class="carta__numero">(12)</span></span>
      </a>
      <a class="carta" href="#" data-carta data-lettera="I" aria-label="Illustration, 21 films">
        <span class="carta__lettera" data-lettera-box><canvas class="carta__film" data-film aria-hidden="true"></canvas></span>
        <span class="carta__riga"><span>Illustration</span><span class="carta__numero">(21)</span></span>
      </a>
      <a class="carta" href="#" data-carta data-lettera="L" aria-label="Live, 5 films">
        <span class="carta__lettera" data-lettera-box><canvas class="carta__film" data-film aria-hidden="true"></canvas></span>
        <span class="carta__riga"><span>Live</span><span class="carta__numero">(5)</span></span>
      </a>
      <a class="carta" href="#" data-carta data-lettera="M" aria-label="Music videos, 9 films">
        <span class="carta__lettera" data-lettera-box><canvas class="carta__film" data-film aria-hidden="true"></canvas></span>
        <span class="carta__riga"><span>Music videos</span><span class="carta__numero">(9)</span></span>
      </a>
    </div>
  </main>

  <script type="module" src="script.js"></script>
</body>
</html>

Playground

Change values, colours and text with the controls and watch the animation respond live. Or write in the code yourself. Then download the folder with your changes.

23 values to change

Or ask Claude Code for it

With the Animorio connector, Claude Code takes it from here, guide included, and fits it into your project. Paste this request:

Take “Letters full of film” from Animorio and fit it into my site

What it does

The dark page of a made-up production company, Mango Pictures, with the headline «Four reels, one word.» and below it four cards with a thin border: Fashion, Illustration, Live and Music videos, each with the number of its films. In each card there is a letter of the word FILM, a thick solid turning round and round, about two axes at almost the same speed, so it never repeats the same turn. Inside its outline the card’s footage plays: a striped sunset over the sea, patches of colour chasing each other in a violet room, the beams of a stage over the crowd, neon waves. The footage does not turn with the letter: it stays still in the card, and it is the letter’s outline that changes, wide when seen from the front, thin when seen edge on. With the pointer over a card, or with the keyboard focus, the letter turns four times faster and the footage comes closer. On a phone the cards sit two to a row.

How it works

The letters

Each letter is drawn on a 32 by 32 square as a list of points, with a round hole in the I and a rounded corner in the L. With Three.js it becomes an extruded shape 8 thick, with a small bevel, centred on the origin. The same points also make a flat SVG mask for when WebGL is missing.

A camera that never cuts

The camera is orthographic and √768 wide, the furthest a 32-unit letter can reach from its centre while it turns: so however it is turned, the letter never touches the edges of the card. Every frame the letter starts from zero and turns first about y and then about x, by angles that grow 0.0008 and 0.00082 radians a millisecond.

The flat footage

The letter’s shader lights nothing: it reads the footage at the screen pixel, gl_FragCoord minus the corner of the card, divided by its size. That is why the picture does not turn with the letter and the solid only shows in its outline. An optional value, SHADE, adds a little light on the faces.

One canvas for four cards

A single WebGL canvas lies behind the whole grid; for each card the script measures its square, sets viewport and scissor there and draws its scene. In WebGL the y axis starts at the bottom, so the card is measured from the bottom of the grid. The loop only runs while the grid is on screen.

The four films

Each film is painted by the script on a 384-pixel canvas: stripes and gradients for the sunset, added radial gradients for the patches, faded triangles for the beams, sine waves for the waves. It is repainted thirty times a second and each time becomes its letter’s texture. With the pointer over a card, a spring brings the speed to four times and the footage zoom to 1.18.

Values to change

NameFileDefaultWhat it changes
SPEEDscript.js[0.0008, 0.00082]How fast a letter turns around its two axes, in radians a millisecond (as on the site).
HOVERscript.js4How many times faster a letter turns with the pointer over it.
ZOOMscript.js1.18How much closer the footage comes with the pointer over it.
SCALEscript.js1How big the letter is in its card (1 = it never touches the edges).
DEPTHscript.js8How thick the letters are (a letter is 32 wide).
SHADEscript.js0A little light on the faces (0 = flat footage, as on the site).
FPSscript.js30How many times a second the footage is repainted.

Try them in the Playground

When to use it

For the categories of a portfolio, the sections of a video archive or the letters of a brand that also work as windows on the work: wherever each entry has footage to show and a letter to give it.

On phones

The cards sit two to a row and the letters turn the same way; with a finger the letter speeds up and the footage comes closer for as long as the card is held down.

With reduced motion

No 3D and no movement: each card shows a still frame of its footage inside the flat outline of the letter.

Pitfalls

  • If the shader reads the footage with the shape’s coordinates, the picture turns with the letter and looks printed on it: it must be read at the screen pixel, with gl_FragCoord.
  • In WebGL viewport and scissor count from the bottom, the DOM from the top: the card must be measured from the bottom of the grid, or the letters end up in the wrong card when the grid wraps.
  • A ShaderMaterial does not convert colours: the canvas texture must be left without a colour space, so the footage keeps the colours it has on the 2D canvas.
  • Dark footage makes the letter vanish on the dark page, because the letter is made only of footage: the stage beams were on a black background and moved to a violet and magenta gradient.
  • Adding small turns every frame takes the letter into poses different from the site’s: it is turned again from zero, first about y and then about x, with the two angles added up.

Libraries

Three.js 0.178.0, Schibsted Grotesk (font variabile) 5.3.0.

Compressed with gzip, the three demo files weigh 6.7 KB; the libraries: Three.js 174 KB.

Testing

Tested on 6 October 2026

  • Desktop: Done
  • Phone: Done
  • Reduced motion: Done
  • Safari on iPhone: To do

License

Use it in your own projects and in your clients’ projects. Do not resell it or redistribute it as is. GSAP stays under its own Standard license. Full license.

All animations