Skip to content
animorio
IT
Back to the library

The theatre-curtain logo

Intro, SVG, TextGSAPAdvancedCompressed weight: Demo 18 KBGSAP 28 KBFreeDownload the zip

A logo’s entrance at the theatre: someone moves behind the red velvet curtain, a gloved hand drums its fingers through the gap, the curtain opens gathering its folds, a spotlight searches the dark stage and finds the logo, the footlights come on one by one and the logo takes a bow among confetti and roses. In the Playground you type your own name or upload your own logo.

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>The theatre-curtain logo</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/bodoni-moda@5.3.0/index.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="scena">
    <!-- the theatre: the script measures it, builds the stage around the logo and draws the curtain every frame -->
    <svg class="palco" data-stage role="img" aria-label="Bravessa" xmlns="http://www.w3.org/2000/svg">
      <defs>
        <!-- one pleat of velvet: dark in the folds, a soft sheen on the crest -->
        <linearGradient id="pleat" x1="0" y1="0" x2="1" y2="0">
          <stop offset="0" class="velluto-fondo" />
          <stop offset="0.3" class="velluto-pieno" />
          <stop offset="0.52" class="velluto-lume" />
          <stop offset="0.74" class="velluto-pieno" />
          <stop offset="1" class="velluto-fondo" />
        </linearGradient>
        <!-- the shade over the curtain: dark under the pelmet, lighter in the middle, dark again at the hem -->
        <linearGradient id="pleat-shade" x1="0" y1="0" x2="0" y2="1">
          <stop offset="0" class="ombra" stop-opacity="0.55" />
          <stop offset="0.22" class="ombra" stop-opacity="0" />
          <stop offset="0.8" class="ombra" stop-opacity="0" />
          <stop offset="1" class="ombra" stop-opacity="0.35" />
        </linearGradient>
        <!-- the swags of the pelmet -->
        <linearGradient id="swag" x1="0" y1="0" x2="0" y2="1">
          <stop offset="0" class="velluto-fondo" />
          <stop offset="0.55" class="velluto-pieno" />
          <stop offset="0.85" class="velluto-lume" />
          <stop offset="1" class="velluto-pieno" />
        </linearGradient>
        <!-- gilded wood: the frame of the stage and the trim of the apron -->
        <linearGradient id="gilt" x1="0" y1="0" x2="1" y2="1">
          <stop offset="0" class="oro-lume" />
          <stop offset="0.35" class="oro-pieno" />
          <stop offset="0.6" class="oro-fondo" />
          <stop offset="0.8" class="oro-pieno" />
          <stop offset="1" class="oro-lume" />
        </linearGradient>
        <linearGradient id="gilt-bar" x1="0" y1="0" x2="0" y2="1">
          <stop offset="0" class="oro-lume" />
          <stop offset="0.5" class="oro-pieno" />
          <stop offset="1" class="oro-fondo" />
        </linearGradient>
        <!-- where something pushes the velvet from behind, it catches the light -->
        <radialGradient id="bulge">
          <stop offset="0" class="velluto-lume" stop-opacity="0.75" />
          <stop offset="1" class="velluto-lume" stop-opacity="0" />
        </radialGradient>
        <!-- the hole the spotlight makes in the dark, soft at its edge -->
        <radialGradient id="spot-hole">
          <stop offset="0" stop-color="#000" />
          <stop offset="0.72" stop-color="#000" />
          <stop offset="1" stop-color="#fff" />
        </radialGradient>
        <!-- the warm pool of the spotlight -->
        <radialGradient id="spot-pool">
          <stop offset="0" class="luce" stop-opacity="0.24" />
          <stop offset="0.7" class="luce" stop-opacity="0.13" />
          <stop offset="1" class="luce" stop-opacity="0" />
        </radialGradient>
        <!-- the beam: strong at the lens, thin by the time it reaches the stage -->
        <linearGradient id="beam" gradientUnits="userSpaceOnUse" data-beam-fill>
          <stop offset="0" class="luce" stop-opacity="0.5" />
          <stop offset="1" class="luce" stop-opacity="0.1" />
        </linearGradient>
        <!-- the footlights wash the stage from below -->
        <linearGradient id="wash" x1="0" y1="1" x2="0" y2="0">
          <stop offset="0" class="ribalta" stop-opacity="0.55" />
          <stop offset="0.5" class="ribalta" stop-opacity="0.12" />
          <stop offset="1" class="ribalta" stop-opacity="0" />
        </linearGradient>
        <linearGradient id="backdrop" x1="0" y1="0" x2="0" y2="1">
          <stop offset="0" class="fondale-alto" />
          <stop offset="1" class="fondale" />
        </linearGradient>
        <!-- the logo goes a little darker while it bows, turned away from the light -->
        <filter id="dim" color-interpolation-filters="sRGB">
          <feComponentTransfer data-dim>
            <feFuncR type="linear" slope="1" />
            <feFuncG type="linear" slope="1" />
            <feFuncB type="linear" slope="1" />
          </feComponentTransfer>
        </filter>
        <!-- everything on the stage stays inside the opening -->
        <clipPath id="opening" clipPathUnits="userSpaceOnUse"><rect data-opening /></clipPath>
        <!-- the dark on the stage, with the hole of the spotlight in it -->
        <mask id="dark-mask" maskUnits="userSpaceOnUse" data-dark-mask>
          <rect fill="#fff" data-dark-full />
          <ellipse fill="url(#spot-hole)" data-hole />
        </mask>
        <!-- the dust only shows inside the beam -->
        <clipPath id="beam-clip" clipPathUnits="userSpaceOnUse"><path data-beam-clip /></clipPath>

        <!-- a tassel: the point where the cord hangs is 0 0 -->
        <g id="t-tassel">
          <path class="nappa-cordone" d="M0 0L0 11" />
          <path class="nappa" d="M-6 10C-7.5 15 -8.5 20 -7.5 24L7.5 24C8.5 20 7.5 15 6 10Z" />
          <ellipse class="nappa" cx="0" cy="10" rx="6" ry="3.4" />
          <path class="nappa-lucido" d="M-3.4 13.5Q-4.6 18 -3.6 21.5" />
          <rect class="nappa-fascia" x="-8.8" y="23" width="17.6" height="5.4" rx="2.2" />
          <path class="nappa" d="M-8 28.4L-11.5 53Q0 57.5 11.5 53L8 28.4Z" />
          <path class="nappa-fili" d="M-5 31L-7.6 53.4M-1.8 31L-2.6 55.2M1.8 31L2.6 55.2M5 31L7.6 53.4" />
        </g>
        <!-- a footlight: a pear of glass on a brass screw, with its filament; the middle of the base is 0 0 -->
        <g id="t-bulb">
          <path class="vetro" d="M-5 -9C-5 -13 -10 -16 -10 -24C-10 -31 -5.5 -35 0 -35C5.5 -35 10 -31 10 -24C10 -16 5 -13 5 -9Z" />
          <path class="vetro-acceso" data-glass-on d="M-5 -9C-5 -13 -10 -16 -10 -24C-10 -31 -5.5 -35 0 -35C5.5 -35 10 -31 10 -24C10 -16 5 -13 5 -9Z" />
          <path class="supporto" d="M-2.4 -9L-3.6 -22M2.4 -9L3.6 -22" />
          <path class="filamento" d="M-3.6 -22L-2.4 -25L-1.2 -22L0 -25L1.2 -22L2.4 -25L3.6 -22" />
          <path class="filamento-acceso" data-wire-on d="M-3.6 -22L-2.4 -25L-1.2 -22L0 -25L1.2 -22L2.4 -25L3.6 -22" />
          <path class="riflesso-vetro" d="M-6.4 -26Q-6.6 -30.5 -3 -32.4" />
          <path class="zoccolo" d="M-6 -9.5L6 -9.5L6 -1L3.4 1.6L-3.4 1.6L-6 -1Z" />
          <path class="zoccolo-righe" d="M-6 -6.8L6 -7.8M-6 -3.6L6 -4.6" />
        </g>
        <!-- a rose: the middle of the flower is 0 0, the stem hangs down -->
        <g id="t-rose">
          <path class="stelo-bordo" d="M0 8C2 30 -2 52 1 78" />
          <path class="stelo" d="M0 8C2 30 -2 52 1 78" />
          <path class="spina" d="M1.4 29L6 25.6L1.8 33.4ZM-0.4 53L-5 49.6L-0.9 57.4Z" />
          <path class="foglia" d="M1 46C7 37 18 36 23 40C17 48 8 50 1 46Z" />
          <path class="venatura" d="M2.5 45.4Q12 41.5 21 40.2" />
          <path class="foglia" d="M-10 8.6L-3.4 4.4L0 9.6L3.4 4.4L10 8.6L4.6 13L0 10.6L-4.6 13Z" />
          <path class="rosa" d="M-14.5 -2C-16.5 -12 -8.5 -19.5 0 -18.5C8.5 -19.5 16.5 -12 14.5 -2C12.5 6 6.5 10.5 0 10.5C-6.5 10.5 -12.5 6 -14.5 -2Z" />
          <path class="rosa-cuore" d="M-8.5 -5.5C-9 -12 -3 -14.5 2 -13C7 -11.4 8 -5.4 4 -2C0.6 0.6 -4.4 -1 -3.6 -5C-3 -8 1.6 -8.4 2.4 -5.4" />
          <path class="rosa-piega" d="M-14.5 -2C-10 2.6 -4.4 4.4 0 3.4M14.5 -2C10 2.6 4.4 4.4 0 3.4M-11 -12.5C-8 -9 -8.6 -5 -8.5 -5.5" />
          <path class="rosa-lucido" d="M-10.5 -11Q-6.6 -15.6 -1 -15.6" />
        </g>
      </defs>

      <rect class="sala" data-house />

      <!-- the stage, seen through the opening -->
      <g clip-path="url(#opening)">
        <g data-set></g>
        <ellipse class="ombra-logo" data-logo-shadow />
        <g data-logo></g>
        <rect class="buio" mask="url(#dark-mask)" data-dark />
        <ellipse fill="url(#spot-pool)" class="schermo" data-pool />
        <g class="pulviscolo" clip-path="url(#beam-clip)" data-motes></g>

        <!-- the curtain: the left half, the gloved hand that comes out of the gap, the right half on top -->
        <g data-curtain-left></g>
        <g data-hand>
          <g data-finger><path class="guanto" d="M4 -17L-21.75 -17A4.25 4.25 0 0 0 -21.75 -8.5L4 -8.5Z" /><path class="guanto-piega" d="M-10.6 -15Q-11.8 -12.75 -10.6 -10.5" /></g>
          <g data-finger><path class="guanto" d="M4 -8.5L-24.75 -8.5A4.25 4.25 0 0 0 -24.75 0L4 0Z" /><path class="guanto-piega" d="M-12 -6.5Q-13.2 -4.25 -12 -2" /></g>
          <g data-finger><path class="guanto" d="M4 0L-22.75 0A4.25 4.25 0 0 0 -22.75 8.5L4 8.5Z" /><path class="guanto-piega" d="M-11 2Q-12.2 4.25 -11 6.5" /></g>
          <g data-finger><path class="guanto" d="M4 8.5L-17.75 8.5A4.25 4.25 0 0 0 -17.75 17L4 17Z" /><path class="guanto-piega" d="M-8.4 10.5Q-9.6 12.75 -8.4 15" /></g>
        </g>
        <g data-curtain-right></g>
        <g data-floor-fx></g>
        <g data-pelmet></g>
        <rect class="buio" data-house-dim />
        <rect fill="url(#wash)" class="schermo" data-wash />
        <path fill="url(#beam)" class="schermo" data-beam />
      </g>

      <!-- the gilded frame, its shell, and the spotlight hanging from it -->
      <g data-frame></g>
      <g data-lamp>
        <path class="staffa-bordo" d="M-27 6L-27 -16L27 -16L27 6" />
        <path class="staffa" d="M-27 6L-27 -16L27 -16L27 6" />
        <g data-barrel>
          <path class="lampada" d="M-15 -20L-11 -28L11 -28L15 -20Z" />
          <rect class="lampada" x="-21" y="-21" width="42" height="69" rx="6" />
          <path class="alette" d="M-21 -11L21 -11M-21 -4L21 -4M-21 3L21 3" />
          <path class="lampada-lucido" d="M-13.5 -15L-13.5 41" />
          <rect class="ghiera" x="-24.5" y="46" width="49" height="12" rx="3" />
          <ellipse class="lente" cx="0" cy="60" rx="18" ry="5" />
          <ellipse class="lente-accesa" cx="0" cy="60" rx="18" ry="5" data-lens-on />
        </g>
        <circle class="pomello" cx="-27" cy="0" r="5" />
        <circle class="pomello" cx="27" cy="0" r="5" />
      </g>

      <!-- the apron and the footlights -->
      <g data-apron></g>
      <g data-bulbs></g>

      <!-- confetti and roses, over everything -->
      <g data-fly></g>
    </svg>
    <p class="nota">Click or tap to see it again</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.

