Skip to content

Instantly share code, notes, and snippets.

@vkryukov
Created May 19, 2026 19:56
Show Gist options
  • Select an option

  • Save vkryukov/029df86d03bfe8f87df1e4d9ed2f6b02 to your computer and use it in GitHub Desktop.

Select an option

Save vkryukov/029df86d03bfe8f87df1e4d9ed2f6b02 to your computer and use it in GitHub Desktop.
Animated SVG frog rowing through a jungle river
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Rowing Frog on a Jungle River</title>
<style>
:root {
color-scheme: dark;
--sky-top: #80cfd8;
--sky-bottom: #f1d38b;
--river: #176f83;
--river-dark: #0d5369;
--leaf: #1b8b4d;
--leaf-dark: #07593f;
--leaf-light: #6fbf4a;
--frog: #5fbd42;
--frog-dark: #2f8739;
--frog-light: #a5df6a;
--wood: #8a4f2a;
--wood-dark: #4b2a1b;
}
* {
box-sizing: border-box;
}
html,
body {
margin: 0;
min-height: 100%;
overflow: hidden;
background: #082b2e;
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
}
main {
width: 100vw;
height: 100vh;
display: grid;
place-items: center;
background:
radial-gradient(circle at 50% 38%, rgba(255, 225, 130, 0.36), transparent 23rem),
linear-gradient(180deg, #063534 0%, #061d20 100%);
}
svg {
width: min(100vw, 150vh);
height: auto;
max-height: 100vh;
display: block;
}
.mist {
animation: mist-drift 18s linear infinite;
}
.mist,
.back-leaves,
.front-leaves,
.current-a,
.current-b,
.boat-rig,
.boat-shadow,
.frog-body,
.frog-head,
.left-oar,
.right-oar,
.left-arm,
.right-arm,
.left-blade-splash,
.right-blade-splash,
.blink,
.breath,
.river-glint {
transform-box: view-box;
will-change: transform, opacity;
}
.back-leaves {
animation: jungle-sway 7s ease-in-out infinite alternate;
transform-origin: 50% 65%;
}
.front-leaves {
animation: jungle-sway 5.4s ease-in-out infinite alternate-reverse;
transform-origin: 50% 78%;
}
.current-a {
animation: river-flow-a 4.8s linear infinite;
}
.current-b {
animation: river-flow-b 6.2s linear infinite;
}
.boat-rig {
animation: boat-bob 2.8s ease-in-out infinite;
transform-origin: 600px 520px;
}
.boat-shadow {
animation: shadow-breathe 2.8s ease-in-out infinite;
transform-origin: 600px 575px;
}
.frog-body {
animation: frog-lean 1.45s ease-in-out infinite;
transform-origin: 600px 430px;
}
.frog-head {
animation: frog-head 1.45s ease-in-out infinite;
transform-origin: 600px 386px;
}
.left-oar {
animation: left-oar-stroke 1.45s ease-in-out infinite;
transform-origin: 520px 500px;
}
.right-oar {
animation: right-oar-stroke 1.45s ease-in-out infinite;
transform-origin: 680px 500px;
}
.left-arm {
animation: left-arm-stroke 1.45s ease-in-out infinite;
transform-origin: 565px 455px;
}
.right-arm {
animation: right-arm-stroke 1.45s ease-in-out infinite;
transform-origin: 635px 455px;
}
.left-blade-splash {
animation: left-splash 1.45s ease-in-out infinite;
transform-origin: 354px 554px;
}
.right-blade-splash {
animation: right-splash 1.45s ease-in-out infinite;
transform-origin: 846px 554px;
}
.blink {
animation: blink 5.8s ease-in-out infinite;
transform-origin: center;
}
.breath {
animation: breath 2.3s ease-in-out infinite;
transform-origin: center;
}
.river-glint {
animation: glint 2.4s ease-in-out infinite alternate;
}
@keyframes mist-drift {
from { transform: translateX(-72px); opacity: 0.42; }
50% { opacity: 0.68; }
to { transform: translateX(72px); opacity: 0.42; }
}
@keyframes jungle-sway {
from { transform: rotate(-0.6deg) translateX(-4px); }
to { transform: rotate(0.8deg) translateX(5px); }
}
@keyframes river-flow-a {
from { transform: translateX(-120px); }
to { transform: translateX(120px); }
}
@keyframes river-flow-b {
from { transform: translateX(135px); }
to { transform: translateX(-135px); }
}
@keyframes boat-bob {
0%, 100% { transform: translateY(0) rotate(-0.6deg); }
35% { transform: translateY(-8px) rotate(0.8deg); }
70% { transform: translateY(4px) rotate(-1deg); }
}
@keyframes shadow-breathe {
0%, 100% { transform: scaleX(1); opacity: 0.34; }
50% { transform: scaleX(0.91); opacity: 0.22; }
}
@keyframes frog-lean {
0%, 100% { transform: translateX(0) rotate(-2deg); }
45% { transform: translateX(7px) translateY(2px) rotate(3deg); }
70% { transform: translateX(-3px) translateY(-2px) rotate(-4deg); }
}
@keyframes frog-head {
0%, 100% { transform: rotate(1deg) translateY(0); }
45% { transform: rotate(-2deg) translateY(2px); }
70% { transform: rotate(3deg) translateY(-1px); }
}
@keyframes left-oar-stroke {
0%, 100% { transform: rotate(18deg); }
34% { transform: rotate(-20deg); }
58% { transform: rotate(-33deg); }
74% { transform: rotate(9deg); }
}
@keyframes right-oar-stroke {
0%, 100% { transform: rotate(-18deg); }
34% { transform: rotate(20deg); }
58% { transform: rotate(33deg); }
74% { transform: rotate(-9deg); }
}
@keyframes left-arm-stroke {
0%, 100% { transform: rotate(-15deg) translateX(0); }
34% { transform: rotate(12deg) translateX(-10px); }
58% { transform: rotate(22deg) translateX(-14px); }
74% { transform: rotate(-5deg) translateX(5px); }
}
@keyframes right-arm-stroke {
0%, 100% { transform: rotate(15deg) translateX(0); }
34% { transform: rotate(-12deg) translateX(10px); }
58% { transform: rotate(-22deg) translateX(14px); }
74% { transform: rotate(5deg) translateX(-5px); }
}
@keyframes left-splash {
0%, 28%, 100% { opacity: 0; transform: scale(0.6) translateY(4px); }
39% { opacity: 1; transform: scale(1.12) translateY(-4px); }
58% { opacity: 0.34; transform: scale(1.5) translateY(-9px); }
}
@keyframes right-splash {
0%, 28%, 100% { opacity: 0; transform: scale(0.6) translateY(4px); }
39% { opacity: 1; transform: scale(1.12) translateY(-4px); }
58% { opacity: 0.34; transform: scale(1.5) translateY(-9px); }
}
@keyframes blink {
0%, 92%, 100% { transform: scaleY(1); }
95% { transform: scaleY(0.08); }
}
@keyframes breath {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.025); }
}
@keyframes glint {
from { opacity: 0.2; }
to { opacity: 0.7; }
}
</style>
</head>
<body>
<main aria-label="Animated SVG of a frog rowing a boat through a jungle river">
<svg viewBox="0 0 1200 800" role="img" aria-labelledby="title desc" xmlns="http://www.w3.org/2000/svg">
<title id="title">Animated frog rowing a boat through a jungle river</title>
<desc id="desc">A green frog rows a wooden canoe on a tropical river, with moving oars, splashes, drifting water, and swaying jungle leaves.</desc>
<defs>
<linearGradient id="sky" x1="0" x2="0" y1="0" y2="1">
<stop offset="0" stop-color="var(--sky-top)"/>
<stop offset="0.58" stop-color="#bbdfad"/>
<stop offset="1" stop-color="var(--sky-bottom)"/>
</linearGradient>
<linearGradient id="riverGradient" x1="0" x2="0" y1="0" y2="1">
<stop offset="0" stop-color="#21909a"/>
<stop offset="0.5" stop-color="var(--river)"/>
<stop offset="1" stop-color="var(--river-dark)"/>
</linearGradient>
<linearGradient id="boatWood" x1="0" x2="1" y1="0" y2="1">
<stop offset="0" stop-color="#b97434"/>
<stop offset="0.45" stop-color="var(--wood)"/>
<stop offset="1" stop-color="var(--wood-dark)"/>
</linearGradient>
<radialGradient id="frogSkin" cx="45%" cy="32%" r="72%">
<stop offset="0" stop-color="#b9f279"/>
<stop offset="0.45" stop-color="var(--frog)"/>
<stop offset="1" stop-color="var(--frog-dark)"/>
</radialGradient>
<radialGradient id="sunGlow" cx="50%" cy="50%" r="50%">
<stop offset="0" stop-color="#fff7af" stop-opacity="0.95"/>
<stop offset="0.58" stop-color="#ffd26c" stop-opacity="0.6"/>
<stop offset="1" stop-color="#ffbf58" stop-opacity="0"/>
</radialGradient>
<filter id="softShadow" x="-30%" y="-30%" width="160%" height="160%">
<feGaussianBlur stdDeviation="6"/>
</filter>
<filter id="leafShadow" x="-20%" y="-20%" width="140%" height="140%">
<feDropShadow dx="0" dy="5" stdDeviation="4" flood-color="#062f29" flood-opacity="0.35"/>
</filter>
<pattern id="woodGrain" width="80" height="22" patternUnits="userSpaceOnUse">
<path d="M0 6 C18 0 38 14 58 7 S86 5 98 10" fill="none" stroke="#c98948" stroke-opacity="0.38" stroke-width="2"/>
<path d="M-8 17 C18 21 29 10 50 17 S78 22 91 15" fill="none" stroke="#3d2115" stroke-opacity="0.32" stroke-width="1.8"/>
</pattern>
</defs>
<rect width="1200" height="800" fill="url(#sky)"/>
<circle cx="600" cy="210" r="178" fill="url(#sunGlow)"/>
<circle cx="600" cy="210" r="64" fill="#ffe08b" opacity="0.78"/>
<g class="mist" opacity="0.46">
<path d="M44 274 C178 238 314 266 456 241 C600 215 755 246 900 222 C1012 203 1116 215 1220 194" fill="none" stroke="#eaffef" stroke-width="18" stroke-linecap="round" opacity="0.34"/>
<path d="M-40 336 C148 302 260 327 402 302 C556 275 693 297 836 279 C980 261 1068 278 1240 246" fill="none" stroke="#f5fff9" stroke-width="12" stroke-linecap="round" opacity="0.28"/>
</g>
<g class="back-leaves" filter="url(#leafShadow)">
<path d="M0 345 C82 252 145 242 238 328 C140 318 74 356 0 428Z" fill="#127347"/>
<path d="M80 312 C135 194 226 142 358 180 C256 222 206 282 190 390Z" fill="#2c9652"/>
<path d="M1000 335 C1087 244 1138 244 1200 299 L1200 448 C1118 364 1072 346 1000 335Z" fill="#0e6b43"/>
<path d="M908 202 C1040 145 1137 176 1210 252 C1110 234 1016 263 945 354Z" fill="#3b9d51"/>
<path d="M306 232 C378 130 486 98 602 150 C501 190 440 249 401 363Z" fill="#117447"/>
<path d="M638 159 C755 92 866 99 984 178 C868 178 779 228 707 343Z" fill="#1c8752"/>
</g>
<g opacity="0.78">
<path d="M0 379 C122 336 206 347 316 395 C442 449 517 430 600 391 C707 342 798 335 927 389 C1023 429 1101 425 1200 388 L1200 800 L0 800Z" fill="#0c694b"/>
<path d="M0 418 C115 375 229 389 328 430 C456 483 534 458 623 416 C724 368 808 371 923 425 C1036 478 1117 464 1200 431 L1200 800 L0 800Z" fill="#07513d"/>
</g>
<path d="M0 438 C142 414 260 448 374 479 C503 514 686 514 826 480 C963 447 1080 419 1200 444 L1200 800 L0 800Z" fill="url(#riverGradient)"/>
<path d="M0 536 C167 482 318 501 493 537 C643 568 775 570 929 526 C1042 493 1135 493 1200 510 L1200 800 L0 800Z" fill="#0d5b72" opacity="0.34"/>
<g class="current-a" fill="none" stroke="#93d9cf" stroke-linecap="round" opacity="0.48">
<path d="M-130 504 C-88 494 -46 494 0 506 S86 519 133 503" stroke-width="5"/>
<path d="M80 602 C132 589 190 592 242 606 S340 623 397 601" stroke-width="3"/>
<path d="M430 555 C486 540 540 544 590 559 S682 575 731 555" stroke-width="4"/>
<path d="M822 629 C884 611 936 617 988 633 S1080 651 1135 630" stroke-width="4"/>
<path d="M1060 494 C1120 477 1175 484 1234 501 S1332 520 1390 498" stroke-width="5"/>
</g>
<g class="current-b" fill="none" stroke="#d6f3df" stroke-linecap="round" opacity="0.32">
<path d="M-70 669 C-10 648 44 651 110 672 S220 697 286 666" stroke-width="4"/>
<path d="M250 466 C306 454 357 458 418 473 S522 488 576 469" stroke-width="3"/>
<path d="M622 702 C681 684 739 687 800 707 S913 733 976 700" stroke-width="4"/>
<path d="M940 565 C1000 544 1055 548 1117 569 S1232 596 1293 563" stroke-width="3"/>
</g>
<g class="river-glint" fill="none" stroke="#fcf2bc" stroke-linecap="round" opacity="0.36">
<path d="M482 459 C522 452 554 454 587 462" stroke-width="3"/>
<path d="M630 452 C674 442 719 446 759 459" stroke-width="3"/>
<path d="M524 678 C590 661 663 664 730 682" stroke-width="2"/>
</g>
<ellipse class="boat-shadow" cx="600" cy="594" rx="265" ry="34" fill="#062d34" opacity="0.32" filter="url(#softShadow)"/>
<g class="boat-rig">
<g class="left-oar">
<line x1="520" y1="500" x2="344" y2="548" stroke="#6f3d22" stroke-width="16" stroke-linecap="round"/>
<line x1="520" y1="500" x2="344" y2="548" stroke="#c98b50" stroke-width="5" stroke-linecap="round" opacity="0.65"/>
<path d="M323 532 C294 541 279 570 297 589 C326 585 351 563 353 538 C345 533 335 530 323 532Z" fill="#c17734" stroke="#4b2a1b" stroke-width="4"/>
</g>
<g class="right-oar">
<line x1="680" y1="500" x2="856" y2="548" stroke="#6f3d22" stroke-width="16" stroke-linecap="round"/>
<line x1="680" y1="500" x2="856" y2="548" stroke="#c98b50" stroke-width="5" stroke-linecap="round" opacity="0.65"/>
<path d="M877 532 C906 541 921 570 903 589 C874 585 849 563 847 538 C855 533 865 530 877 532Z" fill="#c17734" stroke="#4b2a1b" stroke-width="4"/>
</g>
<path d="M382 490 C424 574 503 618 600 618 C697 618 776 574 818 490 C752 511 664 520 600 520 C536 520 448 511 382 490Z" fill="url(#boatWood)" stroke="#321b12" stroke-width="8" stroke-linejoin="round"/>
<path d="M408 496 C468 534 536 550 600 550 C664 550 732 534 792 496 C744 555 676 589 600 589 C524 589 456 555 408 496Z" fill="#5b321e" opacity="0.52"/>
<path d="M397 492 C457 510 526 519 600 519 C674 519 743 510 803 492" fill="none" stroke="#d79655" stroke-width="10" stroke-linecap="round"/>
<path d="M397 492 C457 510 526 519 600 519 C674 519 743 510 803 492" fill="none" stroke="url(#woodGrain)" stroke-width="16" stroke-linecap="round" opacity="0.8"/>
<path d="M475 536 L725 536" stroke="#2b170f" stroke-width="8" stroke-linecap="round" opacity="0.55"/>
<path d="M486 526 C525 540 675 540 714 526" stroke="#c3834b" stroke-width="5" stroke-linecap="round" opacity="0.5"/>
<g class="frog-body">
<ellipse class="breath" cx="600" cy="458" rx="68" ry="72" fill="url(#frogSkin)" stroke="#23672f" stroke-width="5"/>
<ellipse cx="600" cy="476" rx="43" ry="45" fill="#b9e77b" opacity="0.82"/>
<ellipse cx="552" cy="509" rx="31" ry="20" fill="#3d963f" stroke="#23672f" stroke-width="4"/>
<ellipse cx="648" cy="509" rx="31" ry="20" fill="#3d963f" stroke="#23672f" stroke-width="4"/>
<g class="left-arm">
<path d="M558 454 C531 461 512 478 500 505" fill="none" stroke="#4ba940" stroke-width="18" stroke-linecap="round"/>
<circle cx="500" cy="505" r="14" fill="#73c84b" stroke="#23672f" stroke-width="4"/>
<path d="M492 505 L477 492 M493 510 L474 511 M498 517 L484 530" stroke="#23672f" stroke-width="4" stroke-linecap="round"/>
</g>
<g class="right-arm">
<path d="M642 454 C669 461 688 478 700 505" fill="none" stroke="#4ba940" stroke-width="18" stroke-linecap="round"/>
<circle cx="700" cy="505" r="14" fill="#73c84b" stroke="#23672f" stroke-width="4"/>
<path d="M708 505 L723 492 M707 510 L726 511 M702 517 L716 530" stroke="#23672f" stroke-width="4" stroke-linecap="round"/>
</g>
<g class="frog-head">
<circle cx="600" cy="382" r="64" fill="url(#frogSkin)" stroke="#23672f" stroke-width="5"/>
<circle cx="560" cy="336" r="31" fill="#82cf52" stroke="#23672f" stroke-width="5"/>
<circle cx="640" cy="336" r="31" fill="#82cf52" stroke="#23672f" stroke-width="5"/>
<g class="blink">
<circle cx="560" cy="336" r="16" fill="#f7ffe5"/>
<circle cx="640" cy="336" r="16" fill="#f7ffe5"/>
<circle cx="564" cy="340" r="7" fill="#102421"/>
<circle cx="636" cy="340" r="7" fill="#102421"/>
<circle cx="567" cy="337" r="2.5" fill="#fff"/>
<circle cx="639" cy="337" r="2.5" fill="#fff"/>
</g>
<circle cx="575" cy="383" r="5" fill="#23672f"/>
<circle cx="625" cy="383" r="5" fill="#23672f"/>
<path d="M554 403 C575 424 625 424 646 403" fill="none" stroke="#1f5d2c" stroke-width="6" stroke-linecap="round"/>
<circle cx="546" cy="396" r="12" fill="#e77971" opacity="0.35"/>
<circle cx="654" cy="396" r="12" fill="#e77971" opacity="0.35"/>
</g>
</g>
<circle cx="520" cy="500" r="10" fill="#22130d"/>
<circle cx="680" cy="500" r="10" fill="#22130d"/>
</g>
<g class="left-blade-splash" fill="none" stroke="#d3fbff" stroke-linecap="round" opacity="0">
<path d="M314 560 C300 548 294 536 295 522" stroke-width="4"/>
<path d="M332 572 C324 588 309 601 291 606" stroke-width="4"/>
<path d="M347 551 C364 546 380 548 392 557" stroke-width="3"/>
</g>
<g class="right-blade-splash" fill="none" stroke="#d3fbff" stroke-linecap="round" opacity="0">
<path d="M886 560 C900 548 906 536 905 522" stroke-width="4"/>
<path d="M868 572 C876 588 891 601 909 606" stroke-width="4"/>
<path d="M853 551 C836 546 820 548 808 557" stroke-width="3"/>
</g>
<g class="front-leaves" filter="url(#leafShadow)">
<path d="M0 668 C78 590 143 578 226 623 C132 645 64 704 0 800Z" fill="#064c38"/>
<path d="M0 564 C65 522 126 517 198 549 C115 586 55 644 0 738Z" fill="#0d7c45"/>
<path d="M91 696 C137 619 219 602 300 650 C219 670 161 715 116 800 L76 800Z" fill="#2b9950"/>
<path d="M1200 642 C1126 584 1057 582 982 630 C1066 648 1138 707 1200 798Z" fill="#064f3a"/>
<path d="M1200 548 C1134 511 1076 513 1006 552 C1090 584 1148 641 1200 731Z" fill="#11844a"/>
<path d="M1095 704 C1049 618 960 601 878 653 C960 671 1016 718 1060 800 L1124 800Z" fill="#43a84f"/>
<path d="M20 620 C54 592 97 593 134 622 C94 633 59 660 35 704Z" fill="#7dbd39"/>
<path d="M1167 618 C1131 592 1088 596 1054 627 C1094 635 1130 661 1156 704Z" fill="#86c64b"/>
</g>
</svg>
</main>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment