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
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Gravity Playground</title> <link rel="stylesheet" href="style.css"> </head> <body> <div class="ui"> <div class="title">GRAVITY</div> <div class="subtitle">MOVE YOUR MOUSE • CLICK TO CREATE A GRAVITY WELL</div> <button id="reset">RESET</button> </div> <canvas id="canvas"></canvas> <script src="script.js"></script> </body> </html>
* { box-sizing: border-box; } html, body { margin: 0; width: 100%; height: 100%; overflow: hidden; } body { background: radial-gradient( circle at center, #19213a 0%, #090b14 55%, #03040a 100% ); font-family: Inter, Arial, sans-serif; } canvas { position: fixed; inset: 0; display: block; } .ui { position: fixed; top: 32px; left: 40px; z-index: 10; color: white; pointer-events: none; } .title { font-size: 28px; font-weight: 800; letter-spacing: 6px; } .subtitle { margin-top: 8px; font-size: 10px; letter-spacing: 2px; color: rgba(255,255,255,.45); } button { pointer-events: auto; margin-top: 18px; border: 1px solid rgba(255,255,255,.18); background: rgba(255,255,255,.06); color: white; padding: 9px 16px; border-radius: 999px; cursor: pointer; font-size: 11px; letter-spacing: 2px; transition: background .2s, transform .2s; } button:hover { background: rgba(255,255,255,.14); transform: translateY(-2px); }
const canvas = document.getElementById("canvas"); const ctx = canvas.getContext("2d"); const resetButton = document.getElementById("reset"); let width; let height; let particles = []; let gravityWells = []; let mouse = { x: null, y: null, active: false }; /* ================================= COLORS ================================= */ const colors = [ "#7DD3FC", "#A78BFA", "#F472B6", "#34D399", "#FBBF24", "#FB7185" ]; /* ================================= RESIZE ================================= */ function resize() { width = canvas.width = window.innerWidth; height = canvas.height = window.innerHeight; } window.addEventListener( "resize", resize ); resize(); /* ================================= PARTICLE ================================= */ class Particle { constructor() { this.x = Math.random() * width; this.y = Math.random() * height; this.radius = Math.random() * 5 + 2; this.vx = (Math.random() - 0.5) * 2; this.vy = (Math.random() - 0.5) * 2; this.mass = this.radius * 0.8; this.color = colors[ Math.floor( Math.random() * colors.length ) ]; } update() { /* Mouse gravity */ if ( mouse.active && mouse.x !== null ) { const dx = mouse.x - this.x; const dy = mouse.y - this.y; const distance = Math.sqrt( dx * dx + dy * dy ); if (distance > 10) { const force = 0.35 / Math.max(distance, 40); this.vx += dx * force; this.vy += dy * force; } } /* Gravity wells */ gravityWells.forEach( well => { const dx = well.x - this.x; const dy = well.y - this.y; const distance = Math.sqrt( dx * dx + dy * dy ); if (distance > 15) { const force = 20 / ( distance * distance ); this.vx += dx * force; this.vy += dy * force; } } ); /* Friction */ this.vx *= 0.995; this.vy *= 0.995; /* Position */ this.x += this.vx; this.y += this.vy; /* Screen edges */ if ( this.x < 0 || this.x > width ) { this.vx *= -1; this.x = Math.max( 0, Math.min( width, this.x ) ); } if ( this.y < 0 || this.y > height ) { this.vy *= -1; this.y = Math.max( 0, Math.min( height, this.y ) ); } } draw() { /* Glow */ const glow = ctx.createRadialGradient( this.x, this.y, 0, this.x, this.y, this.radius * 5 ); glow.addColorStop( 0, this.color ); glow.addColorStop( 1, "transparent" ); ctx.beginPath(); ctx.fillStyle = glow; ctx.arc( this.x, this.y, this.radius * 5, 0, Math.PI * 2 ); ctx.fill(); /* Core */ ctx.beginPath(); ctx.fillStyle = this.color; ctx.arc( this.x, this.y, this.radius, 0, Math.PI * 2 ); ctx.fill(); } } /* ================================= CREATE PARTICLES ================================= */ function createParticles() { particles = []; for ( let i = 0; i < 120; i++ ) { particles.push( new Particle() ); } } createParticles(); /* ================================= MOUSE ================================= */ window.addEventListener( "mousemove", event => { mouse.x = event.clientX; mouse.y = event.clientY; mouse.active = true; } ); window.addEventListener( "mouseleave", () => { mouse.active = false; } ); /* ================================= CREATE GRAVITY WELL ================================= */ window.addEventListener( "click", event => { /* Ignore UI button */ if ( event.target.tagName === "BUTTON" ) { return; } gravityWells.push({ x: event.clientX, y: event.clientY, life: 240 }); } ); /* ================================= DRAW GRAVITY WELLS ================================= */ function drawGravityWells() { gravityWells.forEach( well => { const pulse = 25 + Math.sin( Date.now() * .005 ) * 5; ctx.beginPath(); ctx.strokeStyle = "rgba(255,255,255,.5)"; ctx.lineWidth = 1; ctx.arc( well.x, well.y, pulse, 0, Math.PI * 2 ); ctx.stroke(); ctx.beginPath(); ctx.fillStyle = "white"; ctx.shadowBlur = 20; ctx.shadowColor = "white"; ctx.arc( well.x, well.y, 3, 0, Math.PI * 2 ); ctx.fill(); ctx.shadowBlur = 0; } ); } /* ================================= PARTICLE CONNECTIONS ================================= */ function drawConnections() { for ( let i = 0; i < particles.length; i++ ) { for ( let j = i + 1; j < particles.length; j++ ) { const a = particles[i]; const b = particles[j]; const dx = a.x - b.x; const dy = a.y - b.y; const distance = Math.sqrt( dx * dx + dy * dy ); if (distance < 100) { const opacity = 1 - distance / 100; ctx.beginPath(); ctx.strokeStyle = `rgba(255,255,255,${opacity * .12})`; ctx.lineWidth = 1; ctx.moveTo( a.x, a.y ); ctx.lineTo( b.x, b.y ); ctx.stroke(); } } } } /* ================================= ANIMATION ================================= */ function animate() { requestAnimationFrame( animate ); ctx.clearRect( 0, 0, width, height ); /* Update particles */ particles.forEach( particle => { particle.update(); particle.draw(); } ); drawConnections(); drawGravityWells(); /* Remove expired wells */ gravityWells = gravityWells.filter( well => { well.life--; return well.life > 0; } ); } animate(); /* ================================= RESET ================================= */ resetButton.addEventListener( "click", () => { gravityWells = []; createParticles(); } );
terminal
JavaScript Console
Preview
Clear
close
›
Run