46 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 theatre-curtain logo” from Animorio and fit it into my site

What it does

A little theatre as big as the window: a gilded frame with a shell on top, a pelmet of velvet swags with gold fringe and tassels, and a pleated red curtain, closed. Below, on the edge of the stage, a row of footlights, off. Someone walks behind the left half: the velvet bulges, catches the light and follows the steps to the middle. The gap trembles and a hand in a white glove comes through, drums its fingers twice, grips the edge and vanishes. The curtain opens: the folds gather towards the sides like real cloth, the hem trails behind and then swings past, the tassels sway, dust rises from the hem and some drifts down from above. The stage is dark. The spotlight hanging from the frame comes on with a flicker, turns on its yoke and searches: the beam sweeps the back wall and the boards with its circle, passes the logo, comes back and finds it, and the circle takes the shape of the made-up brand, Bravessa, set in an ivory Bodoni. The light opens up, the hall comes back into view and the footlights come on one by one, their filaments glowing. The logo takes a bow: a breath in, a bend forward starting from the letters in the middle, a little darker as it turns its face away from the light, and back up with a spring. Confetti flutter down from above and settle on the boards, three roses fly in from the audience, spin in the air and land lying down with a little hop. Then the logo stays in the light: the spotlight sways gently, the velvet breathes, dust floats in the beam, a confetto drifts down now and then. After a few seconds the lights go down, the curtain closes and the show starts again, with a different path for the light and a different shower of confetti. A click restarts it from the beginning. A picture can take the place of the word: the light, the bow and the roses work there too.

