Liveweave: Generative AI Web Editor & HTML/CSS/JS Playground
Initializing
Liveweave
Web
expand_more
home
Home
Palette
Color Explorer
arrow_outward
Polyline
Graphics Editor
arrow_outward
frame_source
Python Playground
arrow_outward
build
Tools
expand_more
restart_alt
Load "Hello Weaver!"
post_add
Generate Lorem ipsum...
code
Format HTML
code_blocks
Format CSS
data_object
Format JavaScript
library_add
Library
expand_more
A
Algolia JS
Animate CSS
Apex Charts JS
B
Bulma CSS
Bootstrap
C
Chart JS
Chartist
Create JS
D
D3
Dojo
F
Foundation
Fullpage JS
G
Granim JS
Google Charts
H
Halfmoon
J
jQuery
M
Materialize
Moment JS
Masonry JS
Milligram CSS
P
Pure CSS
Primer CSS
Popper JS
Pattern CSS
Picnic CSS
R
React JS
Raphael JS
Raisin CSS
S
Semantic UI
Skeleton CSS
Spectre CSS
Tachyons CSS
T
Tailwind
Three JS
U
UI Kit
Vis JS
W
Water CSS
download
Download
expand_more
developer_mode
Download as HTML
folder_zip
Download as .ZIP
cloud_upload
Fork
account_circle
Login
settings
Settings
expand_more
Editor font
14
px
A
A
Night mode
Line number
Mini map
Word wrap
sync_alt
Reset Settings
smart_display
Run
left_panel_close
AI Assistant
dashboard
All
HTML
CSS
JS
visibility
Preview
bolt
Live Preview
terminal
JS Console
<div class="scene"> <div class="ambient-glow"></div> <div class="candle-wrap"> <!-- FLAME --> <div class="flame-wrap" id="flameWrap"> <div class="flame-glow"></div> <div class="flame flame-outer"></div> <div class="flame flame-middle"></div> <div class="flame flame-inner"></div> <div class="flame flame-core"></div> <div class="smoke" id="smoke"> <span></span> <span></span> <span></span> </div> </div> <!-- WICK --> <div class="wick"></div> <!-- CANDLE --> <div class="candle"> <div class="wax-top"> <div class="wax-pool"></div> <div class="melt-hole"></div> </div> <div class="wax-highlight"></div> <div class="drip drip-one"></div> <div class="drip drip-two"></div> <div class="drip drip-three"></div> <div class="wax-shadow"></div> </div> <!-- CANDLE BASE SHADOW --> <div class="candle-shadow"></div> </div> <!-- EMBERS --> <div class="embers" id="embers"></div> <!-- CONTROL --> <button id="toggleButton" class="toggle-button"> Blow out candle </button> </div>
* { box-sizing: border-box; } html, body { margin: 0; width: 100%; height: 100%; overflow: hidden; font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; background: #050505; } /* ----------------------------- SCENE ------------------------------ */ .scene { position: relative; width: 100vw; height: 100vh; display: flex; align-items: center; justify-content: center; overflow: hidden; background: radial-gradient( circle at 50% 55%, #17100a, #080604 40%, #020202 75% ); } /* ----------------------------- AMBIENT LIGHT ------------------------------ */ .ambient-glow { position: absolute; left: 50%; top: 48%; width: 560px; height: 560px; transform: translate(-50%, -50%); border-radius: 50%; background: radial-gradient( circle, rgba(255, 154, 48, .24) 0%, rgba(255, 109, 18, .11) 28%, rgba(255, 75, 10, .04) 52%, transparent 72% ); filter: blur(28px); opacity: .85; pointer-events: none; transition: opacity 1.2s ease; } /* ----------------------------- CANDLE ------------------------------ */ .candle-wrap { position: relative; width: 220px; height: 520px; display: flex; align-items: flex-end; justify-content: center; z-index: 5; } .candle { position: relative; width: 148px; height: 310px; border-radius: 12px 12px 24px 24px; overflow: hidden; background: linear-gradient( 90deg, #c9b9a2 0%, #eadfcf 18%, #fff8ed 42%, #f4e9d9 66%, #cbbba5 100% ); box-shadow: inset 18px 0 30px rgba(100, 70, 40, .13), inset -18px 0 30px rgba(88, 55, 30, .15), 0 30px 60px rgba(0,0,0,.65); } /* ----------------------------- WAX TOP ------------------------------ */ .wax-top { position: absolute; left: 0; top: -17px; width: 148px; height: 42px; border-radius: 50%; background: radial-gradient( ellipse at center, #f7ebdb 0%, #e5d3bb 57%, #c7b198 100% ); box-shadow: inset 0 -6px 12px rgba(95,62,35,.14); } .wax-pool { position: absolute; left: 50%; top: 7px; width: 78px; height: 24px; transform: translateX(-50%); border-radius: 50%; background: radial-gradient( ellipse, rgba(255, 184, 72, .75), rgba(190, 114, 37, .5) 45%, rgba(73, 42, 23, .28) 75% ); box-shadow: 0 0 25px rgba(255, 132, 23, .28); } .melt-hole { position: absolute; left: 50%; top: 11px; width: 30px; height: 13px; transform: translateX(-50%); border-radius: 50%; background: #34241a; box-shadow: inset 0 2px 7px #120c08; } /* ----------------------------- WAX BODY ------------------------------ */ .wax-highlight { position: absolute; left: 38px; top: 10px; width: 26px; height: 270px; border-radius: 30px; background: linear-gradient( to bottom, rgba(255,255,255,.52), rgba(255,255,255,.14), transparent ); filter: blur(4px); } .wax-shadow { position: absolute; right: -10px; top: 0; width: 54px; height: 100%; background: linear-gradient( to left, rgba(80,55,35,.2), transparent ); } /* ----------------------------- WAX DRIPS ------------------------------ */ .drip { position: absolute; top: 0; border-radius: 0 0 50% 50%; background: linear-gradient( to right, #f3e7d5, #dbc8af ); box-shadow: inset -4px 0 5px rgba(110,77,45,.12); } .drip-one { left: 19px; width: 17px; height: 82px; } .drip-two { right: 22px; width: 13px; height: 48px; } .drip-three { left: 50px; width: 10px; height: 33px; } /* ----------------------------- WICK ------------------------------ */ .wick { position: absolute; left: 50%; bottom: 306px; width: 6px; height: 47px; transform: translateX(-50%) rotate(-3deg); border-radius: 4px; background: linear-gradient( 90deg, #201914, #554238, #18120f ); z-index: 8; box-shadow: 0 0 5px rgba(255, 111, 24, .55); } /* ----------------------------- FLAME WRAPPER ------------------------------ */ .flame-wrap { position: absolute; left: 50%; bottom: 342px; width: 150px; height: 190px; transform: translateX(-50%); transform-origin: center bottom; z-index: 15; transition: opacity .5s ease; } /* ----------------------------- FLAME GLOW ------------------------------ */ .flame-glow { position: absolute; left: 50%; bottom: 12px; width: 150px; height: 170px; transform: translateX(-50%); border-radius: 50%; background: radial-gradient( ellipse, rgba(255, 189, 80, .42), rgba(255, 96, 18, .18) 40%, transparent 72% ); filter: blur(22px); animation: glowPulse 1.25s ease-in-out infinite; } @keyframes glowPulse { 0%, 100% { opacity: .75; transform: translateX(-50%) scale(.95); } 50% { opacity: 1; transform: translateX(-50%) scale(1.08); } } /* ----------------------------- FLAMES ------------------------------ */ .flame { position: absolute; left: 50%; bottom: 0; transform-origin: 50% 100%; border-radius: 50% 50% 48% 48%; filter: blur(.3px); } /* outer orange */ .flame-outer { width: 66px; height: 145px; transform: translateX(-50%); background: radial-gradient( ellipse at 50% 80%, #ffb127 0%, #ff8b12 35%, #ff4e07 64%, rgba(255,53,0,.2) 83%, transparent 100% ); clip-path: polygon( 50% 0%, 75% 24%, 92% 54%, 86% 78%, 70% 100%, 30% 100%, 13% 80%, 9% 55%, 26% 26% ); animation: flameOuter .16s ease-in-out infinite alternate; } /* yellow flame */ .flame-middle { width: 43px; height: 108px; transform: translateX(-50%); background: linear-gradient( to top, #fff59a 0%, #ffd54b 35%, #ff9e21 74%, transparent 100% ); clip-path: polygon( 50% 0, 76% 30%, 87% 63%, 69% 100%, 31% 100%, 12% 63%, 25% 29% ); animation: flameMiddle .13s ease-in-out infinite alternate; } /* blue inner base */ .flame-inner { width: 27px; height: 52px; transform: translateX(-50%); background: linear-gradient( to top, #5caeff, #98d7ff 40%, #fff5c2 80%, transparent ); clip-path: polygon( 50% 0, 85% 55%, 65% 100%, 35% 100%, 15% 55% ); opacity: .95; animation: innerFlicker .12s ease-in-out infinite alternate; } /* white-hot core */ .flame-core { width: 13px; height: 31px; transform: translateX(-50%); background: linear-gradient( to top, #ffffff, #fff6c8 70%, transparent ); filter: blur(1px); opacity: .9; } /* ----------------------------- FLAME ANIMATION ------------------------------ */ @keyframes flameOuter { from { transform: translateX(-50%) rotate(-2deg) scaleX(.95) scaleY(1.02); } to { transform: translateX(-50%) rotate(2deg) scaleX(1.05) scaleY(.97); } } @keyframes flameMiddle { from { transform: translateX(-50%) rotate(1deg) scale(.97, 1.04); } to { transform: translateX(-50%) rotate(-2deg) scale(1.03, .96); } } @keyframes innerFlicker { from { transform: translateX(-50%) scaleX(.92); } to { transform: translateX(-50%) scaleX(1.08); } } /* ----------------------------- SMOKE ------------------------------ */ .smoke { position: absolute; left: 50%; top: -20px; width: 80px; height: 100px; transform: translateX(-50%); pointer-events: none; } .smoke span { position: absolute; left: 50%; width: 20px; height: 20px; border-radius: 50%; background: rgba(150,150,150,.13); filter: blur(6px); opacity: 0; } .candle-out .smoke span { animation: smokeRise 2.5s ease-out; } .candle-out .smoke span:nth-child(2) { animation-delay: .25s; } .candle-out .smoke span:nth-child(3) { animation-delay: .5s; } @keyframes smokeRise { 0% { opacity: .38; transform: translate(-50%, 0) scale(.7); } 45% { opacity: .25; transform: translate(-35%, -35px) scale(1.2); } 100% { opacity: 0; transform: translate(-70%, -85px) scale(2); } } /* ----------------------------- EMBERS ------------------------------ */ .embers { position: absolute; inset: 0; pointer-events: none; z-index: 30; } .ember { position: absolute; width: 3px; height: 3px; border-radius: 50%; background: #ffb13b; box-shadow: 0 0 8px #ff6d16; animation: emberRise linear forwards; } @keyframes emberRise { from { opacity: .9; transform: translateY(0) scale(1); } to { opacity: 0; transform: translateY(-110px) translateX(var(--drift)) scale(.2); } } /* ----------------------------- SHADOW ------------------------------ */ .candle-shadow { position: absolute; left: 50%; bottom: -18px; width: 210px; height: 45px; transform: translateX(-50%); border-radius: 50%; background: rgba(0,0,0,.65); filter: blur(16px); } /* ----------------------------- BUTTON ------------------------------ */ .toggle-button { position: absolute; left: 50%; bottom: 35px; transform: translateX(-50%); padding: 11px 18px; border: 1px solid rgba(255,255,255,.12); border-radius: 999px; background: rgba(255,255,255,.06); color: rgba(255,255,255,.72); backdrop-filter: blur(14px); font-size: 11px; cursor: pointer; transition: background .2s, color .2s, transform .2s; } .toggle-button:hover { background: rgba(255,255,255,.12); color: white; transform: translateX(-50%) translateY(-2px); } /* ----------------------------- CANDLE OFF ------------------------------ */ .scene.candle-out .flame-wrap { opacity: 0; } .scene.candle-out .ambient-glow { opacity: .04; } .scene.candle-out { background: radial-gradient( circle at 50% 60%, #11100e, #050505 45%, #010101 75% ); } /* ----------------------------- MOBILE ------------------------------ */ @media ( max-width: 600px ) { .candle-wrap { transform: scale(.82); } }
const scene = document.querySelector( ".scene" ); const flameWrap = document.getElementById( "flameWrap" ); const toggleButton = document.getElementById( "toggleButton" ); const embers = document.getElementById( "embers" ); let candleLit = true; /* ----------------------------- RANDOM FLAME MOVEMENT ------------------------------ */ function flicker() { if (!candleLit) { requestAnimationFrame( flicker ); return; } const rotate = ( Math.random() * 5 - 2.5 ); const moveX = ( Math.random() * 5 - 2.5 ); const scaleY = .95 + Math.random() * .11; const scaleX = .96 + Math.random() * .08; flameWrap.style.transform = ` translateX(-50%) translateX(${moveX}px) rotate(${rotate}deg) scale(${scaleX}, ${scaleY}) `; setTimeout( function() { requestAnimationFrame( flicker ); }, 65 + Math.random() * 75 ); } flicker(); /* ----------------------------- EMBERS ------------------------------ */ function createEmber() { if (!candleLit) { return; } if ( Math.random() > .35 ) { return; } const ember = document.createElement( "span" ); ember.className = "ember"; const centerX = window.innerWidth / 2; const centerY = window.innerHeight / 2 - 130; ember.style.left = ( centerX + Math.random() * 22 - 11 ) + "px"; ember.style.top = ( centerY + Math.random() * 20 ) + "px"; ember.style.setProperty( "--drift", ( Math.random() * 50 - 25 ) + "px" ); ember.style.animationDuration = ( 1.2 + Math.random() * 1.3 ) + "s"; embers.appendChild( ember ); setTimeout( function() { ember.remove(); }, 2600 ); } setInterval( createEmber, 160 ); /* ----------------------------- BLOW OUT / RELIGHT ------------------------------ */ toggleButton.addEventListener( "click", function() { candleLit = !candleLit; scene.classList.toggle( "candle-out", !candleLit ); if (candleLit) { toggleButton.textContent = "Blow out candle"; } else { toggleButton.textContent = "Light candle"; } } );
terminal
JavaScript Console
Preview
Clear
close
›
Run