Source Code

<div class="cf-stage">
  <div class="cf-scene">
    <div class="cf-coin" id="cfCoin">
      <div class="cf-side cf-heads">H</div>
      <div class="cf-side cf-tails">T</div>
    </div>
  </div>
  <button type="button" class="cf-btn" id="cfBtn">Flip coin</button>
  <p class="cf-result" id="cfResult">Heads or tails?</p>
  <p class="cf-tally" id="cfTally"></p>
</div>

Coin Flip — CSS 3D Coin Flip Animation (JS)

Coin Flip · Animations · Plain HTML, CSS & JS · Live preview

What's included

Features

Two-sided 3D coin
Two faces in a preserve-3d scene with perspective for a real tumble.
backface-visibility flip
Hidden backfaces show exactly one side at a time as the coin rotates.
Parity-based landing
Heads at even, tails at odd 180° multiples, so the coin rests on the reported side.
Honest randomness
Math.random() picks the result before the spin, so the visual always matches.
Forward-spinning
An accumulating turn count keeps the coin rotating the same way between flips.
Running tally
A heads/tails counter tracks the session and shows the 50/50 split holding.
Flip guard
The button disables during the tumble so flips can't overlap.
No images, no library
Pure HTML/CSS/JS — themeable and dependency-free.

About this UI Snippet

Coin Flip — A 3D CSS Coin That Tumbles to Heads or Tails

Screenshot of the Coin Flip snippet rendered live

Flipping a coin is the simplest possible randomiser, and a 3D coin that actually tumbles makes it satisfying. This snippet builds a two-sided coin that spins and lands on heads or tails, with a running tally, in pure HTML, CSS, and a few lines of vanilla JavaScript — no images, no library.

Two faces with backface-visibility

The coin is two circular faces stacked on the same spot inside a preserve-3d scene. The tails face is pre-rotated 180° so it points the opposite way, and both faces use backface-visibility: hidden — the key property that makes a flippable two-sided element work, because it hides whichever face is currently turned away from the viewer. Without it you'd see a mirror-image bleed-through; with it, exactly one side shows at a time as the coin rotates. The scene's perspective gives the spin real depth.

Landing on the right side via rotation parity

Heads shows when the coin's rotateY is at an even multiple of 180° (0°, 360°, …) and tails at an odd multiple (180°, 540°, …). A flip picks the result first with Math.random(), then computes a final angle that has the correct parity for that result plus several extra full spins so the coin visibly tumbles before settling. Because the landing angle is derived from the chosen outcome, the coin always rests on the side it reported — the randomness is honest, decided before the animation, never faked afterward. The Math.ceil((turns * 180) / 360) * 360 step is the part that keeps this correct flip after flip: it rounds the accumulated half-turns up to the next full 360°, discarding any leftover odd half-turn from the previous landing, before the new parity offset (0 or 180) is added back on top — without it, the parity from one flip could bleed into the next and land the coin on the wrong face.

Always spinning forward

An accumulating turns counter ensures each flip adds rotation on top of the last, so the coin keeps spinning in the same direction rather than snapping back to zero between flips. This continuity is a small detail that makes repeated flips feel like one continuous physical object rather than a resetting widget.

A running tally

Each result increments a heads/tails count, shown beneath the coin. Over many flips this both adds a sense of a session and quietly demonstrates that the 50/50 split holds — a nice touch for anything that uses the coin to make repeated decisions. The button disables during the ~1.1s tumble so flips can't overlap and desync the tally from the resting face.

Drop-in and adaptable

The coin is self-contained and easy to theme — swap the H/T glyphs for icons or images, change the metals, or resize it. Use it as a decision-maker, a game mechanic, or a playful "let fate decide" control, and as a clear reference for two-sided CSS 3D flips with backface-visibility.

Build with AI

Build, Understand, Optimize, and Extend It With AI

