Musician websites have collapsed into the same wireframe: artist photo, a row of streaming-platform links, a tour dates list, a newsletter form. The album cover is somewhere. The music is one click away — on a different site. The artist's actual aesthetic shows up nowhere on the page.
Echo is the sixth template in the marketplace I'm shipping this month. The brief: a musician portfolio where the album lives on the page, not behind a "listen on Spotify" badge.
Stack
Static HTML — single page (ECHO.html / index.html). React 18 UMD. Babel in the browser. Tailwind via CDN. Four fonts loaded from Google Fonts:
- Anton for the massive display headlines (RESONANCE, WHO IS ECHO)
- Condiment script for the "generative" accent
- Manrope for body text
- Newsreader serif for editorial paragraphs
No motion library. Every animation is CSS keyframes, a 320ms transition, or hand-rolled requestAnimationFrame (the waveform scrubber and ArcSlider tilt).
The hero
The hero is a 10-second ink-in-water Gemini Veo loop, transcoded down to 1280-wide H.264 at CRF 26 (12 MB raw → 1.4 MB shipped). The Veo sparkle watermark in the bottom-right corner gets blurred by ffmpeg's delogo filter at x=1700 y=880 w=120 h=110 — same pass I use across every Veo asset in the marketplace.
Layered on top:
- ECHO logo + small script "new album" tag
- Anton-weight headline "RESONANCE" with a duplicate offset behind it (the ghost echo)
- "06 · 06 · 2026" release date
- A pink "generative" script accent rising at the top of the headline block
- A LISTEN NOW pill with a play icon
- "MOVE TO SCRUB" hint pointing at the waveform below the fold
- "SCROLL" cue, "ECHO — 2026", "A FILM BY ECHO" footer band
The "MOVE TO SCRUB" hint isn't decorative — the waveform under the fold is genuinely scrubbable. Cursor moves left-right across it, the audio playhead follows.
The 3D arc track slider
The flagship interaction is the ArcSlider component. Nine track cards (TRACKS array in app.jsx) sit on a curved arc — center card upright, side cards tilted in 3D toward the camera. Each card carries a track number, title, BPM, key, duration, and a tinted abstract cover from the COVERS array.
Cards rotate through the arc on click or drag. The center card is the "now playing" — the title appears huge above the waveform and the playhead resets.
The pastel tint is per-card (PASTELS array) and overlays the cover at mix-blend-mode: multiply. Each card is unmistakably part of the same album but unmistakably its own track.
Spotlight: cursor reveals the artist
The About section uses the Spotlight component — a small canvas overlay that punches a circular reveal hole at the cursor position. Base image: a wide artist-in-shadow studio shot. Reveal image: the same artist with a direct gaze, lit. As the visitor moves across the frame, the lit portrait fades through the shadow.
It costs nothing — one <canvas> and a requestAnimationFrame that compositingly draws the base, then globalCompositeOperation = 'destination-in' plus a radial gradient, then the reveal. Twenty-something lines.
Tracks, waveforms, live dates
TRACKS: 9 tracks with title, BPM, key, duration. Each gets a procedurally seeded SVG waveform (Waveformcomponent) — same seed = same waveform across reloads.LIVE_DATES: 6 cities with venue, date, country, status (On sale / Few left / Sold out). Each row links to a TICKETS button.- EchoMark: a 28px concentric circle wordmark glyph used in the nav and as a section divider.
What I cut
No "Sign up for the newsletter" form. No "Follow on Instagram" widget. No "About the producer" sub-page. One page. One album. One artist.
The buyer who wants those things adds them. The buyer who doesn't ships the template as-is and the visitor's first impression is the music, not the metadata.
What I would change
The Anton headline in the hero is fixed at clamp(...) and reads a touch tight on iPhone SE (320px). A future pass would drop one font-size step at the smallest breakpoint. Acceptable in v1.
Live
echo-template-06.netlify.app — move the cursor across the artist portrait in the About section.
