Skip to content
animorio
IT
Back to the library

The photo drawn in contour lines

Images, HoverGSAP, CanvasAdvancedCompressed weight: Demo 6.9 KBGSAP 28 KBFreeDownload the zip

A photo made only of contour lines, in the minimal style: on black, a still life with a vase and a sphere is drawn by hairline lines joining the points of equal brightness, as on a map. On opening the lines draw in from the darkest to the lightest, and a thin glint runs along each one. The pointer is a lens on a spring that spreads and lifts the nearby lines like a swelling relief, and the line under it turns vermilion; a tap fades in the real photo they come from.

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>Isoline</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/hanken-grotesk@5.3.0/index.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <!-- a still life drawn only with the contour lines of its brightness: the lines draw in from dark to light, the
       pointer is a lens that lifts and spreads them like a swelling relief, a tap fades in the photo they come from -->
  <main class="pagina" data-pagina>
    <header class="testa">
      <p class="marchio" data-entra>Isoline</p>
      <p class="testa__nota" data-entra>Photography in contour</p>
    </header>

    <figure class="quadro" data-quadro>
      <canvas class="tela" aria-label="A still life of a vase and a sphere drawn with contour lines" data-tela></canvas>
      <figcaption class="didascalia" data-entra>Still life with vase and sphere</figcaption>
    </figure>

    <footer class="piede">
      <p class="nota" data-entra data-nota>Move to lift the lines, tap for the photo</p>
      <p class="stato" data-entra>Showing <span data-stato>lines</span></p>
    </footer>
  </main>

  <script src="https://cdn.jsdelivr.net/npm/gsap@3.15.0/dist/gsap.min.js"></script>
  <script 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.

18 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 “The photo drawn in contour lines” from Animorio and fit it into my site

What it does

Isoline is a made-up photo studio that shows its photos drawn in contour lines. In the middle, on black, there is a picture: a still life with a round vase with a narrow neck and a sphere on a table, lit by a window at the top left. But there is no photo: there are only sixteen families of hairline lines, each joining the points that have the same light, just as the contour lines of a map join the points at the same height. On opening the lines draw themselves, from the darkest to the lightest, each from its own end, and the vase and the sphere come out of the dark. Then a thin glint runs slowly along every line. The pointer is a lens on a spring: near it the lines spread out and rise, the lighter ones higher, like a relief swelling under the hand, and the line running right under the pointer turns vermilion, the only colour. A click or a tap fades in the real photo the lines come from, with a small settle of the picture; another tap goes back to the lines. At the bottom a label says what you are looking at.

How it works

The photo made of light

The photo is not loaded: it is a function that, for every point of the picture, says how bright it is. The wall has a soft light coming from the left, the table starts at 70% of the height with two cast shadows stretched to the right, and the vase and the sphere are shaded like real solids, with diffuse light, a highlight and a bounce from the table below. The edges are blurred by a few thousandths, so the lines don't step.

The contour lines

The light is read on a grid of 168 by 210 points, smoothed twice, and for each of the sixteen levels the script looks for the cells where the light crosses it (marching squares, with the saddle cases resolved by the average at the centre). The pieces of each cell are joined into long lines by following their shared edges, so every line has a start, an end and a length.

The opening and the glint

Each line draws from one end to the other with a dash as long as itself, and level k starts when the opening reaches k: the darkest first. Once the opening is done a second dash, short and far apart, slides along every line at a steady speed, with a different delay for each level: that is the glint.

The lens

Every point near the pointer moves away from the centre of the lens and rises, more if its line is light: with a weight that falls like a bell, exp(-(d/R)²), the lens looks like a relief swelling. The lens chases the pointer on a spring (SPRING) and fades out slowly when the pointer leaves. The line passing under the pointer is drawn again in vermilion, with a gradient that vanishes away from the lens.

The photo and back

The same function draws, once, on a separate canvas of 320 by 400, the photo in warm greys; a tap takes it from 0 to 1 in almost a second with power2.inOut, and the lines are veiled. When nobody moves the pointer, a fake pointer wanders over the picture and now and then shows the photo for two seconds.

Values to change

NameFileDefaultWhat it changes
LEVELSscript.js16How many contour lines: more lines, a finer drawing.
LENSscript.js1How strongly the pointer lifts and spreads the lines: 0 switches the lens off.
RADIUSscript.js0.24How wide the lens is, as a share of the picture's width.
SPRINGscript.js7How quickly the lens follows the pointer: less is softer and later.
GLINTscript.js1How bright the glint running along the lines is: 0 switches it off.
DRAWscript.js2.6How many seconds the lines take to draw in.
LINEscript.js1How thick the lines are.

Try them in the Playground

When to use it

On the page of a photographer or a photo studio, as the opening image of a gallery or a portfolio; for a mapping agency, a science museum or an exhibition about light; anywhere a photo should arrive slowly, first as a drawing and then as an image.

On phones

The same animation: the picture is sized on both width and height, so it fits the box. A dragging finger is the lens, a tap shows the photo; the line at the bottom says drag instead of move.

With reduced motion

The lines are all drawn already and still: no glint, no lens, no fake pointer. A tap goes to the photo and back with a fade only, and the labels fade in.

Pitfalls

  • With hard edges on the vase and the sphere, the lines stepped along the outline: the edges are blurred by a few thousandths and the grid is smoothed twice.
  • The marching squares pieces, drawn one by one, have no direction: for the opening dash and the glint they are joined into long lines by following the cell edge they share.
  • In the saddle cases (two opposite light corners) the way the pieces connect is chosen by the average at the centre, otherwise little crosses appear.
  • The lens moves points every frame: the lines are computed only once, in picture units, and scaled to the real size only when drawn, so a resize doesn't recompute them.

Libraries

GSAP 3.15.0, Hanken Grotesk (font variabile) 5.3.0.

Compressed with gzip, the three demo files weigh 6.9 KB; the libraries: GSAP 28 KB.

Testing

Tested on 24 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