You don't have to work out the rotation parity math in your head. Paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to walk through exactly how the Math.ceil rounding step keeps heads landing on an even multiple of 180 degrees and tails on an odd one, flip after flip. The same assistant can help you optimize it — for example checking whether the accumulating turns counter could grow unbounded over a very long session and whether it should wrap periodically without breaking the parity check. It's also useful for extending the coin: ask it to add a weighted-odds mode for a loaded coin, a session history list instead of just a running tally, or a sound effect timed to the landing moment via the existing setTimeout callback. Treat the code less like a finished artifact and more like a starting point for a conversation.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a 3D coin-flip animation in plain HTML, CSS, and JavaScript using only CSS 3D transforms (perspective, transform-style: preserve-3d, backface-visibility) — no images, no canvas, no library.

Requirements:
- Two circular faces (heads and tails) stacked in the same position inside a perspective scene, with the tails face pre-rotated 180 degrees on the Y axis and both faces set to backface-visibility: hidden so only the face currently pointing at the viewer is ever visible.
- On flip, decide the outcome first with Math.random() before computing any animation values — the animation must never be allowed to land on a face that contradicts the already-chosen result.
- Compute the final rotateY angle so that heads always rests at an even multiple of 180 degrees and tails at an odd multiple, plus several extra half-turns of flourish so the coin visibly tumbles rather than snapping straight to its resting angle.
- Maintain a running total of accumulated half-turns across flips (do not reset it to zero between flips) so the coin always keeps spinning forward in the same direction, while still correctly rounding that accumulated value up to the next full 360 degrees before adding the new landing offset, so parity from a previous flip can never bleed into the next one.
- Disable the flip button for the duration of the CSS transition so a second flip cannot be triggered mid-tumble and desync the displayed result from the coin's resting face.
- After each flip settles, update a visible running tally of heads versus tails counts.

Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSA 3D coin renders on a dark stage with a Flip button.
  2. 2
    Flip itClick Flip (or the coin) and it tumbles for about a second, landing on heads or tails.
  3. 3
    Read the resultThe text shows the outcome, which always matches the resting face.
  4. 4
    Watch the tallyEach flip updates the running heads/tails count beneath the coin.
  5. 5
    Restyle itSwap the H/T glyphs for icons, change the coin colours, or resize it.
  6. 6
    Hook into your appRead the chosen side in flip() to drive a decision, game, or picker.

Real-world uses

Common Use Cases

Decision makers
Settle a yes/no or A/B choice — pair with a dice roller for more options.
Game mechanics
Drive a coin-toss in a game UI alongside a spin wheel.
Sports and matchups
Pick who goes first with a visible, fair toss.
Gamified prompts
Add chance to onboarding or quizzes next to a confetti button.
Party and icebreaker apps
A playful "let fate decide" control.
Learning CSS 3D flips
A reference for backface-visibility and 3D rotation — compare with a 3D flip card.
Related: Cursor Spotlight Reveal
See the Cursor Spotlight Reveal for a related animations pattern worth pairing with this one.

Got questions?

Frequently Asked Questions

Heads corresponds to an even multiple of 180° of rotateY and tails to an odd one. The flip picks the result with Math.random() first, then computes a final angle with the matching parity plus several full spins for flourish. Because the resting angle is derived from the chosen outcome, the coin always settles on the side it announced — the result is decided before the animation, not after.

It hides the side of each face that's turned away from the viewer. The coin is two faces on the same spot, with tails pre-rotated 180°. As the coin spins, backface-visibility:hidden ensures only the face pointing toward you is visible, so you never see the reverse bleeding through. It's the essential property for any two-sided 3D flip element.

A turns counter accumulates across flips, so each new flip's target angle is larger than the last. That keeps the rotation always increasing — the coin spins forward continuously instead of snapping back toward zero between flips, which would look like a glitch. The parity of the final angle still encodes heads or tails correctly.

Yes — Math.random() < 0.5 gives each side an equal chance on every independent flip. The running tally beneath the coin lets you watch the split converge toward 50/50 over many flips. There's no weighting or memory between flips, so it behaves like a fair coin.

In React, hold the rotation, result, and counts in state and set the coin's transform in the click handler with a timeout to settle; in Vue, bind :style with refs; in Angular, bind [style.transform] with component properties. The parity math and randomness are framework-agnostic — only the state and the transform binding move into the framework.