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>Animated signal generator</title> </head> <body> <!-- Start your code here --> <div class="app"> <header class="topbar"> <div class="brand"> <div class="brand-icon">〰</div> <div> <h1>Signal Studio</h1> <p>Interactive waveform laboratory</p> </div> </div> <button id="playBtn" class="play-btn"> <span id="playIcon">Ⅱ</span> <span id="playText">Pause</span> </button> </header> <main class="layout"> <section class="visual-area"> <div class="visual-header"> <div> <span class="eyebrow">LIVE OSCILLOSCOPE</span> <h2>Waveform Explorer</h2> </div> <div class="live-status"><span></span> LIVE</div> </div> <div class="canvas-wrap"> <canvas id="waveCanvas"></canvas> <div class="canvas-label">AMPLITUDE / TIME</div> <div class="canvas-bottom">SIGNAL STUDIO <span>v1.0</span></div> </div> <div class="metrics"> <div class="metric"> <span class="metric-icon cyan">〰</span> <div> <small>Frequency</small> <strong id="metricFreq">2.00 Hz</strong> </div> </div> <div class="metric"> <span class="metric-icon purple">↕</span> <div> <small>Amplitude</small> <strong id="metricAmp">1.00</strong> </div> </div> <div class="metric"> <span class="metric-icon blue">◷</span> <div> <small>Phase</small> <strong id="metricPhase">0°</strong> </div> </div> <div class="metric"> <span class="metric-icon green">≋</span> <div> <small>Wave cycles</small> <strong id="metricCycles">3</strong> </div> </div> </div> </section> <aside class="control-panel"> <div class="panel-heading"> <span class="settings-icon">⚙</span> <h2>Controls</h2> </div> <section class="control-section"> <label class="section-label">Wave Type</label> <div class="wave-buttons"> <button class="wave-btn active" data-wave="sine">Sine</button> <button class="wave-btn" data-wave="square">Square</button> <button class="wave-btn" data-wave="triangle">Triangle</button> <button class="wave-btn" data-wave="sawtooth">Sawtooth</button> </div> </section> <section class="sliders-section"> <div class="slider-control"> <div class="slider-heading"> <label for="frequency">Frequency</label> <output id="frequencyValue">2.00 Hz</output> </div> <input type="range" id="frequency" min="0.2" max="8" step="0.1" value="2"> </div> <div class="slider-control"> <div class="slider-heading"> <label for="amplitude">Amplitude</label> <output id="amplitudeValue">1.00</output> </div> <input type="range" id="amplitude" min="0.1" max="1.8" step="0.05" value="1"> </div> <div class="slider-control"> <div class="slider-heading"> <label for="phase">Phase</label> <output id="phaseValue">0°</output> </div> <input type="range" id="phase" min="0" max="360" step="1" value="0"> </div> <div class="slider-control"> <div class="slider-heading"> <label for="cycles">Wave cycles</label> <output id="cyclesValue">3</output> </div> <input type="range" id="cycles" min="1" max="10" step="1" value="3"> </div> <div class="slider-control"> <div class="slider-heading"> <label for="speed">Animation speed</label> <output id="speedValue">1.0×</output> </div> <input type="range" id="speed" min="0" max="3" step="0.1" value="1"> </div> </section> <section class="color-section"> <label class="section-label">Color Theme</label> <div class="color-options"> <button class="color-btn active" data-color="multi" title="Multicolor"></button> <button class="color-btn blue" data-color="blue" title="Blue"></button> <button class="color-btn purple" data-color="purple" title="Purple"></button> <button class="color-btn green" data-color="green" title="Green"></button> <button class="color-btn orange" data-color="orange" title="Orange"></button> <button class="color-btn pink" data-color="pink" title="Pink"></button> </div> </section> <button id="resetBtn" class="reset-btn">↻ Reset settings</button> </aside> </main> </div> <!-- End your code here --> </body> </html>
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Space+Mono:wght@400;700&display=swap'); * { box-sizing: border-box; } body { margin: 0; min-height: 100vh; background: #070914; color: #edf2ff; font-family: Inter, sans-serif; } button { font: inherit; cursor: pointer; } .app { max-width: 1600px; margin: auto; padding: 24px; } .topbar { display: flex; align-items: center; justify-content: space-between; margin-bottom: 24px; } .brand { display: flex; align-items: center; gap: 16px; } .brand-icon { font-size: 48px; color: #a76aff; text-shadow: 0 0 25px #a76aff; } h1 { margin: 0; font-size: 27px; letter-spacing: -1px; } .brand p { margin: 5px 0 0; color: #7f8ba8; font-size: 13px; } .play-btn { border: 1px solid #274e42; background: #0b201c; color: #6fffc2; padding: 12px 20px; border-radius: 12px; font-weight: 600; } .layout { display: grid; grid-template-columns: minmax(0, 1fr) 330px; gap: 22px; } .visual-area, .control-panel { background: linear-gradient(145deg, #101426, #090c18); border: 1px solid #252d49; border-radius: 20px; padding: 22px; } .visual-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 18px; } .eyebrow { color: #7786aa; font: 11px 'Space Mono', monospace; letter-spacing: 2px; } .visual-header h2 { margin: 7px 0 0; font-size: 22px; } .live-status { color: #75ffbc; font: 12px 'Space Mono', monospace; } .live-status span { display: inline-block; width: 8px; height: 8px; background: #64ffb5; border-radius: 50%; margin-right: 6px; box-shadow: 0 0 12px #64ffb5; } .canvas-wrap { height: 450px; position: relative; overflow: hidden; border: 1px solid #202a45; border-radius: 12px; background: #050813; } canvas { width: 100%; height: 100%; display: block; } .canvas-label, .canvas-bottom { position: absolute; color: #52617f; font: 10px 'Space Mono', monospace; letter-spacing: 1px; pointer-events: none; } .canvas-label { top: 15px; left: 15px; } .canvas-bottom { bottom: 13px; left: 15px; right: 15px; display: flex; justify-content: space-between; } .metrics { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; margin-top: 18px; } .metric { display: flex; align-items: center; gap: 12px; padding: 17px 12px; border: 1px solid #252e4b; background: #0c1020; border-radius: 12px; } .metric-icon { font-size: 26px; } .cyan { color: #35eaff; } .purple { color: #b58aff; } .blue { color: #58baff; } .green { color: #76ffb1; } .metric small { display: block; color: #8490aa; font-size: 11px; margin-bottom: 5px; } .metric strong { font: 700 17px 'Space Mono', monospace; } .control-panel { padding: 20px; } .panel-heading { display: flex; align-items: center; gap: 12px; margin-bottom: 24px; } .panel-heading h2 { margin: 0; font-size: 22px; } .settings-icon { color: #a5b6ff; font-size: 26px; } .control-section, .sliders-section, .color-section { border: 1px solid #202944; background: #0a0e1b; border-radius: 14px; padding: 16px; margin-bottom: 16px; } .section-label { display: block; color: #c8d2e9; font-size: 13px; margin-bottom: 14px; } .wave-buttons { display: grid; grid-template-columns: repeat(2, 1fr); gap: 7px; } .wave-btn { border: 1px solid #27324e; border-radius: 8px; padding: 10px 5px; color: #9aa8c5; background: #11182a; font-size: 12px; transition: 0.2s; } .wave-btn.active { color: white; background: linear-gradient(135deg, #6659ff, #9d56ed); border-color: #8b72ff; box-shadow: 0 0 18px #6954ff33; } .slider-control { margin-bottom: 24px; } .slider-control:last-child { margin-bottom: 4px; } .slider-heading { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; font-size: 13px; } .slider-heading output { color: #e6eaff; font: 12px 'Space Mono', monospace; } input[type="range"] { width: 100%; height: 6px; appearance: none; background: #27314b; border-radius: 10px; outline: none; cursor: pointer; } input[type="range"]::-webkit-slider-thumb { appearance: none; width: 16px; height: 16px; background: #fff; border: 4px solid #a56cff; border-radius: 50%; box-shadow: 0 0 12px #a56cff88; } #amplitude::-webkit-slider-thumb { border-color: #4cf4e8; } #phase::-webkit-slider-thumb { border-color: #55bfff; } #speed::-webkit-slider-thumb { border-color: #4cf4e8; } .color-options { display: flex; justify-content: space-between; gap: 8px; } .color-btn { width: 30px; height: 30px; border: 2px solid transparent; border-radius: 50%; background: conic-gradient(red, yellow, lime, cyan, blue, magenta, red); } .color-btn.blue { background: #3269ff; } .color-btn.purple { background: #9b4dff; } .color-btn.green { background: #4bdf70; } .color-btn.orange { background: #ff923f; } .color-btn.pink { background: linear-gradient(135deg, #ff55df, #51caff); } .color-btn.active { outline: 2px solid white; outline-offset: 3px; } .reset-btn { width: 100%; border: 1px solid #344361; background: #11182a; color: #c6d5f5; border-radius: 10px; padding: 13px; transition: 0.2s; } .reset-btn:hover { background: #1b2540; } @media (max-width: 950px) { .layout { grid-template-columns: 1fr; } .control-panel { order: 2; } } @media (max-width: 600px) { .app { padding: 10px; } .visual-area, .control-panel { padding: 14px; } .canvas-wrap { height: 300px; } .metrics { grid-template-columns: repeat(2, 1fr); } h1 { font-size: 20px; } }
const canvas = document.getElementById("waveCanvas"); const ctx = canvas.getContext("2d"); const controls = { frequency: document.getElementById("frequency"), amplitude: document.getElementById("amplitude"), phase: document.getElementById("phase"), cycles: document.getElementById("cycles"), speed: document.getElementById("speed") }; const outputs = { frequency: document.getElementById("frequencyValue"), amplitude: document.getElementById("amplitudeValue"), phase: document.getElementById("phaseValue"), cycles: document.getElementById("cyclesValue"), speed: document.getElementById("speedValue") }; let waveType = "sine"; let colorTheme = "multi"; let paused = false; let elapsed = 0; let lastTime = 0; const colors = { multi: ["#35eaff", "#d64cff", "#7cff82"], blue: ["#4a8dff", "#32d8ff", "#8aafff"], purple: ["#b16cff", "#e65aff", "#8c75ff"], green: ["#5dff9a", "#a0ff54", "#36e7b0"], orange: ["#ff9a45", "#ff5e55", "#ffd166"], pink: ["#ff56df", "#8c63ff", "#45dfff"] }; function resizeCanvas() { const rect = canvas.getBoundingClientRect(); const dpr = window.devicePixelRatio || 1; canvas.width = rect.width * dpr; canvas.height = rect.height * dpr; ctx.setTransform(dpr, 0, 0, dpr, 0, 0); } window.addEventListener("resize", resizeCanvas); resizeCanvas(); function getValue(type, angle) { switch (type) { case "square": return Math.sin(angle) >= 0 ? 1 : -1; case "triangle": return (2 / Math.PI) * Math.asin(Math.sin(angle)); case "sawtooth": return 2 * ((angle / (2 * Math.PI)) % 1) - 1; default: return Math.sin(angle); } } function drawGrid(w, h) { ctx.strokeStyle = "rgba(75, 100, 150, 0.16)"; ctx.lineWidth = 1; const spacing = 50; for (let x = 0; x < w; x += spacing) { ctx.beginPath(); ctx.moveTo(x, 0); ctx.lineTo(x, h); ctx.stroke(); } for (let y = 0; y < h; y += spacing) { ctx.beginPath(); ctx.moveTo(0, y); ctx.lineTo(w, y); ctx.stroke(); } ctx.strokeStyle = "rgba(150, 170, 210, 0.25)"; ctx.beginPath(); ctx.moveTo(0, h / 2); ctx.lineTo(w, h / 2); ctx.stroke(); } function drawWave(w, h, color, phaseOffset, reflection = false) { const frequency = Number(controls.frequency.value); const amplitude = Number(controls.amplitude.value); const cycles = Number(controls.cycles.value); const phase = Number(controls.phase.value) * Math.PI / 180; const centerY = h / 2; const maxAmplitude = h * 0.34 * amplitude; ctx.save(); if (reflection) { ctx.globalAlpha = 0.13; ctx.translate(0, h); ctx.scale(1, -1); } ctx.beginPath(); for (let x = 0; x <= w; x++) { const progress = x / w; const angle = progress * cycles * 2 * Math.PI + phase + elapsed * frequency * 0.65 + phaseOffset; const value = getValue(waveType, angle); const y = centerY - value * maxAmplitude; if (x === 0) ctx.moveTo(x, y); else ctx.lineTo(x, y); } ctx.strokeStyle = color; ctx.lineWidth = reflection ? 2 : 3; ctx.shadowColor = color; ctx.shadowBlur = reflection ? 18 : 20; ctx.stroke(); ctx.restore(); } function draw(timestamp) { if (!lastTime) lastTime = timestamp; const delta = (timestamp - lastTime) / 1000; lastTime = timestamp; if (!paused) { elapsed += delta * Number(controls.speed.value); } const w = canvas.clientWidth; const h = canvas.clientHeight; ctx.clearRect(0, 0, w, h); drawGrid(w, h); const palette = colors[colorTheme]; // Reflection first drawWave(w, h, palette[0], 0, true); // Draw several waveforms drawWave(w, h, palette[0], 0); drawWave(w, h, palette[1], 1.4); drawWave(w, h, palette[2], 2.8); requestAnimationFrame(draw); } requestAnimationFrame(draw); function updateUI() { outputs.frequency.textContent = Number(controls.frequency.value).toFixed(2) + " Hz"; outputs.amplitude.textContent = Number(controls.amplitude.value).toFixed(2); outputs.phase.textContent = controls.phase.value + "°"; outputs.cycles.textContent = controls.cycles.value; outputs.speed.textContent = Number(controls.speed.value).toFixed(1) + "×"; document.getElementById("metricFreq").textContent = Number(controls.frequency.value).toFixed(2) + " Hz"; document.getElementById("metricAmp").textContent = Number(controls.amplitude.value).toFixed(2); document.getElementById("metricPhase").textContent = controls.phase.value + "°"; document.getElementById("metricCycles").textContent = controls.cycles.value; } Object.values(controls).forEach(input => { input.addEventListener("input", updateUI); }); document.querySelectorAll(".wave-btn").forEach(button => { button.addEventListener("click", () => { document.querySelectorAll(".wave-btn").forEach(b => b.classList.remove("active") ); button.classList.add("active"); waveType = button.dataset.wave; }); }); document.querySelectorAll(".color-btn").forEach(button => { button.addEventListener("click", () => { document.querySelectorAll(".color-btn").forEach(b => b.classList.remove("active") ); button.classList.add("active"); colorTheme = button.dataset.color; }); }); document.getElementById("playBtn").addEventListener("click", () => { paused = !paused; document.getElementById("playIcon").textContent = paused ? "▶" : "Ⅱ"; document.getElementById("playText").textContent = paused ? "Resume" : "Pause"; }); document.getElementById("resetBtn").addEventListener("click", () => { controls.frequency.value = 2; controls.amplitude.value = 1; controls.phase.value = 0; controls.cycles.value = 3; controls.speed.value = 1; waveType = "sine"; colorTheme = "multi"; paused = false; elapsed = 0; document.querySelectorAll(".wave-btn").forEach(button => { button.classList.toggle("active", button.dataset.wave === "sine"); }); document.querySelectorAll(".color-btn").forEach(button => { button.classList.toggle("active", button.dataset.color === "multi"); }); document.getElementById("playIcon").textContent = "Ⅱ"; document.getElementById("playText").textContent = "Pause"; updateUI(); }); updateUI();
terminal
JavaScript Console
Preview
Clear
close
›
Run