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>Tic tac toe demo</title> </head> <body> <!-- Start your code here --> <div class="game-shell"> <div class="game-card"> <div class="top-bar"> <div> <span class="eyebrow">CLASSIC GAME</span> <h1>Tic Tac Toe</h1> </div> <button id="resetScores" class="ghost-btn"> Reset score </button> </div> <div class="scoreboard"> <div class="score-box active" id="scoreXBox"> <span class="player-symbol x">X</span> <div> <small>PLAYER X</small> <strong id="scoreX">0</strong> </div> </div> <div class="score-box"> <span class="draw-symbol">—</span> <div> <small>DRAWS</small> <strong id="scoreDraw">0</strong> </div> </div> <div class="score-box" id="scoreOBox"> <span class="player-symbol o">O</span> <div> <small>PLAYER O</small> <strong id="scoreO">0</strong> </div> </div> </div> <div class="status-row"> <div class="turn-indicator"> <span id="turnSymbol" class="turn-symbol x">X</span> <span id="statusText">Player X's turn</span> </div> <button id="newRound" class="round-btn"> New round </button> </div> <div class="board" id="board"> <button class="cell" data-index="0"></button> <button class="cell" data-index="1"></button> <button class="cell" data-index="2"></button> <button class="cell" data-index="3"></button> <button class="cell" data-index="4"></button> <button class="cell" data-index="5"></button> <button class="cell" data-index="6"></button> <button class="cell" data-index="7"></button> <button class="cell" data-index="8"></button> </div> <div class="footer-note"> First player to connect three wins the round. </div> </div> </div> <!-- End your code here --> </body> </html>
* { box-sizing: border-box; } :root { --bg: #07090d; --card: rgba(18, 21, 28, 0.88); --border: rgba(255, 255, 255, 0.08); --text: #f5f7fb; --muted: rgba(255, 255, 255, 0.4); --x: #6c8cff; --o: #38d7bf; } html, body { margin: 0; min-height: 100%; font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; background: radial-gradient( circle at 20% 15%, rgba(89, 83, 255, 0.2), transparent 35% ), radial-gradient( circle at 80% 80%, rgba(40, 210, 190, 0.13), transparent 30% ), var(--bg); color: var(--text); } button { font: inherit; } /* PAGE */ .game-shell { min-height: 100vh; display: grid; place-items: center; padding: 28px; } /* CARD */ .game-card { width: min(560px, 95vw); padding: 26px; border: 1px solid var(--border); border-radius: 28px; background: linear-gradient( 145deg, rgba(255,255,255,.05), rgba(255,255,255,.02) ); backdrop-filter: blur(20px); box-shadow: 0 35px 90px rgba(0,0,0,.45); } /* HEADER */ .top-bar { display: flex; align-items: flex-start; justify-content: space-between; gap: 20px; } .eyebrow { display: block; margin-bottom: 6px; font-size: 9px; font-weight: 700; letter-spacing: 2.3px; color: var(--muted); } .top-bar h1 { margin: 0; font-size: 27px; letter-spacing: -1px; } .ghost-btn { height: 34px; padding: 0 12px; border: 1px solid var(--border); border-radius: 8px; background: rgba(255,255,255,.035); color: rgba(255,255,255,.58); font-size: 10px; cursor: pointer; transition: .18s; } .ghost-btn:hover { background: rgba(255,255,255,.08); color: white; } /* SCOREBOARD */ .scoreboard { display: grid; grid-template-columns: repeat(3, 1fr); gap: 9px; margin-top: 24px; } .score-box { display: flex; align-items: center; gap: 10px; padding: 13px; border: 1px solid var(--border); border-radius: 14px; background: rgba(255,255,255,.025); transition: .2s; } .score-box.active { background: rgba(108,140,255,.08); border-color: rgba(108,140,255,.35); } .score-box small { display: block; color: var(--muted); font-size: 8px; font-weight: 700; letter-spacing: 1px; } .score-box strong { display: block; margin-top: 3px; font-size: 18px; } .player-symbol { font-size: 25px; font-weight: 700; } .player-symbol.x, .turn-symbol.x { color: var(--x); } .player-symbol.o, .turn-symbol.o { color: var(--o); } .draw-symbol { color: rgba(255,255,255,.35); font-size: 25px; } /* STATUS */ .status-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin: 22px 0 14px; } .turn-indicator { display: flex; align-items: center; gap: 8px; color: rgba(255,255,255,.6); font-size: 11px; } .turn-symbol { font-size: 18px; font-weight: 700; } .round-btn { height: 34px; padding: 0 13px; border: 0; border-radius: 8px; background: #f4f5f8; color: #111318; font-size: 10px; font-weight: 600; cursor: pointer; transition: transform .18s, background .18s; } .round-btn:hover { transform: translateY(-1px); background: white; } /* BOARD */ .board { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; } .cell { position: relative; aspect-ratio: 1; border: 1px solid rgba(255,255,255,.08); border-radius: 18px; background: linear-gradient( 145deg, rgba(255,255,255,.045), rgba(255,255,255,.018) ); color: white; cursor: pointer; overflow: hidden; transition: transform .16s, background .16s, border-color .16s; } .cell:hover:empty { transform: translateY(-2px); background: rgba(255,255,255,.06); border-color: rgba(255,255,255,.14); } /* X and O */ .cell.x::before, .cell.x::after { content: ""; position: absolute; left: 50%; top: 50%; width: 54%; height: 7px; border-radius: 10px; background: linear-gradient( 90deg, #7f9cff, #596ff0 ); box-shadow: 0 0 20px rgba(108,140,255,.28); } .cell.x::before { transform: translate(-50%, -50%) rotate(45deg); } .cell.x::after { transform: translate(-50%, -50%) rotate(-45deg); } .cell.o::before { content: ""; position: absolute; left: 50%; top: 50%; width: 47%; height: 47%; transform: translate(-50%, -50%); border: 7px solid var(--o); border-radius: 50%; box-shadow: 0 0 20px rgba(56,215,191,.24); } /* ENTRY ANIMATION */ .cell.played { animation: popIn .22s cubic-bezier(.2,.9,.3,1.3); } @keyframes popIn { 0% { transform: scale(.75); opacity: .2; } 100% { transform: scale(1); opacity: 1; } } /* WIN */ .cell.win { border-color: rgba(255,255,255,.3); background: rgba(255,255,255,.09); animation: winPulse .8s ease-in-out infinite alternate; } @keyframes winPulse { from { transform: scale(1); } to { transform: scale(1.035); } } /* FOOTER */ .footer-note { margin-top: 18px; text-align: center; color: rgba(255,255,255,.25); font-size: 9px; letter-spacing: .5px; } /* MOBILE */ @media ( max-width: 520px ) { .game-card { padding: 18px; } .scoreboard { gap: 6px; } .score-box { padding: 10px; } .score-box small { font-size: 7px; } .score-box strong { font-size: 16px; } .board { gap: 7px; } }
const cells = document.querySelectorAll( ".cell" ); const statusText = document.getElementById( "statusText" ); const turnSymbol = document.getElementById( "turnSymbol" ); const scoreXDisplay = document.getElementById( "scoreX" ); const scoreODisplay = document.getElementById( "scoreO" ); const scoreDrawDisplay = document.getElementById( "scoreDraw" ); const scoreXBox = document.getElementById( "scoreXBox" ); const scoreOBox = document.getElementById( "scoreOBox" ); let board = [ "", "", "", "", "", "", "", "", "" ]; let currentPlayer = "X"; let gameOver = false; let scores = { X: 0, O: 0, draw: 0 }; const winningCombos = [ [0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 3, 6], [1, 4, 7], [2, 5, 8], [0, 4, 8], [2, 4, 6] ]; /* PLAY */ cells.forEach( function(cell) { cell.addEventListener( "click", function() { const index = Number( cell.dataset.index ); if ( board[index] !== "" || gameOver ) { return; } board[index] = currentPlayer; cell.classList.add( currentPlayer .toLowerCase() ); cell.classList.add( "played" ); setTimeout( function() { cell.classList.remove( "played" ); }, 230 ); const result = checkWinner(); if (result) { finishGame( result ); return; } if ( board.every( value => value !== "" ) ) { finishDraw(); return; } currentPlayer = currentPlayer === "X" ? "O" : "X"; updateTurn(); } ); } ); /* WIN CHECK */ function checkWinner() { for ( const combo of winningCombos ) { const [a, b, c] = combo; if ( board[a] && board[a] === board[b] && board[a] === board[c] ) { return { player: board[a], combo: combo }; } } return null; } /* WIN */ function finishGame( result ) { gameOver = true; result.combo.forEach( function(index) { cells[index] .classList .add( "win" ); } ); scores[result.player]++; updateScores(); statusText.textContent = "Player " + result.player + " wins!"; turnSymbol.textContent = result.player; turnSymbol.className = "turn-symbol " + result.player .toLowerCase(); } /* DRAW */ function finishDraw() { gameOver = true; scores.draw++; updateScores(); statusText.textContent = "It's a draw"; turnSymbol.textContent = "—"; turnSymbol.className = "turn-symbol"; } /* UPDATE TURN */ function updateTurn() { statusText.textContent = "Player " + currentPlayer + "'s turn"; turnSymbol.textContent = currentPlayer; turnSymbol.className = "turn-symbol " + currentPlayer .toLowerCase(); scoreXBox.classList.toggle( "active", currentPlayer === "X" ); scoreOBox.classList.toggle( "active", currentPlayer === "O" ); } /* SCORES */ function updateScores() { scoreXDisplay.textContent = scores.X; scoreODisplay.textContent = scores.O; scoreDrawDisplay.textContent = scores.draw; } /* NEW ROUND */ function newRound() { board = [ "", "", "", "", "", "", "", "", "" ]; gameOver = false; currentPlayer = scores.X <= scores.O ? "X" : "O"; cells.forEach( function(cell) { cell.className = "cell"; } ); updateTurn(); } document .getElementById( "newRound" ) .addEventListener( "click", newRound ); /* RESET SCORES */ document .getElementById( "resetScores" ) .addEventListener( "click", function() { scores = { X: 0, O: 0, draw: 0 }; updateScores(); newRound(); } ); /* INITIAL */ updateTurn();
terminal
JavaScript Console
Preview
Clear
close
›
Run