Rainy Bus Stop
A midnight bus shelter glowing with warm amber light, gentle rain, a puddle reflection, and a tiny waiting traveler.
← you, in 40 minutes.
what you'll build
Here's the plan
A midnight bus shelter scene in SVG — cool purples and blues outside, a warm amber bench light, gentle rain, a puddle catching the glow, and a tiny hooded traveler waiting quietly.
You’ll learn
- Build a moody scene with layered rectangles for sky, ground, and shelter
- Use low-opacity glass panels to separate shelter inside from rain outside
- Animate many rain streaks together with one transform animation
- Add gentle light flicker and character breathing while respecting reduced motion
- Skill level
- Intermediate
- Time
- ~40 min
- Tools
- Just a browser
- Code type
- SVG + CSS
- Lines
- ~90
the steps
Build it, one change at a time
Set the shelter stage
A dark midnight sky, wet ground, and a simple bus shelter with a roof, back wall, glass panels, and a wooden bench. The warm-cool contrast is already there before the light turns on.
<svg class="rainy-bus-stop" viewBox="0 0 230 210" width="230" height="210"> <rect x="0" y="0" width="230" height="210" fill="#2A2356" /> <rect x="0" y="120" width="230" height="90" fill="#4A4478" opacity="0.35" /> <rect x="0" y="185" width="230" height="25" fill="#2D2750" /> <rect x="62" y="64" width="126" height="108" rx="3" fill="#3E3A66" stroke="#1A1536" stroke-width="4" /> <path d="M55 52 L195 52 L188 64 L62 64 Z" fill="#5A5680" stroke="#1A1536" stroke-width="4" /> <rect x="58" y="48" width="134" height="8" rx="2" fill="#1A1536" /> <rect x="58" y="64" width="8" height="118" rx="2" fill="#5A5680" stroke="#1A1536" stroke-width="4" /> <rect x="164" y="64" width="8" height="118" rx="2" fill="#5A5680" stroke="#1A1536" stroke-width="4" /> <rect x="68" y="74" width="28" height="88" fill="#8BA4D0" opacity="0.22" /> <rect x="134" y="74" width="28" height="88" fill="#8BA4D0" opacity="0.22" /> <rect x="76" y="158" width="78" height="8" rx="2" fill="#8B7355" stroke="#1A1536" stroke-width="4" /> </svg>a midnight shelter waiting in the rain — empty, but full of mood.
Add rain, puddle, and warm light
Diagonal rain streaks outside the shelter, a tiny puddle reflecting the shelter glow, and a soft amber light on the back wall turn the structure into a lived-in shelter.
<!-- warm amber bench light glow --> <ellipse class="bench-light" cx="115" cy="140" rx="32" ry="22" fill="#FFB347" opacity="0.28" /> <ellipse class="bench-light-core" cx="115" cy="142" rx="14" ry="9" fill="#FFE4B5" opacity="0.55" /> <!-- rain streaks --> <g class="rain" fill="none" stroke="#8BA4D0" stroke-width="1.6" stroke-linecap="round" opacity="0.7"> <line x1="28" y1="14" x2="22" y2="38" /> <line x1="52" y1="8" x2="46" y2="32" /> <line x1="84" y1="18" x2="78" y2="42" /> <line x1="206" y1="12" x2="200" y2="36" /> <line x1="182" y1="26" x2="176" y2="50" /> <line x1="216" y1="50" x2="210" y2="74" /> <line x1="34" y1="86" x2="28" y2="110" /> <line x1="196" y1="82" x2="190" y2="106" /> </g> <!-- puddle catching the glow --> <ellipse class="puddle" cx="122" cy="196" rx="54" ry="7" fill="#8BA4D0" opacity="0.35" /> <ellipse cx="122" cy="196" rx="38" ry="4" fill="#FFE4B5" opacity="0.18" />rain, puddle, and a warm bench light — the shelter feels safe now.
Add the tiny traveler
A small hooded character in a purple coat, a duffel bag on the ground, and tiny tucked hands make the scene feel like a pause in someone's journey.
<!-- small duffel bag --> <rect x="98" y="172" width="18" height="14" rx="4" fill="#6B5E4F" stroke="#1A1536" stroke-width="3.5" /> <line x1="104" y1="172" x2="104" y2="166" stroke="#1A1536" stroke-width="3" /> <!-- hooded traveler --> <g class="character" stroke="#1A1536" stroke-width="3.5" stroke-linecap="round" stroke-linejoin="round"> <ellipse cx="100" cy="148" rx="16" ry="20" fill="#C9B8E8" /> <circle cx="100" cy="130" r="13" fill="#C9B8E8" /> <ellipse cx="100" cy="124" rx="14" ry="11" fill="#9B8AC4" /> <circle cx="96" cy="130" r="1.6" fill="#1A1536" stroke="none" /> <circle cx="104" cy="130" r="1.6" fill="#1A1536" stroke="none" /> <circle cx="92" cy="152" r="3.5" fill="#9B8AC4" stroke="none" /> <circle cx="108" cy="152" r="3.5" fill="#9B8AC4" stroke="none" /> <line x1="92" y1="162" x2="92" y2="172" /> <line x1="108" y1="162" x2="108" y2="172" /> </g>a tiny traveler waiting quietly — the scene now has a story.
Animate the rain, light, and breathing
One keyframe slides the whole rain group down, another flickers the bench light, and a third gently breathes the character. All motion is wrapped in prefers-reduced-motion.
@media (prefers-reduced-motion: no-preference) { .rainy-bus-stop .rain { animation: rainy-bus-stop-rain 1.1s linear infinite; } .rainy-bus-stop .bench-light { animation: rainy-bus-stop-flicker 3.2s ease-in-out infinite; } .rainy-bus-stop .bench-light-core { animation: rainy-bus-stop-flicker 3.2s ease-in-out infinite reverse; } .rainy-bus-stop .character { animation: rainy-bus-stop-breathe 3.6s ease-in-out infinite; } } @keyframes rainy-bus-stop-rain { 0% { transform: translateY(-12px) translateX(4px); opacity: 0.45; } 20% { opacity: 0.7; } 100% { transform: translateY(18px) translateX(-6px); opacity: 0.45; } } @keyframes rainy-bus-stop-flicker { 0%, 100% { opacity: 0.22; transform: scale(1); } 45% { opacity: 0.30; transform: scale(1.06); } 55% { opacity: 0.24; transform: scale(0.98); } 70% { opacity: 0.32; transform: scale(1.04); } }the finished rainy bus stop — rain falling, light flickering, traveler breathing.
the complete code
Everything, in one place
Skipped straight to the end? Welcome. Copy the whole thing, download it, or open it in the Playground to start remixing.
<svg class="rainy-bus-stop" viewBox="0 0 230 210" width="230" height="210" role="img" aria-label="Animated rainy bus stop cozy scene">
<!-- midnight sky wash -->
<rect x="0" y="0" width="230" height="210" fill="#2A2356" stroke="none"/>
<!-- soft lower glow behind the shelter -->
<rect x="0" y="120" width="230" height="90" fill="#4A4478" opacity="0.35" stroke="none"/>
<!-- wet ground -->
<rect x="0" y="185" width="230" height="25" fill="#2D2750" stroke="none"/>
<!-- shelter back wall -->
<rect x="62" y="64" width="126" height="108" rx="3" fill="#3E3A66" stroke="#1A1536" stroke-width="4"/>
<!-- shelter roof -->
<path d="M55 52 L195 52 L188 64 L62 64 Z" fill="#5A5680" stroke="#1A1536" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
<rect x="58" y="48" width="134" height="8" rx="2" fill="#1A1536" stroke="none"/>
<!-- front frame posts -->
<rect x="58" y="64" width="8" height="118" rx="2" fill="#5A5680" stroke="#1A1536" stroke-width="4"/>
<rect x="164" y="64" width="8" height="118" rx="2" fill="#5A5680" stroke="#1A1536" stroke-width="4"/>
<!-- glass side panels -->
<rect x="68" y="74" width="28" height="88" fill="#8BA4D0" opacity="0.22" stroke="none"/>
<rect x="134" y="74" width="28" height="88" fill="#8BA4D0" opacity="0.22" stroke="none"/>
<!-- bench -->
<g stroke="#1A1536" stroke-width="4" stroke-linecap="round" stroke-linejoin="round">
<rect x="76" y="158" width="78" height="8" rx="2" fill="#8B7355"/>
<rect x="82" y="166" width="6" height="18" rx="1" fill="#6B5E4F"/>
<rect x="142" y="166" width="6" height="18" rx="1" fill="#6B5E4F"/>
</g>
<!-- warm amber bench light glow on the back wall -->
<ellipse class="bench-light" cx="115" cy="140" rx="32" ry="22" fill="#FFB347" opacity="0.28" stroke="none"/>
<ellipse class="bench-light-core" cx="115" cy="142" rx="14" ry="9" fill="#FFE4B5" opacity="0.55" stroke="none"/>
<!-- rain streaks outside the shelter -->
<g class="rain" fill="none" stroke="#8BA4D0" stroke-width="1.6" stroke-linecap="round" opacity="0.7">
<line x1="28" y1="14" x2="22" y2="38"/>
<line x1="52" y1="8" x2="46" y2="32"/>
<line x1="84" y1="18" x2="78" y2="42"/>
<line x1="14" y1="44" x2="8" y2="68"/>
<line x1="42" y1="54" x2="36" y2="78"/>
<line x1="206" y1="12" x2="200" y2="36"/>
<line x1="182" y1="26" x2="176" y2="50"/>
<line x1="216" y1="50" x2="210" y2="74"/>
<line x1="34" y1="86" x2="28" y2="110"/>
<line x1="196" y1="82" x2="190" y2="106"/>
<line x1="12" y1="120" x2="6" y2="144"/>
<line x1="222" y1="118" x2="216" y2="142"/>
<line x1="50" y1="130" x2="44" y2="154"/>
<line x1="180" y1="134" x2="174" y2="158"/>
</g>
<!-- tiny puddle catching the shelter glow -->
<ellipse class="puddle" cx="122" cy="196" rx="54" ry="7" fill="#8BA4D0" opacity="0.35" stroke="none"/>
<ellipse cx="122" cy="196" rx="38" ry="4" fill="#FFE4B5" opacity="0.18" stroke="none"/>
<!-- a few reflected shelter lines in the puddle -->
<g opacity="0.2" stroke="#FFE4B5" stroke-width="2" stroke-linecap="round">
<line x1="92" y1="196" x2="108" y2="196"/>
<line x1="128" y1="196" x2="152" y2="196"/>
</g>
<!-- tiny waiting character -->
<g class="character" stroke="#1A1536" stroke-width="3.5" stroke-linecap="round" stroke-linejoin="round">
<!-- small duffel bag on the ground -->
<rect x="98" y="172" width="18" height="14" rx="4" fill="#6B5E4F" stroke="#1A1536"/>
<path d="M104 172 L104 166" fill="none" stroke="#1A1536" stroke-width="3"/>
<!-- body in a cozy hooded coat -->
<ellipse cx="100" cy="148" rx="16" ry="20" fill="#C9B8E8"/>
<!-- hood and head -->
<circle cx="100" cy="130" r="13" fill="#C9B8E8"/>
<ellipse cx="100" cy="124" rx="14" ry="11" fill="#9B8AC4"/>
<!-- face peeping out of the hood -->
<circle cx="96" cy="130" r="1.6" fill="#1A1536" stroke="none"/>
<circle cx="104" cy="130" r="1.6" fill="#1A1536" stroke="none"/>
<!-- tiny hands tucked close -->
<circle cx="92" cy="152" r="3.5" fill="#9B8AC4" stroke="none"/>
<circle cx="108" cy="152" r="3.5" fill="#9B8AC4" stroke="none"/>
<!-- short dangling legs -->
<path d="M92 162 L92 172" fill="none" stroke="#1A1536" stroke-width="3.5" stroke-linecap="round"/>
<path d="M108 162 L108 172" fill="none" stroke="#1A1536" stroke-width="3.5" stroke-linecap="round"/>
</g>
</svg>
tips & gotchas
Mistakes we actually made
Rain reads as rain because all streaks move together as one group, not individually — one transform on the parent <g> is enough.
A warm light glow against a cool background is the single contrast that makes the shelter feel cozy.
Keep the traveler small and simple; too much detail would steal attention from the whole scene.
Use opacity generously for glass, puddles, and reflections — real rain is never fully opaque.
make it yours
Remix it
- Day buseasy
Swap the midnight palette for a pale morning blue and turn off the bench light.
- Heavier raineasy
Add more diagonal lines and speed up the rain animation duration.
- Different travelermedium
Change the coat color, add a tiny umbrella, or make the character stand instead of sit.
- Bus arrivalmedium
Add a bright headlight beam entering from the right and a reflection in the puddle.
challenge extension
Same shelter, new season: turn the scene into a snowy stop by replacing rain with soft falling circles and adding a small snow pile on the roof.