047

Plucked Strings

£10 or the whole Vault, £99

Interactive elastic strings that bend around your cursor and twang back with damped oscillation — with an opt-in sound toggle that voices every pluck as a synthesized, guitar-tuned string note.

advanced
6 more details
pointer-effectsphysicssvg-animationelasticmicro-interactionweb-audio

This demo reads better at your own screen size than in the frame below:

Updated

About this effect

A field of taut SVG strings stretched edge to edge across the section, each one a live elastic instrument. Drag across a string and it bends around your cursor; let go, or whip straight through, and it snaps back with a damped oscillation that rings for about a second before settling dead straight. Deflection drives stroke weight and a tension colour that fades in over the resting hairline, and a hard release passes a sympathetic shimmer to neighbouring strings so the whole field reacts like one instrument.

Read the full effect overview

The demo composes it as a music venue's opening statement, with the strings crossing the whole frame behind the copy so a sweep anywhere plucks something. Colours are two CSS custom properties on the container, so the strings take your accent without a script change, and an optional wake setting starts a couple of strings ringing the moment the section appears.

Flip the sound toggle and every pluck is voiced: a synthesized Karplus-Strong string note per pluck (Web Audio, zero external audio files), tuned to a standard guitar's open strings (E A D G B E) so a whip across the field strums a real open-string chord. Built on GSAP core alone with no plugins, costing zero work per frame at rest.

Plucked Strings - GSAP animation effect preview

What's included

10 items
  • Pointer-tracking elastic bend rendered as a single SVG quadratic bezier per string
  • Damped-sine release: strings overshoot, ring, and converge to straight in about 1.2 seconds
  • Deflection-driven tension colour and stroke weight: a chalk hairline at rest, your accent under load, no blur filters
  • Sympathetic vibration: hard releases excite neighbouring strings at 20% amplitude with a phase offset
  • Whip detection: a fast vertical swipe snaps every string it crosses into a cascading chord
  • Opt-in pluck audio: a sound toggle voices every pluck with Karplus-Strong synthesis (Web Audio, no samples), tuned to a standard guitar's open strings (E A D G B E) with strength driving volume, brightness, and stereo pan; a pentatonic tuning option covers non-guitar fields
  • Ambient idle auto-pluck keeps the field alive before anyone interacts, plus a wake option that opens with strings already ringing
  • Colours come from CSS custom properties on the container, with a data attribute override for one-off fields
  • Touch: a tap plucks the nearest string and vertical swipes still scroll the page (touch-action: pan-y)
  • Keyboard playable: arrow keys walk and pluck the strings, Enter plucks hard

Perfect for

5 use cases
  • Hero sections for music, audio, and creative studio sites that want a playable centrepiece
  • Portfolio and agency landing pages with an interactive signature moment above the fold
  • Product pages for audio gear, plugins, and instruments where the metaphor sells itself
  • Event and festival microsites that need the page itself to feel performative
  • 404 or waiting pages that reward idle cursors with something tactile

How it works

2 sections

Each string is an SVG path whose quadratic bezier control point tracks the pointer, with deflection clamped to a configurable maximum sag. On release the string enters a free damped-sine oscillation, controlY = amplitude x sin(wt + phase) x e^(-kt), stepped on gsap.ticker until the envelope falls below a rest threshold. Active strings update their path with one attribute write per frame while resting strings do zero work, and the ticker callback removes itself entirely once the field is still. Each string is two strokes on one path: a resting hairline and an accent tension stroke whose opacity and width follow the deflection, and releases past half the maximum sag hand a phase-offset fraction of their amplitude to the neighbouring strings.

With sound enabled, every ring start also plays a Karplus-Strong pluck: a noise burst circulated through a one-sample averaging filter, rendered once per pitch into an AudioBuffer and cached. Strings are pitched as a standard guitar's open strings from low E2 (or a minor pentatonic via an attribute), pluck strength scales both the note's gain and a lowpass cutoff, stereo pan follows the pluck position, and the AudioContext is only ever created inside the toggle click, which keeps it inert until the visitor opts in and satisfies browser autoplay policies.

Difficulty Advanced
Includes HTML + JS + CSS source, documentation, AI setup prompt, lifetime updates

Lighthouse, as measured

Google Lighthouse on this effect's demo, from the latest scan. A measurement of the demo as shipped, not a promise for your page.

Accessibility
100
Best practices
100

No performance score, on purpose. That figure depends on how you deploy: your server's compression and caching, your CDN, the connection and the device doing the test, none of which the code controls. The same page can score very differently on two consecutive runs, so measure it where it will live.

Paid effect

