Skip to content
animorio
IT
Back to the library

The frame that changes shape

Images, TransitionsGSAPMediumCompressed weight: Demo 9.7 KBGSAP 28 KBFreeDownload the zip

In the minimal style: a gallery with a single thin frame in the middle. The pictures behind it stay still, and at every change the frame takes a breath and springs to another proportion (square, portrait, panorama, landscape, story), cropping them in a new way; the caption underneath rolls letter by letter.

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>Ratio</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/instrument-sans@5.3.0/wdth.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <!-- one thin frame in the middle of the room: the pictures behind it never move, the frame crops them -->
  <main class="room" data-room tabindex="0" role="region" aria-roledescription="gallery" aria-label="Ratio, a gallery of five pictures. Press the arrow keys or click to change picture.">
    <header class="top">
      <p class="mark" data-mark aria-hidden="true">Ratio</p>
      <p class="sub" data-sub>Studies in crop</p>
    </header>

    <div class="pictures" data-pictures aria-hidden="true"></div>

    <svg class="frame" data-frame aria-hidden="true">
      <path class="frame__line" data-line pathLength="1" d="" />
    </svg>

    <div class="caption" data-caption aria-hidden="true">
      <p class="caption__title"><span class="slot" data-title></span></p>
      <p class="caption__meta"><span class="slot slot--format" data-format></span><span class="slot slot--ratio" data-ratio></span></p>
    </div>

    <p class="hint" data-hint aria-hidden="true">Click for the next picture</p>
    <p class="sr" data-live aria-live="polite"></p>
  </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.

33 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 frame that changes shape” from Animorio and fit it into my site

What it does

A paper-coloured room, with the name of a made-up gallery, Ratio, at the top left and a small line at the right. In the middle a thin black line draws itself all round a square, starting from a corner; inside, the picture opens from a horizontal line on a spring: a low sun touching the sea, drawn with flat shapes and soft gradients and a light print grain. Under the frame the title rises, Low sun, and on the right the name of the shape and the proportion, Square 1:1: the letters come up from below one after another and widen with a little bounce of the width axis. After a couple of seconds the frame changes: it shrinks by a breath, then springs to the new proportion, overshoots a touch and settles, while the white space between picture and line opens and closes with an elastic. At first it is still the picture from before, cropped differently (nothing moves behind the frame); then the new one comes in like a blind, sideways if the frame gets wider, from below if it gets taller. Meanwhile the caption rolls: the letters of the old title escape upwards, the new ones rise from below, then the name of the shape and the proportion. The five pictures are two hills in portrait (4:5), still water with an island in panorama (21:9), a terracotta arch in landscape (3:2) and a field at night in the story format (9:16), then it starts again. A click goes to the next picture, a click on the left third goes back to the one before (the line at the bottom says which way it goes); the arrow keys too and, on a phone, a tap and a swipe. With a mouse the frame glides a few pixels towards the pointer over the still picture, and hovering over it the white space tightens and the picture stays until you leave.

How it works

The pictures do not move

Every picture is an SVG as big as the room, drawn by the script around the middle of the frame: the sun, the hills, the island and the arch always sit in the centre, so every crop is a good one. They all live in one container cut with clip-path: inset(), and the window is the frame: changing the four inset values changes the shape, while the pictures stay where they are. On top sits a tile of noise drawn once on a canvas, in multiply, for the grain.

The proportions

Every entry in PICTURES has its proportion written as width:height. For each one the size is found by fitting it into the free space (less the name at the top and the caption at the bottom) and then capping its area at a little more than the square's: so the panorama does not get huge and the story does not vanish, and it really looks like the same picture cut another way.

A real spring

The ease is a function written by hand: the position of a spring let go from rest, 1 minus e to the minus dt times (cos wt plus d/w sin wt). The first overshoot is e to the minus d pi over w, so SPRING picks exactly how far the frame goes past; the tiny remainder left at the end is spread over the tail, so the tween lands precisely. Before the spring the frame shrinks by 1.6% in a sixth of a second: the breath that sets up the jump.

The line and the white space

The thin line is a path in an SVG as big as the room, redrawn on every frame by the GSAP ticker around the window, on half a pixel to stay sharp. The space between picture and line is a number of its own: during a change it opens with power2.out and closes again with elastic.out, and with the mouse over it it tightens; so the line never touches the picture, even when the spring overshoots. At the opening the line draws itself with stroke-dashoffset on pathLength 1.

The blind and the caption

The new picture comes on top of the others and is uncovered by a clip-path: inset() of its own, running from one side of the box that holds both the old and the new frame; it starts when the spring is already a third of the way, so first you see the old picture cropped another way. The caption follows the bottom edge of the line and is as wide as it. Every text sits in a slot with hidden overflow: old and new lines stack in the same grid cell, letters leave upwards and come in from below, and the --w variable takes the typeface's wdth axis from 76 to 100 with an elastic.

Values to change

NameFileDefaultWhat it changes
PICTURESscript.js[{ title: 'Low sun', shape: 'Square', ratio: '1:1' }, …]The pictures, in order: the title, the name of the shape and the proportion of the frame (width:height, for example 16:9). There are five drawings, repeated if there are more entries.
HOLDscript.js2.6How many seconds each picture stays before the next one.
MORPHscript.js1.15How many seconds the frame takes to change shape.
SPRINGscript.js0.4How far the frame goes past before it settles: 0 arrives smoothly, 1 bounces a lot.
MATscript.js10The white space between the picture and the line, in pixels (0 = the line on the picture's edge).
SIZEscript.js0.8How much of the room the frame takes up.
AUTOPLAYscript.jstrueWhether the pictures change by themselves. With false they change only with a click, a swipe or the arrow keys.

Try them in the Playground

When to use it

For a gallery that should feel like an object, not a grid: a photographer's or illustrator's portfolio, an exhibition page, a design studio's showcase, an art print shop, a project presentation. It shows pictures of different formats well, without stretching them or cropping them at random.

On phones

The same animation with the sizes adapted: the frame takes up almost the whole width and the title is smaller. A tap goes to the next picture, a swipe right or left goes forwards or back.

With reduced motion

Nothing moves: everything fades in, and at every change frame, picture and caption fade out and back in with the new shape, with no spring, blind or rolling letters.

Pitfalls

  • With the blind starting together with the spring the idea did not come across: you only saw a new picture in a new frame. It starts when the spring is a third of the way, so first you see the old picture cropped another way.
  • A line following the frame with a little delay ended up over the picture in big jumps (from story to panorama): the white space is a number of its own that opens and closes with an elastic, and the line is always the window plus that space.
  • Between a panorama and a story the area changed threefold and they looked like two different pictures: every shape fits the free space, but its area stays close to the square's.
  • Letters widening with an elastic change the width of the line: old and new lines sit in the same grid cell, so the slot does not jump, and the name of the shape sits on the right, away from the title.
  • A one-pixel line on whole coordinates blurs over two pixels: the path is drawn on the half pixel, and the window on whole pixels.

Libraries

GSAP 3.15.0, Instrument Sans (font variabile) 5.3.0.

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

Testing

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