How it works

A theatre to size

The stage is an SVG whose viewBox is as big as the window, so one unit is one pixel. The frame is worked out from the window (on a tall screen the opening becomes upright), then the letters are measured on a canvas in the same typeface (measureText, actualBoundingBoxAscent for the true height) and the logo takes the size that fits on the boards without touching the pelmet. Everything else, the circle of light, the roses, the confetti, the bulbs, comes from these two measures.

A curtain drawn again

Each half of the curtain is a row of pleats: strips with a horizontal gradient (dark in the hollow, shiny on the crest) and the dark outline, plus a second strip with the vertical shade. The edges of the pleats are shared, so a gap never opens, and they are worked out again every frame from one state object: how open it is, how far the hem trails, the breathing of the velvet and the bulge of someone pushing from behind. As it opens, the place of each pleat follows a power that grows with the opening: the pleats near the side squeeze up more, like gathered cloth.

Fringe and tassels

The hem is a row of arcs, one per pleat. The braid is a gold stroke along the arcs; the threads of the fringe are many vertical segments starting from the arc, worked out again with the pleats, so they stay straight even when the pleats are tight. On the swags of the pelmet, which do not move, the threads are instead a wide dashed stroke along the curve. The tassels are a single drawing in the defs, copied where needed: each one turns around the point where its cord hangs, worked out with getBBox.

