Tornado Funnel
A copy-paste weather & ambient component in pure HTML & CSS. Zero dependencies, framework-agnostic, MIT-licensed.
Weather & AmbientHTMLCSSany framework
Copy into your project
HTML
<!-- Tornado Funnel (5 counter-spinning rings + orbiting debris) -->
<div class="nuda-wa2-tornado" role="img" aria-label="Spinning tornado funnel with flying debris">
<span class="nuda-wa2-tornado__ring nuda-wa2-tornado__ring--1"></span>
<span class="nuda-wa2-tornado__ring nuda-wa2-tornado__ring--2"></span>
<span class="nuda-wa2-tornado__ring nuda-wa2-tornado__ring--3"></span>
<span class="nuda-wa2-tornado__ring nuda-wa2-tornado__ring--4"></span>
<span class="nuda-wa2-tornado__ring nuda-wa2-tornado__ring--5"></span>
<span class="nuda-wa2-tornado__debris" style="left:50%; --td-d:0s"></span>
<span class="nuda-wa2-tornado__debris" style="left:58%; --td-d:.5s"></span>
<span class="nuda-wa2-tornado__debris" style="left:42%; --td-d:1s"></span>
</div>CSS
.nuda-wa2-tornado {
position: relative;
width: 100%;
max-width: 200px;
height: 140px;
border-radius: 14px;
overflow: hidden;
background: linear-gradient(180deg,#141419,#09090b 70%);
}
.nuda-wa2-tornado__ring {
position: absolute;
left: 50%;
border-radius: 50%;
background: repeating-conic-gradient(rgba(228,255,84,.35) 0 10deg,rgba(250,250,250,.12) 10deg 20deg);
will-change: transform;
opacity: .85;
}
.nuda-wa2-tornado__ring--1 {
top: 10px;
width: 26px;
height: 10px;
transform: translateX(-50%);
animation: _nuda-wa2tornadoSpin 1.1s linear infinite;
}
.nuda-wa2-tornado__ring--2 {
top: 34px;
width: 44px;
height: 14px;
transform: translateX(-50%);
animation: _nuda-wa2tornadoSpin 1.4s linear infinite reverse;
}
.nuda-wa2-tornado__ring--3 {
top: 60px;
width: 64px;
height: 18px;
transform: translateX(-50%);
animation: _nuda-wa2tornadoSpin 1.7s linear infinite;
}
.nuda-wa2-tornado__ring--4 {
top: 88px;
width: 88px;
height: 22px;
transform: translateX(-50%);
animation: _nuda-wa2tornadoSpin 2s linear infinite reverse;
}
.nuda-wa2-tornado__ring--5 {
top: 116px;
width: 112px;
height: 24px;
transform: translateX(-50%);
opacity: .6;
animation: _nuda-wa2tornadoSpin 2.3s linear infinite;
}
.nuda-wa2-tornado__debris {
position: absolute;
bottom: 10px;
left: 50%;
width: 3px;
height: 3px;
border-radius: 50%;
background: #e4ff54;
will-change: transform,opacity;
animation: _nuda-wa2tornadoDebris 1.6s ease-in-out var(--td-d,0s) infinite;
}
@keyframes _nuda-wa2tornadoSpin {
to {
transform: translateX(-50%) rotate(360deg);
}
}
@keyframes _nuda-wa2tornadoDebris {
0% {
transform: translate(-50%,0) scale(.6);
opacity: 0;
}
30% {
opacity: .9;
}
100% {
transform: translate(calc(-50% + 40px),-70px) scale(.2);
opacity: 0;
}
}
@media (prefers-reduced-motion:reduce) {
.nuda-wa2-tornado__ring,.nuda-wa2-tornado__debris {
animation: none;
opacity: .5;
}
}
How to use Tornado Funnel
Paste the HTML where you need it and the CSS into a global stylesheet (or a <style> tag). Every class is prefixed nuda- so it never collides with Tailwind or your own styles. Tweak the CSS custom properties to match your design system.
Works in React, Vue, Svelte, Astro, Next.js, Nuxt, Laravel Blade, Django, Rails — or a single .html file. No npm install, no build step.