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
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="meter-page"> <div class="meter-card"> <div class="gauge-wrap"> <svg class="gauge" viewBox="0 0 520 350" aria-label="Analog meter" > <defs> <linearGradient id="arcGradient" x1="0" y1="0" x2="1" y2="0" > <stop offset="0%" stop-color="#19e86d"/> <stop offset="42%" stop-color="#d5f51e"/> <stop offset="66%" stop-color="#ffc21b"/> <stop offset="83%" stop-color="#ff742b"/> <stop offset="100%" stop-color="#ff2538"/> </linearGradient> <filter id="arcGlow"> <feGaussianBlur stdDeviation="7" result="blur" /> <feMerge> <feMergeNode in="blur"/> <feMergeNode in="SourceGraphic"/> </feMerge> </filter> <filter id="needleGlow"> <feGaussianBlur stdDeviation="3" result="blur" /> <feMerge> <feMergeNode in="blur"/> <feMergeNode in="SourceGraphic"/> </feMerge> </filter> </defs> <!-- OUTER ARC --> <path class="arc-shadow" d="M 65 255 A 195 195 0 0 1 455 255" /> <path class="arc" d="M 65 255 A 195 195 0 0 1 455 255" /> <!-- TICKS + LABELS --> <g id="ticks"></g> <!-- NEEDLE --> <g id="needleGroup"> <line x1="260" y1="255" x2="260" y2="105" class="needle" /> </g> <!-- HUB --> <circle cx="260" cy="255" r="22" class="hub-shadow" /> <circle cx="260" cy="255" r="17" class="hub" /> <circle cx="260" cy="255" r="8" class="hub-center" /> </svg> <!-- VALUE IS OUTSIDE SVG SO IT CAN NEVER COLLIDE WITH TICKS --> <div class="reading"> <div class="reading-number"> <span id="value">95</span> <small>%</small> </div> <div class="status-pill critical" id="meterLabel" > Critical </div> </div> </div> <div class="controls"> <button data-value="15"> Low </button> <button data-value="42"> Normal </button> <button data-value="72"> High </button> <button data-value="95" class="active" > Critical </button> </div> </div> </div>
* { box-sizing: border-box; } html, body { margin: 0; min-height: 100%; font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; } body { background: radial-gradient( circle at 50% 20%, #1e2636, #141a27 45%, #0a0e16 85% ); color: white; } /* PAGE */ .meter-page { min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 30px; } /* CARD */ .meter-card { width: min(760px, 96vw); padding: 20px 25px 30px; border: 1px solid rgba(255,255,255,.08); border-radius: 26px; background: linear-gradient( 145deg, rgba(30,38,54,.92), rgba(14,19,29,.96) ); box-shadow: 0 35px 90px rgba(0,0,0,.45); overflow: hidden; } /* GAUGE */ .gauge-wrap { position: relative; width: min(650px, 100%); margin: 0 auto; padding-bottom: 135px; } .gauge { display: block; width: 100%; height: auto; overflow: visible; } /* ARC */ .arc-shadow { fill: none; stroke: rgba(255,255,255,.06); stroke-width: 29; stroke-linecap: round; } .arc { fill: none; stroke: url(#arcGradient); stroke-width: 19; stroke-linecap: round; filter: url(#arcGlow); } /* TICKS */ .tick-line { stroke: rgba(255,255,255,.34); stroke-width: 3; } .tick-line.major { stroke: rgba(255,255,255,.88); stroke-width: 5; } /* NUMBERS */ .tick-text { fill: rgba(255,255,255,.52); font-size: 14px; text-anchor: middle; dominant-baseline: middle; font-weight: 500; } /* NEEDLE */ #needleGroup { transform-origin: 260px 255px; transform: rotate(-90deg); } .needle { stroke: #f8fafc; stroke-width: 7; stroke-linecap: round; filter: url(#needleGlow); } /* HUB */ .hub-shadow { fill: rgba(0,0,0,.55); stroke: rgba(255,255,255,.12); stroke-width: 6; } .hub { fill: #10151f; stroke: rgba(255,255,255,.2); stroke-width: 2; } .hub-center { fill: #f8fafc; filter: drop-shadow( 0 0 8px rgba(255,255,255,.6) ); } /* VALUE */ .reading { position: absolute; left: 50%; bottom: 15px; transform: translateX(-50%); display: flex; flex-direction: column; align-items: center; width: 100%; pointer-events: none; } .reading-number { display: flex; align-items: baseline; justify-content: center; line-height: 1; white-space: nowrap; } .reading-number span { min-width: 150px; text-align: right; font-size: clamp(80px, 14vw, 118px); font-weight: 250; letter-spacing: -8px; color: #f8fafc; text-shadow: 0 6px 20px rgba(0,0,0,.35); } .reading-number small { margin-left: 12px; font-size: clamp(35px, 5vw, 52px); font-weight: 400; color: rgba(255,255,255,.55); } /* STATUS */ .status-pill { margin-top: 16px; min-width: 180px; padding: 10px 26px; border-radius: 999px; text-align: center; font-size: 14px; font-weight: 700; letter-spacing: 4px; text-transform: uppercase; border: 1px solid rgba(255,255,255,.14); } .status-pill.low { color: #7bfaa4; background: rgba(28,145,76,.22); border-color: rgba(69,230,117,.35); } .status-pill.normal { color: #d5f95d; background: rgba(113,136,32,.22); border-color: rgba(197,238,62,.35); } .status-pill.high { color: #ffc44f; background: rgba(159,103,14,.24); border-color: rgba(255,184,50,.38); } .status-pill.critical { color: #f8e9eb; background: linear-gradient( 180deg, rgba(127,14,27,.75), rgba(72,10,20,.8) ); border-color: rgba(255,42,65,.55); box-shadow: inset 0 1px 0 rgba(255,255,255,.08); } /* CONTROLS */ .controls { display: grid; grid-template-columns: repeat(4,1fr); gap: 9px; width: min(560px, 100%); margin: 15px auto 0; } .controls button { height: 42px; border: 1px solid rgba(255,255,255,.09); border-radius: 10px; background: rgba(255,255,255,.035); color: rgba(255,255,255,.5); font-size: 11px; cursor: pointer; transition: background .2s, color .2s, border-color .2s, transform .2s; } .controls button:hover { background: rgba(255,255,255,.08); color: white; transform: translateY(-1px); } .controls button.active { border-color: rgba(255,255,255,.22); background: rgba(255,255,255,.1); color: white; } /* MOBILE */ @media ( max-width: 600px ) { .meter-page { padding: 15px; } .meter-card { padding: 10px 12px 25px; } .gauge-wrap { padding-bottom: 115px; } .reading-number span { min-width: 110px; letter-spacing: -6px; } .status-pill { min-width: 145px; font-size: 11px; letter-spacing: 3px; } .controls { grid-template-columns: repeat(2,1fr); } }
const needleGroup = document.getElementById( "needleGroup" ); const valueDisplay = document.getElementById( "value" ); const labelDisplay = document.getElementById( "meterLabel" ); const ticksGroup = document.getElementById( "ticks" ); const buttons = document.querySelectorAll( ".controls button" ); let currentValue = 95; /* --------------------------------- POLAR POSITION ---------------------------------- */ function polarPoint( cx, cy, radius, angleDegrees ) { const radians = angleDegrees * Math.PI / 180; return { x: cx + Math.cos(radians) * radius, y: cy + Math.sin(radians) * radius }; } /* --------------------------------- CREATE TICKS ---------------------------------- */ for ( let i = 0; i <= 20; i++ ) { const value = i * 5; const angle = 180 + ( value / 100 ) * 180; const major = value % 20 === 0; /* Outer ticks are close to the colored arc. */ const outer = polarPoint( 260, 255, 165, angle ); /* Major ticks are longer. */ const inner = polarPoint( 260, 255, major ? 139 : 149, angle ); const line = document.createElementNS( "http://www.w3.org/2000/svg", "line" ); line.setAttribute( "x1", outer.x ); line.setAttribute( "y1", outer.y ); line.setAttribute( "x2", inner.x ); line.setAttribute( "y2", inner.y ); line.setAttribute( "class", major ? "tick-line major" : "tick-line" ); ticksGroup.appendChild( line ); /* ------------------------------- NUMBER LABELS -------------------------------- */ if (major) { /* Pull numbers further inward so they never collide with ticks. */ const textPoint = polarPoint( 260, 255, 113, angle ); const text = document.createElementNS( "http://www.w3.org/2000/svg", "text" ); text.setAttribute( "x", textPoint.x ); text.setAttribute( "y", textPoint.y ); text.setAttribute( "class", "tick-text" ); text.textContent = value; ticksGroup.appendChild( text ); } } /* --------------------------------- VALUE TO NEEDLE ANGLE ---------------------------------- */ function valueToAngle( value ) { return ( -90 + ( value / 100 ) * 180 ); } /* --------------------------------- STATUS ---------------------------------- */ function getStatus( value ) { if (value < 30) { return { label: "Low", className: "low" }; } if (value < 60) { return { label: "Normal", className: "normal" }; } if (value < 85) { return { label: "High", className: "high" }; } return { label: "Critical", className: "critical" }; } /* --------------------------------- SET STATUS ---------------------------------- */ function updateStatus( value ) { const status = getStatus( value ); labelDisplay.textContent = status.label; labelDisplay.className = "status-pill " + status.className; } /* --------------------------------- ANIMATE METER ---------------------------------- */ function setMeter( newValue ) { newValue = Math.max( 0, Math.min( 100, newValue ) ); const startValue = currentValue; const duration = 950; const startTime = performance.now(); function animate( now ) { const progress = Math.min( ( now - startTime ) / duration, 1 ); /* Smooth ease-out motion. */ const eased = 1 - Math.pow( 1 - progress, 4 ); const value = startValue + ( newValue - startValue ) * eased; const angle = valueToAngle( value ); needleGroup.style.transform = "rotate(" + angle + "deg)"; valueDisplay.textContent = Math.round( value ); updateStatus( value ); if ( progress < 1 ) { requestAnimationFrame( animate ); } else { currentValue = newValue; } } requestAnimationFrame( animate ); } /* --------------------------------- BUTTON CONTROLS ---------------------------------- */ buttons.forEach( function(button) { button.addEventListener( "click", function() { buttons.forEach( function(item) { item.classList.remove( "active" ); } ); button.classList.add( "active" ); setMeter( Number( button.dataset.value ) ); } ); } ); /* --------------------------------- INITIAL STATE ---------------------------------- */ needleGroup.style.transform = "rotate(" + valueToAngle( currentValue ) + "deg)"; updateStatus( currentValue );
terminal
JavaScript Console
Preview
Clear
close
›
Run