The spotlight

The light is an object with the centre and the radii of the circle and how bright it is. The dark on the stage is a rectangle with a mask: inside it there is an ellipse with a radial gradient, black in the middle and white at the edge, the soft hole of the light. The beam starts from both sides of the lens and reaches the two points where it touches the ellipse (where the tangent is parallel to the direction of the lamp), going round the far side; the same path is the clipPath of the dust, which only shows in the light. The lamp turns on its yoke towards the circle with a rotate worked out from atan2.

The bow and the applause

Each letter bends from its foot (transformOrigin at the bottom) with a stagger that starts from the middle: a breath, down, a pause and up with elastic.out. While it is bent the logo goes under a feComponentTransfer filter whose slope is lowered, so it darkens a little without turning see-through. The confetti are rectangles that fall spinning and flutter with scaleX back and forth; the roses are a drawing in the defs, thrown from below in an arc and laid down with a little hop.

Direction and your logo

The whole story is one timeline, with timeScale for the speed; its onUpdate draws the curtain, the light, the hand and the dust again once per frame, after every tween has moved. At the end the lights go down, the curtain closes and the scene is rebuilt from the «arrive» label, with a new path for the light and new confetti. If IMAGE holds an address, the logo becomes that picture, a single piece that bows all at once. In the Playground, next to the field, there is a button to upload a file from your computer, which goes into the code as a data: address.