Purchase to unlock the code.

Buying Plucked Strings opens the HTML, CSS and JavaScript source, the full documentation, an AI setup prompt for your editor, and every update we ship to it. Standard license: unlimited personal and commercial projects. Every paid product is tested for desktop and mobile layouts, reduced-motion handling, animation cleanup and keyboard controls wherever there is something to operate.

£10 Standard license, unlimited projects

Browse free effects

Or the whole library: the Vault, £99, one payment.

Documentation

Quick Start

1. Add to your HTML <head>:

Code snippet omitted: it ships with the download.

2. Add the string field to your <body>:

Code snippet omitted: it ships with the download.

3. Add before the closing </body> tag:

Code snippet omitted: it ships with the download.

The script finds every [data-strings] container, builds an SVG of evenly spaced horizontal strings sized to the container, and wires up pointer, touch, and keyboard plucking. No other markup is required.

4. Optional — add a sound toggle (anywhere on the page) to voice each pluck with a synthesized string note:

Code snippet omitted: it ships with the download.

See the Sound section below. Omit the button and the effect is simply silent.

Using It With Your Own Design

What the effect needs from your markup: one element carrying the data-strings attribute, plus (only if you want sound) a button carrying data-strings-sound-toggle. Those attributes are the entire structural contract; the script never reads any class name, so the demo's toggle styling (.showcase-sound) is yours to replace. The container must have a real height (the strings are laid out as a fraction of it) and position: relative, because the generated SVG is absolutely positioned to fill it. Give the container tabindex="0" if you want the keyboard plucking to work.

Colours are CSS. The script reads two custom properties off the container once at init: --strings-rest (the hairline every string shows at rest) and --strings-hot (the colour a string takes under tension). The demo sets them on .strings-field to a translucent chalk and the page accent. Change either there and the strings follow; data-strings-color overrides the tension colour for one field without touching CSS.

What is only the demo's styling: the prompt line and the bottom bar (.venue__bar) are the page the demo is pretending to be. Delete or replace them freely; the strings render over any content and any background you supply, and the demo's .venue grid padding is layout for that copy, not something the effect needs.

CSS the effect depends on:

  • .ps-svg (the generated SVG) must stay position: absolute; inset: 0; pointer-events: none; so the container, not the SVG, receives pointer events. Keep that rule when porting the stylesheet.
  • touch-action: pan-y on the container. A vertical swipe that lands on the field scrolls the page as normal, so the section never traps a visitor mid-scroll; a tap plucks the nearest string and a sideways strum bends the strings it passes. Set touch-action: none instead only if the field fills a page that has nowhere to scroll and you want vertical whips on touch as well. The demo restores touch-action: auto under reduced motion, where the strings are inert.
  • overflow: clip (or hidden) on the container if you do not want a fully bent string drawing past its edges.
  • Content inside the container that should not take the pointer (the demo's copy) gets pointer-events: none, otherwise a sweep over your headline stops plucking. Anything that must stay clickable (the demo's sound toggle) gets pointer-events: auto and a z-index above the SVG.
  • There are no pre-hidden reveal states: with JavaScript disabled the container simply renders without strings, and everything inside it stays visible.

Options

All options are data attributes on the [data-strings] container.

Attribute Values Default Description
data-strings marker required Identifies a string field container
data-strings-count integer 6 Number of strings, spread evenly through the middle band of the container
data-strings-color any CSS color --strings-hot Tension colour for every string in this field, overriding the CSS custom property. The resting hairline always comes from --strings-rest
data-strings-sag pixels 110 Maximum deflection. The pointer bends a string this far before it slips off and snaps back; keep it under half the gap to the container edge or a bent string will clip
data-strings-damping number 3.4 Exponential decay rate of the ring. Higher dies faster; at 3.4 a full pluck settles in roughly 1.2 seconds
data-strings-idle true, false true Ambient auto-pluck: a random string gets a gentle pluck every 3 to 4 seconds of pointer inactivity
data-strings-wake integer 0 Strings set ringing the moment the field initialises, starting from their peak so the first frame already shows a bent string. The demo uses 2; 0 opens at rest
data-strings-volume 0 to 1 0.5 Master gain of the pluck sound (read from the first [data-strings] container; the engine is shared)
data-strings-tuning guitar, pentatonic guitar What the strings play. guitar is a standard-tuned guitar's open strings (E2 A2 D3 G3 B3 E4, low E at the bottom) — pair it with data-strings-count="6" for the real thing. pentatonic is a minor pentatonic over E3 for an ambient field of any string count

