Yasin Hassim
All posts
· 3 min read

flower-for-sharana: A Bud That Blooms on Tap

A tiny, no-build interactive page I built as a personal gift — a CSS/canvas flower that unfurls into bloom and reveals a note underneath.

DevelopmentPersonal Projects

Why I Built This

Not every project needs to be a big rebuild with a database and an OAuth flow. Sometimes you just want to send someone a link that makes them smile. That’s what flower-for-sharana is — a single page with a closed flower bud sitting in the dark. You tap it, it blooms, and a personal note fades in underneath.

No app, no sign-in, no dashboard. Just a bud, a bloom, and a message.

What It Does

Land on the page and there’s a greeting (“Asalamualaikum”), a dark starry background, and a closed flower with a small hint underneath it — “sentuh bunga ni” (“tap the flower”). Tap it and:

  • The bud’s leaves and petals unfurl outward with a springy, staggered animation
  • A burst of gold and pink pollen particles scatters from the center
  • The hint fades out and, a beat later, a personal note fades in below the flower
  • Tap again and it closes back up, ready for another bloom
A closed golden bud on a green stem against a dark starry background, with the hint sentuh bunga ni
The bud, waiting
Petals springing open with gold and pink pollen particles bursting from the centre
A fraction of a second after the tap
The fully bloomed pink flower with a note underneath
Full bloom and the note (a demo note here, not the real one)

While it’s blooming, petals occasionally drift down from the top of the screen and fade out as they fall — a small ambient touch so the page doesn’t feel static once the flower’s open.

The Tech

It’s deliberately boring in the best way: plain HTML, CSS, and vanilla JS, no framework, no build step, no dependencies. python3 -m http.server and you’re previewing it.

The bloom is pure CSS transitions, not JS animation. Toggling a single .bloomed class on the flower element is enough — petals, leaves, and the center all have their own transition rules with staggered delays (petals use a cubic-bezier(0.34, 1.56, 0.64, 1) easing for that overshoot/springiness), so the whole unfurl is one class toggle away and the browser handles the actual animation work.

Petals are generated, not hand-placed. A buildPetals() function creates each petal div and sets a --angle CSS custom property per petal ((360 / count) * i), so an 8-petal outer ring and a 6-petal inner ring are both just loops writing angles into custom properties that the CSS reads.

The background — stars, pollen burst, falling petals — is a <canvas> running its own requestAnimationFrame loop, separate from the DOM/CSS bloom. Stars twinkle via a sine wave per star; the pollen burst on tap spawns ~34 particles with random velocity and lets gravity and alpha-fade retire them; falling petals spawn on a timer while the flower is bloomed and get culled once they’re off-screen or past their lifespan.

prefers-reduced-motion is respected throughout — particle counts drop, transition durations shrink to 200ms, and the whole thing degrades gracefully instead of just ignoring the setting.

Tap bloom() DOM layer canvas layer toggle .bloomed on the flower one class, no JS animation code --angle per petal = 360 / count × i CSS transitions do the work 8 outer + 6 inner petals, staggered cubic-bezier(.34, 1.56, .64, 1) <canvas> with its own requestAnimationFrame loop ✦ stars twinkle on a sine wave ✺ ~34 pollen particles, gravity + fade ❀ petals drift down while bloomed, culled off-screen
Two independent layers: CSS owns the flower, a canvas loop owns everything floating around it.

A couple of small, deliberate touches from later commits: touch-action: manipulation on the flower so mobile taps register faster (no 300ms delay waiting to see if it’s a double-tap), and Open Graph meta tags so the link itself previews nicely when shared instead of showing a bare URL.

The Personalization Bit

The whole point of the project is the message, so that’s the one thing pulled to the very top of script.js as a NOTE object — to, message (with \n for line breaks), and from. Edit three strings, no need to touch markup or CSS, and the page is customized. I also translated the tap hints to Malay (“sentuh bunga ni” / “sentuh untuk mekar lagi”) since that’s the language the note itself is in.

Where It Stands

It’s finished and deployed — static site, no framework preset needed, straight onto Vercel. There’s nothing left to build here; it did exactly the one job it was meant to do.

Keep reading