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
<!DOCTYPE html> <html> <head> <title>Interactive magnetic field simulator demo</title> </head> <body> <!-- Start your code here --> <div class="app"> <header class="topbar"> <div> <div class="eyebrow">INTERACTIVE EXPERIMENT</div> <h1>Magnetic Field</h1> </div> <div class="controls"> <button id="modeBtn">Attract</button> <button id="clearBtn">Clear magnets</button> </div> </header> <main id="field"> <div class="center-label"> <div class="dot"></div> <span>MOVE YOUR CURSOR</span> </div> </main> <footer> <span>MOVE — influence the particles</span> <span>CLICK — place a magnet</span> <span>SPACE — clear magnets</span> </footer> </div> <!-- End your code here --> </body> </html>
* { box-sizing: border-box; } html, body { margin: 0; width: 100%; height: 100%; overflow: hidden; } body { font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; color: #232420; background: radial-gradient( circle at 50% 40%, #ffffff 0%, #f4f3ef 42%, #e5e3dc 100% ); } button { font: inherit; } .app { width: 100%; height: 100%; display: flex; flex-direction: column; } .topbar { position: relative; z-index: 10; display: flex; align-items: center; justify-content: space-between; padding: 28px 34px 18px; background: rgba(255, 255, 255, .55); border-bottom: 1px solid rgba(0, 0, 0, .06); backdrop-filter: blur(10px); } .eyebrow { font-size: 9px; font-weight: 700; letter-spacing: 3px; color: #96978f; } h1 { margin: 5px 0 0; font-size: 30px; line-height: 1; font-weight: 700; letter-spacing: -1.2px; } .controls { display: flex; gap: 8px; } .controls button { padding: 9px 13px; border: 1px solid #d2d1ca; border-radius: 8px; background: rgba(255,255,255,.8); color: #44453f; font-size: 11px; font-weight: 600; cursor: pointer; transition: transform .15s ease, box-shadow .15s ease, background .15s ease; } .controls button:hover { background: #fff; transform: translateY(-1px); box-shadow: 0 5px 14px rgba(0,0,0,.08); } .controls button:active { transform: translateY(1px); } #modeBtn { min-width: 82px; } /* Field */ #field { position: relative; flex: 1; overflow: hidden; cursor: crosshair; } /* subtle grid */ #field::before { content: ""; position: absolute; inset: 0; background-image: linear-gradient( rgba(0,0,0,.028) 1px, transparent 1px ), linear-gradient( 90deg, rgba(0,0,0,.028) 1px, transparent 1px ); background-size: 40px 40px; pointer-events: none; } /* center instruction */ .center-label { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); display: flex; align-items: center; gap: 8px; color: rgba(70,70,65,.35); font-size: 9px; letter-spacing: 2.5px; pointer-events: none; transition: opacity .4s ease, transform .4s ease; } .center-label.hidden { opacity: 0; transform: translate(-50%, -50%) scale(.96); } .dot { width: 6px; height: 6px; border-radius: 50%; border: 1px solid rgba(80,80,75,.4); } /* particles */ .particle { position: absolute; width: 3px; height: 3px; border-radius: 50%; background: #70716b; pointer-events: none; will-change: transform; box-shadow: 0 0 2px rgba(0,0,0,.15); } /* magnets */ .magnet { position: absolute; width: 20px; height: 20px; margin-left: -10px; margin-top: -10px; border-radius: 50%; pointer-events: none; border: 1px solid rgba(60,60,55,.35); background: radial-gradient( circle at 35% 30%, #ffffff, #d7d6d0 62%, #b3b2aa ); box-shadow: 0 4px 12px rgba(0,0,0,.12); } .magnet::after { content: ""; position: absolute; inset: -9px; border-radius: 50%; border: 1px solid rgba(70,70,65,.12); animation: pulse 1.8s ease-in-out infinite; } .magnet.repel { background: radial-gradient( circle at 35% 30%, #ffffff, #ddd4cb 60%, #b9a99a ); } @keyframes pulse { 0%, 100% { transform: scale(.92); opacity: .25; } 50% { transform: scale(1.08); opacity: .65; } } footer { position: relative; z-index: 10; display: flex; justify-content: center; gap: 34px; padding: 12px 20px 15px; color: #9a9a93; font-size: 9px; letter-spacing: 1.2px; background: rgba(255,255,255,.55); border-top: 1px solid rgba(0,0,0,.05); } @media (max-width: 700px) { .topbar { padding: 20px 18px 14px; } h1 { font-size: 24px; } footer { gap: 12px; flex-wrap: wrap; } .controls button { padding: 8px 10px; } }
const field = document.getElementById("field"); const modeBtn = document.getElementById("modeBtn"); const clearBtn = document.getElementById("clearBtn"); const centerLabel = document.querySelector(".center-label"); const particles = []; const magnets = []; let mode = "attract"; let mouse = { x: 0, y: 0, active: false }; const PARTICLE_COUNT = 850; /* ---------------------------------- Create particles ---------------------------------- */ function createParticles() { for (let i = 0; i < PARTICLE_COUNT; i++) { const el = document.createElement("div"); el.className = "particle"; field.appendChild(el); const w = field.clientWidth; const h = field.clientHeight; const angle = Math.random() * Math.PI * 2; const radius = Math.sqrt(Math.random()) * Math.min(w, h) * 0.48; const x = w / 2 + Math.cos(angle) * radius; const y = h / 2 + Math.sin(angle) * radius; particles.push({ el, x, y, vx: (Math.random() - .5) * .12, vy: (Math.random() - .5) * .12, homeX: x, homeY: y, seed: Math.random() * 1000 }); } } createParticles(); /* ---------------------------------- Mouse ---------------------------------- */ field.addEventListener("pointermove", e => { const rect = field.getBoundingClientRect(); mouse.x = e.clientX - rect.left; mouse.y = e.clientY - rect.top; mouse.active = true; centerLabel.classList.add("hidden"); }); field.addEventListener("pointerleave", () => { mouse.active = false; }); /* ---------------------------------- Add magnet ---------------------------------- */ field.addEventListener("click", e => { const rect = field.getBoundingClientRect(); const x = e.clientX - rect.left; const y = e.clientY - rect.top; addMagnet(x, y); }); function addMagnet(x, y) { const el = document.createElement("div"); el.className = "magnet" + (mode === "repel" ? " repel" : ""); el.style.left = x + "px"; el.style.top = y + "px"; field.appendChild(el); magnets.push({ el, x, y, mode }); } /* ---------------------------------- Clear ---------------------------------- */ function clearMagnets() { magnets.forEach(m => { m.el.remove(); }); magnets.length = 0; } /* ---------------------------------- Mode ---------------------------------- */ modeBtn.addEventListener("click", () => { mode = mode === "attract" ? "repel" : "attract"; modeBtn.textContent = mode === "attract" ? "Attract" : "Repel"; }); /* ---------------------------------- Keyboard ---------------------------------- */ document.addEventListener("keydown", e => { if (e.code === "Space") { e.preventDefault(); clearMagnets(); } }); /* ---------------------------------- Physics ---------------------------------- */ function update() { const width = field.clientWidth; const height = field.clientHeight; for (const p of particles) { let forceX = 0; let forceY = 0; /* Mouse magnet */ if (mouse.active) { const dx = mouse.x - p.x; const dy = mouse.y - p.y; const distanceSq = dx * dx + dy * dy; const distance = Math.sqrt(distanceSq) + 0.001; const influence = Math.min( 1, 42000 / (distanceSq + 400) ); const direction = mode === "attract" ? 1 : -1; forceX += (dx / distance) * influence * direction * 0.42; forceY += (dy / distance) * influence * direction * 0.42; } /* Clicked magnets */ for (const magnet of magnets) { const dx = magnet.x - p.x; const dy = magnet.y - p.y; const distanceSq = dx * dx + dy * dy; const distance = Math.sqrt(distanceSq) + 0.001; const influence = Math.min( 1, 18000 / (distanceSq + 500) ); const direction = magnet.mode === "attract" ? 1 : -1; forceX += (dx / distance) * influence * direction * 0.22; forceY += (dy / distance) * influence * direction * 0.22; } /* Gentle wandering */ forceX += Math.sin( p.y * .012 + p.seed ) * .002; forceY += Math.cos( p.x * .010 + p.seed ) * .002; /* Spring back toward original position when nothing is influencing */ if (!mouse.active && magnets.length === 0) { forceX += (p.homeX - p.x) * .0005; forceY += (p.homeY - p.y) * .0005; } /* Velocity */ p.vx += forceX; p.vy += forceY; p.vx *= .92; p.vy *= .92; p.x += p.vx; p.y += p.vy; /* Soft boundaries */ if (p.x < 0) { p.x = 0; p.vx *= -.5; } if (p.x > width) { p.x = width; p.vx *= -.5; } if (p.y < 0) { p.y = 0; p.vy *= -.5; } if (p.y > height) { p.y = height; p.vy *= -.5; } p.el.style.transform = `translate3d(${p.x}px, ${p.y}px, 0)`; } requestAnimationFrame(update); } update(); /* ---------------------------------- Initial magnets ---------------------------------- */ /* Two very subtle magnets make the scene feel alive immediately. */ setTimeout(() => { addMagnet( field.clientWidth * .32, field.clientHeight * .52 ); addMagnet( field.clientWidth * .68, field.clientHeight * .48 ); }, 250);
terminal
JavaScript Console
Preview
Clear
close
›
Run