Values to change

NameFileDefaultWhat it changes
NAMEscript.js'Bravessa'The logo as a word: every letter bows a moment after the one in the middle.
IMAGEscript.js''The logo as a picture: the address of a file, or upload it from your computer. If there is one, it takes the place of the word.
SPOTscript.js1How wide the spotlight’s circle is around the logo, and so the beam: 0.7 tight, 1.6 generous.
CONFETTIscript.js60How many confetti fall at the bow.
BOWscript.js1How deep the logo bows: 0 stands still, 1.6 is a deep bow.
ROSESscript.js3How many roses the audience throws on the stage.
SPEEDscript.js1The speed of the whole show: 2 is twice as fast, 0.5 half as fast.
RESTscript.js5How many seconds the logo stays in the light before the curtain closes.
LOOPscript.jstrueWhether the curtain closes and the show starts again. With false the logo stays in the light for good, with the spotlight swaying.

Try them in the Playground

When to use it

To present a logo with a little ceremony: a preview for a client, the opening of the site of a theatre, a festival, a company or a venue, a product launch, a presentation video, a social post. It works with a written wordmark and with a picture.

On phones

The same show, with the sizes adapted: on a tall screen the opening becomes upright, there are fewer, wider pleats, the logo stands lower on the boards and the beam is longer. A tap restarts it.

With reduced motion

Nothing moves: the closed curtain fades away leaving the dark stage, then the light appears on the logo, then the footlights fade on and the roses and confetti appear, already lying on the boards. If the show starts again, the curtain fades back in.

Pitfalls

  • With many tweens on the same state object, drawing the curtain in each one’s onUpdate draws it with old values halfway through a frame (and several times). It is drawn only once, in the timeline’s onUpdate, which comes after all its children: so even a seek to any time shows the right frame.
  • Fringe threads made as a dashed stroke along the hem twisted into a zigzag when the pleats squeeze up (the dashes follow the curve, which turns almost vertical): on the curtain they are vertical segments worked out again every frame.
  • A tassel hung from the corner of the hem dangled below the edge of the stage and ended up behind the bulbs: now it hangs from the inner edge, a little below the middle.
  • Lowering the logo’s opacity to darken it in the bow made it see-through over the boards (with a picture the floor showed through): a feComponentTransfer filter is used instead, set only during the bow.
  • Roses and confetti sit above everything: in the reduced-motion version they stayed visible over the curtain fading back in. They fade out with it.
  • The beam over the closing curtain looked like a pale stain on the velvet: the lights go down while the curtain closes, not after.
  • The lamp is visible even with the curtain closed: if the circle started from a random point at every round the lamp would jump. The starting point is fixed and, with the light off, the lamp slowly goes back to it.

Libraries

GSAP 3.15.0, Bodoni Moda (font variabile) 5.3.0.

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

Testing

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