The base recipe handles a quiet two-phase reveal: stroke draws, then the fill fades in by opacity. Production "saved/liked" affordances (App Store, Threads, Twitter) stage the moment with FOUR layers in one cycle: (1) the outline traces itself with stroke-dashoffset, (2) a small bright spark rides the pen tip via offset-path so the eye follows the line being drawn, (3) a wider after-glow stroke trails behind the outline for ink-trail feel, and (4) once the trace completes, a fill heart blooms from the center with a springy ease (cubic-bezier(.3, 1.5, .5, 1)) that overshoots past 1 and settles. After the bloom lands, the heart breathes via a drop-shadow filter pulse. All four layers stay pure CSS — offset-path replaces JS path sampling.
Paste this as a complete alternative to the base recipe — different SVG structure (single shared <path> referenced via <use>, plus a <circle> spark with offset-path) and a richer four-layer animation.
1<figure class="heart-reveal" aria-labelledby="heart-reveal-caption">2 <svg class="heart-reveal__svg" viewBox="0 0 100 100" aria-hidden="true">3 <defs>4 <path id="heart-reveal-path"5 d="M50 84 C 18 60, 6 44, 6 28 C 6 14, 16 6, 28 6 C 38 6, 46 12, 50 22 C 54 12, 62 6, 72 6 C 84 6, 94 14, 94 28 C 94 44, 82 60, 50 84 Z"6 pathLength="1" />7 <radialGradient id="heart-reveal-spark-fill">8 <stop offset="0%" stop-color="#fff" />9 <stop offset="45%" stop-color="#ffd6e8" />10 <stop offset="100%" stop-color="rgba(255, 94, 156, 0)" />11 </radialGradient>12 </defs>13 <g class="heart-reveal__body">14 <use class="heart-reveal__fill" href="#heart-reveal-path" fill="#ff4d8d" />15 <use class="heart-reveal__afterglow" href="#heart-reveal-path"16 fill="none" stroke="#ff6fa5" stroke-width="7" />17 <use class="heart-reveal__outline" href="#heart-reveal-path"18 fill="none" stroke="#ff5e9c" stroke-width="3" />19 </g>20 <circle class="heart-reveal__spark" cx="0" cy="0" r="4.5"21 fill="url(#heart-reveal-spark-fill)" />22 </svg>23 <figcaption id="heart-reveal-caption">Saved to favorites</figcaption>24</figure>25 26<style>27.heart-reveal {28 display: inline-grid;29 justify-items: center;30 gap: .6rem;31 color: #f6d6e2;32 font: 700 .9rem/1.2 ui-sans-serif, system-ui;33}34.heart-reveal__svg {35 width: 220px;36 height: 220px;37 overflow: visible;38}39.heart-reveal__body {40 transform-box: view-box;41 transform-origin: 50px 50px;42 animation: heart-reveal-breathe 4.8s ease-in-out infinite;43}44.heart-reveal__outline {45 stroke-linecap: round;46 stroke-linejoin: round;47 stroke-dasharray: 1;48 stroke-dashoffset: 1;49 animation: heart-reveal-trace 4.8s cubic-bezier(.45, 0, .25, 1) infinite;50}51.heart-reveal__afterglow {52 stroke-linecap: round;53 stroke-linejoin: round;54 stroke-dasharray: 1;55 stroke-dashoffset: 1;56 opacity: 0;57 animation: heart-reveal-afterglow 4.8s ease-out infinite;58}59.heart-reveal__fill {60 transform-box: view-box;61 transform-origin: 50px 50px;62 transform: scale(0);63 animation: heart-reveal-bloom 4.8s cubic-bezier(.3, 1.5, .5, 1) infinite;64}65.heart-reveal__spark {66 opacity: 0;67 offset-path: path('M50 84 C 18 60, 6 44, 6 28 C 6 14, 16 6, 28 6 C 38 6, 46 12, 50 22 C 54 12, 62 6, 72 6 C 84 6, 94 14, 94 28 C 94 44, 82 60, 50 84 Z');68 offset-distance: 0%;69 offset-rotate: 0deg;70 animation: heart-reveal-spark 4.8s cubic-bezier(.45, 0, .25, 1) infinite;71}72@keyframes heart-reveal-trace {73 0%, 2% { stroke-dashoffset: 1; }74 28% { stroke-dashoffset: 0; }75 88% { stroke-dashoffset: 0; }76 94%, 100% { stroke-dashoffset: 1; }77}78@keyframes heart-reveal-afterglow {79 0%, 4% { opacity: 0; stroke-dashoffset: 1; }80 10% { opacity: .5; }81 32% { opacity: .28; stroke-dashoffset: 0; }82 40%, 100% { opacity: 0; stroke-dashoffset: 0; }83}84@keyframes heart-reveal-spark {85 0%, 2% { opacity: 0; offset-distance: 0%; }86 6% { opacity: 1; }87 26% { opacity: 1; offset-distance: 100%; }88 30%, 100% { opacity: 0; offset-distance: 100%; }89}90@keyframes heart-reveal-bloom {91 0%, 28% { transform: scale(0); }92 44% { transform: scale(1); }93 88% { transform: scale(1); }94 94%, 100% { transform: scale(0); }95}96@keyframes heart-reveal-breathe {97 0%, 44% { filter: drop-shadow(0 0 6px rgba(244, 63, 126, .4)); }98 62% { filter: drop-shadow(0 0 18px rgba(244, 63, 126, .75)); }99 82%, 100% { filter: drop-shadow(0 0 6px rgba(244, 63, 126, .4)); }100}101@media (prefers-reduced-motion: reduce) {102 .heart-reveal__body,103 .heart-reveal__outline,104 .heart-reveal__afterglow,105 .heart-reveal__fill,106 .heart-reveal__spark { animation: none; }107 .heart-reveal__outline,108 .heart-reveal__afterglow { stroke-dashoffset: 0; }109 .heart-reveal__fill { transform: scale(1); }110}111</style>