The sound toggle is its own attribute, data-strings-sound-toggle, on a <button> anywhere in the page rather than on the container — see Sound below.

How the Interaction Feels

  • Slow drag: the string under the cursor bends and follows, clamped to the sag limit, with the bend centred on the pointer.
  • Release or slip: past the sag limit the string slips off the cursor and rings down from wherever it was, a damped sine, never a linear snap.
  • Whip: a fast vertical swipe crosses several strings in one move; each snaps immediately in the direction of travel, and the field rings as a chord before settling.
  • Hard release: anything past about half the sag limit passes a 20% amplitude, phase-offset shimmer to the two neighbouring strings.
  • Tension colour: stroke width and the accent stroke's opacity scale with the current deflection, so a hard pluck flashes to full colour and fades back to the resting hairline as the ring decays.
  • Touch: a tap plucks the nearest string at the point you touched, and a sideways strum bends what it passes. Vertical swipes scroll the page.

Sound

With the toggle on, every pluck also plays a synthesized string note — Karplus-Strong synthesis through the Web Audio API, generated at runtime with no audio files to load.

  • Opt-in by design. Sound is off until the visitor presses a [data-strings-sound-toggle] button. The AudioContext is created inside that click, which is exactly what browser autoplay policies require, so there is never a blocked-audio warning. Toggling off suspends the context (no idle battery cost); toggling back on resumes it.
  • Tuning. By default the strings are a standard-tuned guitar's open strings — E2 A2 D3 G3 B3 E4, low E at the bottom — so a six-string field is literally a guitar and a whip across it strums the open strings. Fields with more strings repeat the tuning an octave up. data-strings-tuning="pentatonic" switches to a minor pentatonic over E3, which suits ambient fields of arbitrary string counts (every combination of notes is consonant).
  • Expression. Pluck strength drives the note's volume and its brightness (a lowpass opens with harder plucks), stereo pan follows where along the string you plucked, and a few cents of random detune keep repeated notes from sounding sampled. Sympathetic neighbour shimmers play quietly; the keyboard and idle auto-pluck are voiced like any other pluck. Wake plucks fire before the toggle can have been pressed, so they are always silent.
  • The toggle button. Any <button> with data-strings-sound-toggle works, anywhere in the page; every such button controls the one shared engine and stays in sync. The script updates aria-pressed, toggles an is-on class for your styling, and rewrites the text of an optional inner [data-sound-label] element to "Sound on"/"Sound off". A field with no toggle button on the page never creates any audio object at all.
  • Headroom. Notes route through a shared compressor, so a nine-string whip chord does not clip.
  • iPhone silent switch. iOS mutes plain Web Audio whenever the hardware ring/silent switch is on silent, which most phones are. The engine handles this two ways: on iOS 17+ it requests a media-playback audio session (navigator.audioSession.type = 'playback'), and on older versions it loops a 50ms silent <audio> element while sound is on, which holds the session in the playback category — the same one a video player uses. Both mean the plucks stay audible with the phone on silent, and the silent loop starts inside the toggle tap so it is never blocked by autoplay rules. The engine also resumes the context from iOS's 'interrupted' state when the tab returns to the foreground.

Accessibility

  • Reduced motion: under prefers-reduced-motion: reduce the strings render as static straight lines. No oscillation, no auto-pluck, no wake, and the pointer does nothing; all text in the container stays fully visible. The sound engine is never wired up (nothing can be plucked), and the demo hides its toggle button.
  • Sound: strictly opt-in via an explicit button press, never autoplayed, and the toggle reflects its state through aria-pressed. Browsers without Web Audio simply leave the toggle in the off state.
  • Keyboard: with the container focused, ArrowUp and ArrowDown pluck each string in turn and Enter (or Space) plucks the current string hard. :focus-visible shows a visible outline on the field.
  • No JavaScript: the container renders without strings; nothing is hidden behind a script.
  • Screen readers: the generated SVG is aria-hidden="true". Give the container a short aria-label describing the keyboard interaction, as in Quick Start.

Performance Notes

  • Strings at rest cost zero work per frame. The gsap.ticker callback is only attached while at least one string is bending or ringing, and removes itself when the field is still.
  • Each active string writes one path d (shared by the hairline and its tension twin) plus two stroke attributes per frame; there is no layout work in the loop.
  • No SVG filters: the tension colour is a second plain stroke, so a bent string costs the same to paint as a straight one.
  • On resize the field re-measures and redraws at rest after a 150ms debounce.

Dependencies

Required:

  • GSAP 3.12+ (core only, no plugins)

Worked examples, the events and programmatic API, and the class reference ship with the download, alongside the full source.