@minicode-dev/chat 0.1.11 → 0.1.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TanksLiveGameCard-DGsnMD3j.js","names":["_Fragment","useChatGames","GameSoundControls","decodeSignal","parseManualTurnConfig","encodeSignal","ChatContext","stopAllTanksLoops","startTanksSounds","handleSceneEvent","playOutcome","getTanksSoundManager","__defProp","__exportAll","target","name","all","no_symbols","PLACEHOLDER","ManualTurnDialog","dialogRef","useRef","requestRef","titleId","useId","descriptionId","errorId","json","setJson","useState","ttl","setTtl","relayOnly","setRelayOnly","error","setError","busy","setBusy","applied","setApplied","dialog","open","opener","submit","event","options","validationError","request","onApply","applyError","progress","manualTurn","onClose","bounds","Link2","X","ShieldCheck","Loader2","CheckCircle2","code","value","connectionDiagnostics","route","net","candidates","manual","connectionHint","RULES","clamp","lo","hi","n","angleDelta","b","a","createArena","x","z","r","i","createTank","id","index","validPosition","arena","radius","o","moveTank","tank","throttle","input","steer","dt","segmentCircle","dx","bx","ax","dz","bz","az","length","t","cx","cz","advanceShell","shell","first","tanks","interpolatePose","fraction","finite","idValid","createLiveMatch","selfId","game","createPeerLink","ids","initialTurnConfigured","iceServers","server","url","peerId","shells","events","time","sendAt","round","sequence","status","winner","destroyed","wasConnected","pendingResign","endReason","poses","lastPoseAt","lastPose","lastFire","seen","wantsRematch","me","other","notify","onChange","emit","send","link","e","remember","key","snapshot","reset","finish","force","fire","owner","shot","broadcast","receiveMove","data","yaw","turretYaw","speed","elapsed","previous","pose","receiveEvent","isHost","hp","validPlaying","validOver","maybeRematch","s","peerFactory","signaling","signal","text","scoped","frame","listener","previousPhase","state","resumed","next","dtMs","renderTime","remaining","hz","hit","out","config","RAD_TO_DEG","num","fallback","arenaBounds","withSize","w","d","box","arenaObstacles","eventKind","shooterOf","list","found","best","bestD","tankById","selfTank","damageLevel","alive","wrapAngle","v","createSelfTracker","last","moving","turning","moveIdle","turnIdle","hull","turret","isMoving","moveSpeed","turnSpeed","holdMs","isTurning","soundEventsFor","outcomeFor","render","createLiveScene2d","canvas","container","ctx","h","scale","ox","oz","resize","dpr","ro","nx","ny","obstacle","TanksLiveGameCard_exports","TanksLiveGameCard_default","act","type","stopInput","connectionText","prolonged","TanksLiveGameCard","rtcOptions","useContext","gameKey","suspendedRef","suspended","stage","match","renderer","view","setView","prefer2d","setPrefer2d","mode","setMode","turnOpen","setTurnOpen","waitingMs","setWaitingMs","connected","useEffect","started","timer","active","setArena","disposed","scene","createLiveScene","published","outcome","tracker","keys","session","currentUserId","clear","down","up","host","visibility","tick","now","paused","sound","nextOutcome","guest","over","configuring","connectionProblem","routeText","applyTurn","aim","rect","ground","hold","field","onMinimize","onDismiss","AlertTriangle","Settings2","Fragment","memo"],"sources":["../../src/games/tanks-live/ManualTurnDialog.jsx","../../src/games/tanks-live/net/connectionDiagnostics.js","../../src/games/tanks-live/logic/simulation.js","../../src/games/tanks-live/net/createLiveMatch.js","../../src/games/tanks-live/scene/liveView.js","../../src/games/tanks-live/scene/createLiveScene2d.js","../../src/games/tanks-live/TanksLiveGameCard.jsx"],"sourcesContent":["/* eslint-disable react/prop-types */\nimport { useEffect, useId, useRef, useState } from 'react';\nimport { CheckCircle2, Link2, Loader2, ShieldCheck, X } from 'lucide-react';\nimport { parseManualTurnConfig } from '../../net/webrtc/manualTurnConfig.js';\n\nconst PLACEHOLDER = '{\\n \"iceServers\": [{\\n \"urls\": [\"turn:turn.cloudflare.com:3478?transport=udp\"],\\n \"username\": \"usuario-temporal\",\\n \"credential\": \"credencial-temporal\"\\n }]\\n}';\n\nexport default function ManualTurnDialog({ open, onClose, onApply, manualTurn }) {\n const dialogRef = useRef(null);\n const requestRef = useRef(0);\n const titleId = useId();\n const descriptionId = useId();\n const errorId = useId();\n const [json, setJson] = useState('');\n const [ttl, setTtl] = useState('');\n const [relayOnly, setRelayOnly] = useState(false);\n const [error, setError] = useState('');\n const [busy, setBusy] = useState(false);\n const [applied, setApplied] = useState(false);\n useEffect(() => {\n const dialog = dialogRef.current;\n if (!open) {\n requestRef.current += 1;\n setJson(''); setTtl(''); setRelayOnly(false); setError(''); setBusy(false); setApplied(false);\n if (dialog?.open) dialog.close();\n return undefined;\n }\n const opener = document.activeElement;\n dialog.showModal();\n return () => {\n requestRef.current += 1;\n if (dialog.open) dialog.close();\n if (opener instanceof HTMLElement && opener.isConnected) opener.focus({ preventScroll: true });\n };\n }, [open]);\n const submit = async (event) => {\n event.preventDefault();\n if (busy || !json.trim()) return;\n setError('');\n const options = { iceTransportPolicy: relayOnly ? 'relay' : 'all', ...(ttl.trim() ? { ttlSeconds: Number(ttl) } : {}) };\n try { parseManualTurnConfig(json, options); }\n catch (validationError) { setError(validationError.message); return; }\n const request = ++requestRef.current;\n setBusy(true); setApplied(false);\n try {\n await onApply(json, options);\n if (request !== requestRef.current) return;\n setJson(''); setTtl(''); setApplied(true);\n } catch (applyError) {\n if (request === requestRef.current) setError(applyError.message || 'No se pudo compartir la configuración. Inténtalo de nuevo.');\n } finally {\n if (request === requestRef.current) setBusy(false);\n }\n };\n const progress = manualTurn?.status === 'applying' ? 'Aplicando configuración en ambos jugadores…'\n : manualTurn?.status === 'waiting_peer' ? 'Esperando al otro jugador para compartir la configuración…'\n : 'Sincronizando con el otro jugador…';\n return <dialog ref={dialogRef} className=\"tl-turn-dialog\" aria-labelledby={titleId} aria-describedby={descriptionId}\n onCancel={(event) => { event.preventDefault(); onClose(); }}\n onClick={(event) => { if (event.target === event.currentTarget) { const bounds = event.currentTarget.getBoundingClientRect(); if (event.clientX < bounds.left || event.clientX > bounds.right || event.clientY < bounds.top || event.clientY > bounds.bottom) onClose(); } }}>\n <header className=\"tl-turn-dialog__header\"><span className=\"tl-turn-dialog__icon\" aria-hidden=\"true\"><Link2 size={22} /></span><div><h2 id={titleId}>Configurar conexión alternativa</h2><p>Se comparte con el otro jugador.</p></div><button type=\"button\" className=\"tl-turn-dialog__close\" aria-label=\"Cerrar configuración de conexión\" onClick={onClose}><X size={18} /></button></header>\n <form onSubmit={submit}>\n <div className=\"tl-turn-dialog__body\">\n <p id={descriptionId}>Pega el JSON de credenciales temporales de Cloudflare TURN. Se compartirá con el otro jugador para buscar una conexión alternativa.</p>\n <label className=\"tl-turn-dialog__field\">Configuración JSON<textarea autoFocus value={json} onChange={(event) => { setJson(event.target.value); setError(''); setApplied(false); }} placeholder={PLACEHOLDER} maxLength={6000} rows={7} required={!applied} readOnly={busy} autoComplete=\"off\" autoCorrect=\"off\" autoCapitalize=\"off\" spellCheck={false} aria-invalid={Boolean(error)} aria-describedby={error ? errorId : undefined} /></label>\n <div className=\"tl-turn-dialog__privacy\"><ShieldCheck size={16} aria-hidden=\"true\" /><span>Solo credenciales temporales. No pegues tu API Token ni secretos permanentes.</span></div>\n <label className=\"tl-turn-dialog__field\">Validez restante en segundos <span className=\"tl-turn-dialog__optional\">Opcional</span><input type=\"number\" min=\"1\" max=\"172800\" step=\"1\" inputMode=\"numeric\" value={ttl} onChange={(event) => { setTtl(event.target.value); setError(''); }} disabled={busy} placeholder=\"Ej. 3600\" /><small>Déjalo vacío si no conoces la caducidad. Si dejan de funcionar, pega credenciales nuevas.</small></label>\n <label className=\"tl-turn-dialog__debug\"><input type=\"checkbox\" checked={relayOnly} onChange={(event) => setRelayOnly(event.target.checked)} disabled={busy} /><span><strong>Forzar relay para diagnóstico</strong><small>Normalmente se permite P2P. Actívalo solo para comprobar TURN.</small></span></label>\n {busy && <p className=\"tl-turn-dialog__feedback\" role=\"status\"><Loader2 size={16} className=\"tl-connection-spinner\" aria-hidden=\"true\" />{progress}</p>}\n {applied && <p className=\"tl-turn-dialog__feedback tl-turn-dialog__feedback--success\" role=\"status\"><CheckCircle2 size={17} aria-hidden=\"true\" />Configuración compartida y aplicada en ambos jugadores. La ruta utilizada se mostrará al conectar.</p>}\n {error && <p id={errorId} className=\"tl-turn-dialog__error\" role=\"alert\">{error}</p>}\n </div>\n <footer className=\"tl-turn-dialog__footer\"><button type=\"button\" onClick={onClose}>{applied ? 'Listo' : 'Cancelar'}</button><button type=\"submit\" className=\"tl-turn-dialog__apply\" disabled={busy || !json.trim()}>{busy ? <Loader2 size={16} className=\"tl-connection-spinner\" aria-hidden=\"true\" /> : <Link2 size={16} aria-hidden=\"true\" />}Aplicar y reconectar</button></footer>\n </form>\n </dialog>;\n}\n","// Never include SDP, candidate addresses, pasted JSON, passwords or TURN usernames.\nconst code = value => typeof value === 'string' && /^[a-z_]+$/.test(value) ? value : value ? 'connection_error' : null;\nexport function connectionDiagnostics(net = {}) {\n const route = net.route;\n const candidates = net.candidates ?? {};\n const manual = net.manualTurn ?? {};\n return {\n phase: net.phase ?? 'idle', ice: net.ice ?? 'new',\n connection: net.connection ?? 'new', signalingState: net.signalingState ?? 'stable', gathering: net.gathering ?? 'new',\n signaling: {\n sent: net.signals?.sent ?? 0, received: net.signals?.received ?? 0,\n sendFailures: net.signals?.sendFailures ?? 0, ignored: net.signals?.ignored ?? 0,\n invalid: net.signals?.invalid ?? 0, retransmits: net.signals?.retransmits ?? 0,\n duplicates: net.signals?.duplicates ?? 0, tooLarge: net.signals?.tooLarge ?? 0,\n },\n turnConfigured: Boolean(net.turnConfigured),\n configuration: { status: manual.status ?? 'idle', shared: Boolean(manual.shared), received: Boolean(manual.received), expiresAt: manual.expiresAt ?? null, expired: manual.expiresAt != null && manual.expiresAt <= Date.now() },\n route: route?.label ?? null,\n selectedPair: route ? { relay: Boolean(route.relay), localType: route.local ?? null, remoteType: route.remote ?? null, protocol: route.protocol ?? null, relayProtocol: route.relayProtocol ?? null } : null,\n candidates: { local: candidates.local ?? 0, remote: candidates.remote ?? 0, accepted: candidates.accepted ?? 0, rejected: candidates.rejected ?? 0, localRelay: candidates.localRelay ?? 0, remoteRelay: candidates.remoteRelay ?? 0 },\n iceErrors: (net.iceErrors ?? []).slice(-10).map(error => ({ code: Number(error.code) || 0, stage: error.stage === 'gathering' ? 'gathering' : 'remote_candidate' })),\n reconnects: net.reconnects ?? 0, restarts: net.restarts ?? 0,\n rttMs: net.rtt ?? net.statsRtt ?? null, connectionTimeMs: net.elapsedMs ?? 0,\n channels: { move: net.channels?.move ?? 'closed', events: net.channels?.events ?? 'closed' },\n movesSent: net.move?.sent ?? 0, movesReceived: net.move?.received ?? 0,\n error: code(net.error),\n };\n}\n\nexport function connectionHint(net = {}) {\n if (net.phase === 'connected') return '';\n if (net.manualTurn?.status === 'applying') return 'Aplicando la configuración de conexión alternativa.';\n if (net.manualTurn?.status === 'sharing') return 'Sincronizando la configuración con el otro jugador.';\n if (net.manualTurn?.status === 'waiting_peer') return 'Esperando al otro jugador para compartir la configuración.';\n if (net.error === 'turn_credentials_expired' || (net.manualTurn?.expiresAt != null && net.manualTurn.expiresAt <= Date.now())) return 'La validez indicada de TURN terminó. Pega credenciales temporales nuevas para reconectar.';\n if (net.signals?.sendFailures) return 'No se pudieron enviar señales por el chat. Revisa la conexión WebSocket y reintenta.';\n if (net.ice === 'checking' || net.ice === 'failed') return net.turnConfigured\n ? 'WebRTC aún no encuentra una ruta entre los jugadores. Puedes revisar o renovar la configuración TURN.'\n : 'WebRTC aún no encuentra una ruta entre los jugadores. Algunas redes necesitan un servidor TURN; puedes configurar una conexión alternativa.';\n if (net.phase === 'listening') return 'Esperando la conexión del rival. Ambos deben mantener abierta la partida y usar la misma versión del chat.';\n if (net.phase === 'failed') return 'No se pudo conectar. Revisa el diagnóstico de ambos jugadores y reintenta.';\n return 'Intercambiando señales de conexión por el chat. El combate empieza cuando conecta WebRTC.';\n}\n","// Deterministic arcade simulation. Angles are radians, forward is +x.\nexport const RULES = Object.freeze({ speed: 16, reverse: 9, turn: 1.8, acceleration: 28, radius: 2, reloadMs: 1500, shellSpeed: 60, damage: 25 });\nexport const clamp = (n, lo, hi) => Math.max(lo, Math.min(hi, n));\nexport const angleDelta = (a, b) => Math.atan2(Math.sin(b - a), Math.cos(b - a));\nexport function createArena() {\n return { size: 120, bounds: { minX: 0, maxX: 120, minZ: 0, maxZ: 120 }, obstacles: [\n [42, 35, 4], [78, 85, 4], [60, 30, 3], [60, 90, 3], [35, 65, 3], [85, 55, 3], [60, 60, 5],\n ].map(([x, z, r], i) => ({ x, z, r, kind: i % 2 ? 'tree' : 'rock' })) };\n}\nexport function createTank(id, index) { return { id: String(id), x: index ? 102 : 18, z: 60, yaw: index ? Math.PI : 0, turretYaw: index ? Math.PI : 0, speed: 0, hp: 100, alive: true, color: index ? '#d7463f' : '#54a34a' }; }\nexport function validPosition(x, z, arena, radius = RULES.radius) {\n const b = arena.bounds;\n return x >= b.minX + radius && x <= b.maxX - radius && z >= b.minZ + radius && z <= b.maxZ - radius\n && !arena.obstacles.some(o => Math.hypot(x - o.x, z - o.z) < o.r + radius);\n}\nexport function moveTank(tank, input, dt, arena) {\n if (!tank.alive) return;\n const throttle = clamp(Number(input.throttle) || 0, -1, 1), steer = clamp(Number(input.steer) || 0, -1, 1);\n const target = throttle * (throttle < 0 ? RULES.reverse : RULES.speed);\n tank.speed += clamp(target - tank.speed, -RULES.acceleration * dt, RULES.acceleration * dt);\n tank.yaw += steer * RULES.turn * dt;\n if (Number.isFinite(input.turretYaw)) tank.turretYaw = input.turretYaw;\n const x = tank.x + Math.cos(tank.yaw) * tank.speed * dt, z = tank.z + Math.sin(tank.yaw) * tank.speed * dt;\n if (validPosition(x, tank.z, arena)) tank.x = x; else tank.speed = 0;\n if (validPosition(tank.x, z, arena)) tank.z = z; else tank.speed = 0;\n}\nexport function segmentCircle(ax, az, bx, bz, cx, cz, radius) {\n const dx = bx - ax, dz = bz - az, length = dx * dx + dz * dz;\n const t = length ? clamp(((cx - ax) * dx + (cz - az) * dz) / length, 0, 1) : 0;\n return Math.hypot(ax + dx * t - cx, az + dz * t - cz) <= radius ? t : null;\n}\nexport function advanceShell(shell, dt, arena, tanks) {\n const x = shell.x + Math.cos(shell.yaw) * RULES.shellSpeed * dt, z = shell.z + Math.sin(shell.yaw) * RULES.shellSpeed * dt;\n let first = null;\n for (const o of arena.obstacles) { const t = segmentCircle(shell.x, shell.z, x, z, o.x, o.z, o.r); if (t !== null && (!first || t < first.t)) first = { t, kind: 'obstacle' }; }\n for (const tank of tanks) { if (!tank.alive || tank.id === shell.owner) continue; const t = segmentCircle(shell.x, shell.z, x, z, tank.x, tank.z, RULES.radius); if (t !== null && (!first || t < first.t)) first = { t, kind: 'tank', target: tank.id }; }\n if (first) { shell.x += (x - shell.x) * first.t; shell.z += (z - shell.z) * first.t; return first; }\n shell.x = x; shell.z = z; shell.age += dt;\n return !validPosition(x, z, { ...arena, obstacles: [] }, 0) || shell.age > 3 ? { kind: 'terrain' } : null;\n}\nexport function interpolatePose(a, b, fraction) {\n const t = clamp(fraction, 0, 1);\n return { ...b, x: a.x + (b.x - a.x) * t, z: a.z + (b.z - a.z) * t, yaw: a.yaw + angleDelta(a.yaw, b.yaw) * t, turretYaw: a.turretYaw + angleDelta(a.turretYaw, b.turretYaw) * t };\n}\n","import { decodeSignal, encodeSignal } from '../../../net/webrtc/protocol.js';\nimport { createPeerLink } from '../../../net/webrtc/createPeerLink.js';\nimport { RULES, createArena, createTank, moveTank, advanceShell, validPosition, interpolatePose } from '../logic/simulation.js';\n\nconst finite = n => typeof n === 'number' && Number.isFinite(n);\nconst idValid = id => typeof id === 'string' && id.length > 0 && id.length < 160;\nexport function createLiveMatch({ game, selfId, isHost = String(selfId) === String(game.hostId), signaling, onChange = () => {}, peerFactory = createPeerLink, iceServers, iceTransportPolicy, RTCPeerConnectionImpl } = {}) {\n selfId = String(selfId);\n const ids = [String(game.hostId), String(game.guestId)];\n if (!ids.includes(selfId) || ids[0] === ids[1]) throw new Error('Invalid live match players');\n const initialTurnConfigured = (iceServers || []).some(server => [server.urls].flat().some(url => /^turns?:/i.test(String(url))));\n const peerId = ids.find(id => id !== selfId), arena = createArena();\n let tanks = ids.map(createTank), shells = [], events = [], input = {}, time = 0, sendAt = 0, round = 0, sequence = 0;\n let status = 'connecting', winner = null, destroyed = false, net = { phase: 'idle', rtt: null, route: null }, wasConnected = false, pendingResign = false, endReason = null;\n let poses = [], lastPoseAt = null, lastPose = null, lastFire = new Map(), seen = new Set(), wantsRematch = new Set();\n const me = () => tanks.find(t => t.id === selfId), other = () => tanks.find(t => t.id === peerId);\n const notify = () => { if (!destroyed) onChange({ status, winner, net }); };\n const emit = e => { events.push(e); if (events.length > 200) events.shift(); };\n const send = e => link.sendEvent({ ...e, g: game.gameId, r: round });\n const remember = key => { seen.add(key); if (seen.size > 2048) seen.delete(seen.values().next().value); };\n const snapshot = () => ({ k: 'snapshot', hp: tanks.map(t => t.hp), status, winner, reason: endReason });\n function reset() {\n tanks = ids.map(createTank); shells = []; poses = []; lastPoseAt = null; lastPose = null; lastFire.clear(); seen.clear(); wantsRematch.clear(); pendingResign = false; endReason = null; winner = null; status = net.phase === 'connected' ? 'playing' : 'connecting'; emit({ k: 'rematch' }); notify();\n }\n function finish(id, force = false) { if (status === 'over' && (!force || winner === id)) return; status = 'over'; winner = id; shells = []; link.clearManualTurn?.(); emit({ k: 'over', winner }); notify(); }\n function fire(owner, e, broadcast) {\n if (status !== 'playing' || !idValid(e.id) || seen.has(e.id)) return false;\n const tank = tanks.find(t => t.id === owner);\n if (!tank?.alive || time - (lastFire.get(owner) ?? -Infinity) < RULES.reloadMs - 20) return false;\n if (![e.x, e.z, e.yaw].every(finite) || Math.hypot(e.x - (owner === peerId && lastPose ? lastPose.x : tank.x), e.z - (owner === peerId && lastPose ? lastPose.z : tank.z)) > 6) return false;\n remember(e.id);\n lastFire.set(owner, time);\n const shot = { ...e, k: 'fire', owner, x: e.x + Math.cos(e.yaw) * 2.8, z: e.z + Math.sin(e.yaw) * 2.8, y: 1.4, age: 0 };\n shells.push(shot); emit(shot); if (broadcast) send({ ...e, k: 'fire' }); return true;\n }\n function receiveMove(data) {\n if (destroyed || status !== 'playing' || data?.g !== game.gameId || data.r !== round || !Array.isArray(data.p) || data.p.length !== 5 || !data.p.every(finite)) return;\n const [x, z, yaw, turretYaw, speed] = data.p;\n if (!validPosition(x, z, arena) || Math.abs(speed) > RULES.speed + 0.1 || Math.abs(yaw) > 1e6 || Math.abs(turretYaw) > 1e6) return;\n const elapsed = lastPoseAt === null ? 0.1 : Math.max(0, (time - lastPoseAt) / 1000);\n const previous = lastPose || other();\n if (Math.hypot(x - previous.x, z - previous.z) > RULES.speed * elapsed + 3) return;\n const pose = { ...other(), x, z, yaw, turretYaw, speed };\n lastPose = pose; lastPoseAt = time; poses.push({ time, pose }); if (poses.length > 30) poses.shift();\n }\n function receiveEvent(e) {\n if (destroyed || !e || e.g !== game.gameId || !Number.isInteger(e.r)) return;\n if (e.k === 'round' && !isHost && status === 'over' && wantsRematch.has(selfId) && e.r === round + 1) { round = e.r; reset(); return; }\n if (e.r !== round) return;\n if (e.k === 'sync' && isHost) { send(snapshot()); return; }\n if (e.k === 'snapshot' && !isHost && Array.isArray(e.hp) && e.hp.length === 2 && e.hp.every(hp => Number.isInteger(hp) && hp >= 0 && hp <= 100)) {\n const validPlaying = e.status === 'playing' && e.winner === null && e.hp.every(hp => hp > 0);\n const validOver = e.status === 'over' && ids.includes(e.winner) && (e.hp[1 - ids.indexOf(e.winner)] === 0 || e.reason === 'resigned');\n if (!validPlaying && !validOver) return;\n tanks.forEach((t, i) => { t.hp = e.hp[i]; t.alive = t.hp > 0; });\n if (validOver) { pendingResign = false; endReason = e.reason; finish(e.winner, true); }\n return;\n }\n if (e.k === 'resign') { endReason = 'resigned'; finish(selfId, isHost); if (isHost) send(snapshot()); return; }\n if (e.k === 'rematch' && status === 'over') { wantsRematch.add(peerId); maybeRematch(); return; }\n if (status !== 'playing') return;\n if (e.k === 'fire') fire(peerId, e, false);\n if (!isHost && e.k === 'hit' && idValid(e.id) && !seen.has(`hit:${e.id}`) && ids.includes(e.target) && Array.isArray(e.hp) && e.hp.length === 2 && e.hp.every((hp, i) => Number.isInteger(hp) && hp >= 0 && hp <= tanks[i].hp) && [e.x, e.z].every(finite)) {\n remember(`hit:${e.id}`); tanks.forEach((tank, i) => { tank.hp = e.hp[i]; tank.alive = tank.hp > 0; }); shells = shells.filter(s => s.id !== e.id); emit(e);\n }\n if (!isHost && e.k === 'destroyed' && ids.includes(e.target) && !seen.has(`destroyed:${e.target}`) && tanks.find(t => t.id === e.target).hp === 0) { remember(`destroyed:${e.target}`); emit(e); }\n if (!isHost && e.k === 'over' && ids.includes(e.winner) && tanks.find(t => t.id !== e.winner).hp === 0) finish(e.winner);\n }\n // Scope negotiation itself: a finished card must never answer another game's hello.\n const scopedSignaling = signaling && {\n send(text) { const signal = decodeSignal(text); if (!signal) return Promise.reject(new Error('Invalid live signal')); const scoped = encodeSignal({ ...signal, liveGame: game.gameId }); return scoped ? signaling.send(scoped) : Promise.reject(new Error('Live signal too large')); },\n subscribe(listener) { return signaling.subscribe(frame => { const signal = decodeSignal(frame?.text); if (signal?.liveGame === game.gameId) listener(frame); }); },\n };\n const link = peerFactory({ configurationAuthority: isHost, signaling: scopedSignaling, selfId, peerId, roomId: game.roomId, iceServers, iceTransportPolicy, RTCPeerConnectionImpl, onMove: receiveMove, onEvent: receiveEvent, onChange(state) {\n const previousPhase = net.phase; net = state;\n if (state.phase === 'connected') { const resumed = wasConnected; wasConnected = true; if (status !== 'over') status = 'playing'; if (previousPhase !== 'connected') queueMicrotask(() => { if (!destroyed) { if (pendingResign) send({ k: 'resign' }); if (isHost && resumed) send(snapshot()); else if (!isHost) send({ k: 'sync' }); } }); }\n else if (status !== 'over') status = wasConnected ? 'disconnected' : 'connecting';\n notify();\n } });\n function maybeRematch() { if (isHost && wantsRematch.size === 2) { round++; send({ k: 'round' }); reset(); } }\n if (isHost) link.connect(); else link.setListening(true);\n return {\n setInput(next) { input = { ...next }; },\n step(dtMs) {\n if (destroyed) return;\n const elapsed = Math.max(0, Math.min(Number(dtMs) || 0, 100)); time += elapsed;\n if (status !== 'playing') return;\n const dt = elapsed / 1000;\n const renderTime = time - 100;\n while (poses.length > 1 && poses[1].time <= renderTime) poses.shift();\n if (poses.length) { const a = poses[0], b = poses[1] || a; const pose = interpolatePose(a.pose, b.pose, b.time === a.time ? 1 : (renderTime - a.time) / (b.time - a.time)); for (const key of ['x', 'z', 'yaw', 'turretYaw', 'speed']) other()[key] = pose[key]; }\n for (let remaining = dt; remaining > 0; remaining -= 0.016) moveTank(me(), input, Math.min(remaining, 0.016), arena);\n if (input.fire) fire(selfId, { id: `${selfId}:${round}:${++sequence}`, x: me().x, z: me().z, yaw: me().turretYaw, t: time }, true);\n const hz = net.rtt > 250 || net.move?.lossPct > 15 ? 10 : net.rtt > 100 ? 15 : 20;\n if (time >= sendAt) { sendAt = time + 1000 / hz; const t = me(); link.sendMove({ g: game.gameId, r: round, p: [t.x, t.z, t.yaw, t.turretYaw, t.speed], t: time }); }\n shells = shells.filter(shell => {\n const hit = advanceShell(shell, dt, arena, tanks);\n if (!hit) return true;\n if (isHost && hit.target && status === 'playing') {\n const tank = tanks.find(t => t.id === hit.target); tank.hp = Math.max(0, tank.hp - RULES.damage); tank.alive = tank.hp > 0;\n const e = { k: 'hit', id: shell.id, target: tank.id, dmg: RULES.damage, hp: tanks.map(t => t.hp), x: shell.x, z: shell.z }; send(e); emit(e);\n if (!tank.alive) { const e = { k: 'destroyed', target: tank.id }; send(e); emit(e); send({ k: 'over', winner: shell.owner }); finish(shell.owner); }\n } else emit({ k: 'impact', kind: hit.kind, x: shell.x, z: shell.z });\n return false;\n });\n },\n getRender() { const out = { arena, tanks: tanks.map(t => ({ ...t, self: t.id === selfId, reload: Math.min(1, (time - (lastFire.get(t.id) ?? -Infinity)) / RULES.reloadMs) })), shells: shells.map(s => ({ ...s })), events, status, winner, net: { ...net, turnConfigured: net.turnConfigured ?? initialTurnConfigured } }; events = []; return out; },\n configureTurn(config, options) {\n if (destroyed || status === 'over') return Promise.reject(new Error('La partida ya terminó.'));\n return link.configureTurn(config, options);\n },\n reconnect() { if (!destroyed && status !== 'over') { if (link.requestReconnect) link.requestReconnect(); else link.connect(); } },\n rematch() { if (!destroyed && status === 'over') { wantsRematch.add(selfId); send({ k: 'rematch' }); maybeRematch(); } },\n resign() { if (!destroyed && status !== 'over') { pendingResign = true; endReason = 'resigned'; send({ k: 'resign' }); finish(peerId); } },\n destroy() { if (destroyed) return; destroyed = true; link.destroy(); shells = []; poses = []; events = []; },\n };\n}\n","// Pure helpers shared by the live 3D/2D scenes and the card (no three, no DOM).\n// Render-state yaw is radians with forward = (cos yaw, sin yaw) on the x/z plane.\n\nexport const DEFAULT_ARENA_SIZE = 120;\nexport const RAD_TO_DEG = 180 / Math.PI;\n\nconst num = (value, fallback) => (Number.isFinite(value) ? value : fallback);\n\n/** Arena rectangle in world meters: explicit bounds, or `size` (corner origin unless `centered`). */\nexport function arenaBounds(arena) {\n const a = arena || {};\n const b = a.bounds || a;\n if (Number.isFinite(b.minX) && Number.isFinite(b.maxX) && Number.isFinite(b.minZ) && Number.isFinite(b.maxZ)) {\n return withSize({ minX: b.minX, minZ: b.minZ, maxX: b.maxX, maxZ: b.maxZ });\n }\n const w = num(a.width, num(a.size, DEFAULT_ARENA_SIZE));\n const d = num(a.depth, num(a.height, num(a.size, w)));\n const centered = a.centered === true || a.origin === 'center';\n return withSize(centered\n ? { minX: -w / 2, minZ: -d / 2, maxX: w / 2, maxZ: d / 2 }\n : { minX: 0, minZ: 0, maxX: w, maxZ: d });\n}\n\nfunction withSize(box) {\n return { ...box, width: box.maxX - box.minX, depth: box.maxZ - box.minZ, cx: (box.minX + box.maxX) / 2, cz: (box.minZ + box.maxZ) / 2 };\n}\n\n/** Circular obstacles [{ x, z, r, kind: 'tree'|'rock' }]. */\nexport function arenaObstacles(arena) {\n const list = arena?.obstacles || [];\n return list\n .filter((o) => Number.isFinite(o?.x) && Number.isFinite(o?.z))\n .map((o) => ({ x: o.x, z: o.z, r: num(o.r, num(o.radius, 1.5)), kind: o.kind === 'tree' ? 'tree' : 'rock' }));\n}\n\nexport const eventKind = (event) => (event ? event.k ?? event.type ?? null : null);\n\n/** Tank that fired: explicit owner field, else the tank nearest to the shot origin. */\nexport function shooterOf(event, tanks) {\n const list = tanks || [];\n const owner = event?.tank ?? event?.by ?? event?.owner ?? event?.from;\n if (owner != null) {\n const found = list.find((t) => String(t.id) === String(owner));\n if (found) return found;\n }\n if (!Number.isFinite(event?.x) || !Number.isFinite(event?.z)) return null;\n let best = null;\n let bestD = Infinity;\n for (const t of list) {\n const d = (t.x - event.x) ** 2 + (t.z - event.z) ** 2;\n if (d < bestD) { bestD = d; best = t; }\n }\n return best;\n}\n\nexport const tankById = (tanks, id) => (id == null ? null : (tanks || []).find((t) => String(t.id) === String(id)) || null);\nexport const selfTank = (tanks) => (tanks || []).find((t) => t.self) || null;\n\n/** 0 healthy, 1 smoking, 2 burning (also wrecks). */\nexport const damageLevel = (hp, alive = true) => (!alive || hp <= 25 ? 2 : hp <= 50 ? 1 : 0);\n\nexport const wrapAngle = (a) => {\n let v = a % (Math.PI * 2);\n if (v > Math.PI) v -= Math.PI * 2;\n if (v < -Math.PI) v += Math.PI * 2;\n return v;\n};\n\n/**\n * Tracks the own tank between frames to drive the engine/tracks/turret loops.\n * update(tank, dtMs) → scene-style sound events (move_start/move_end/turret_start/turret_end).\n */\nexport function createSelfTracker({ moveSpeed = 0.6, turnSpeed = 0.35, holdMs = 160 } = {}) {\n let last = null;\n let moving = false;\n let turning = false;\n let moveIdle = 0;\n let turnIdle = 0;\n return {\n update(tank, dtMs) {\n const out = [];\n if (!tank || tank.alive === false) {\n if (moving) out.push({ type: 'move_end' });\n if (turning) out.push({ type: 'turret_end' });\n moving = turning = false;\n last = null;\n return out;\n }\n const dt = Math.max(1, dtMs) / 1000;\n if (last) {\n const speed = Math.hypot(tank.x - last.x, tank.z - last.z) / dt;\n const hull = Math.abs(wrapAngle((tank.yaw ?? 0) - last.yaw)) / dt;\n const turret = Math.abs(wrapAngle((tank.turretYaw ?? 0) - (tank.yaw ?? 0) - last.rel)) / dt;\n const isMoving = speed > moveSpeed || hull > turnSpeed;\n moveIdle = isMoving ? 0 : moveIdle + dtMs;\n if (isMoving && !moving) { moving = true; out.push({ type: 'move_start' }); }\n else if (!isMoving && moving && moveIdle >= holdMs) { moving = false; out.push({ type: 'move_end' }); }\n const isTurning = turret > turnSpeed;\n turnIdle = isTurning ? 0 : turnIdle + dtMs;\n if (isTurning && !turning) { turning = true; out.push({ type: 'turret_start' }); }\n else if (!isTurning && turning && turnIdle >= holdMs) { turning = false; out.push({ type: 'turret_end' }); }\n }\n last = { x: tank.x, z: tank.z, yaw: tank.yaw ?? 0, rel: wrapAngle((tank.turretYaw ?? 0) - (tank.yaw ?? 0)) };\n return out;\n },\n reset() {\n last = null;\n moving = turning = false;\n moveIdle = turnIdle = 0;\n },\n get moving() { return moving; },\n get turning() { return turning; },\n };\n}\n\n/** Render events → scene-style sound events (sound/cues.js vocabulary). */\nexport function soundEventsFor(event) {\n switch (eventKind(event)) {\n case 'fire': return [{ type: 'fire' }, { type: 'projectile_start' }];\n case 'impact': return [{ type: 'impact', kind: event.kind === 'obstacle' ? 'obstacle' : 'terrain' }];\n case 'hit': return [{ type: 'tank_hit' }];\n case 'destroyed': return [{ type: 'destroyed' }];\n default: return [];\n }\n}\n\n/** 'victory' | 'defeat' | null for the own player once the match is over. */\nexport function outcomeFor(render) {\n if (!render || render.status !== 'over') return null;\n const me = selfTank(render.tanks);\n if (!me || render.winner == null) return null;\n return String(render.winner) === String(me.id) ? 'victory' : 'defeat';\n}\n\n/** Own reload progress 0..1 (1 = ready): the tank's own field when given, else from the last own fire. */\nexport function reloadProgress(tank, lastFireAt, now, reloadMs = 1500) {\n if (!tank) return 1;\n if (Number.isFinite(tank.reload)) return Math.max(0, Math.min(1, tank.reload));\n if (Number.isFinite(tank.reloadMs)) return Math.max(0, Math.min(1, 1 - tank.reloadMs / reloadMs));\n if (!Number.isFinite(lastFireAt)) return 1;\n return Math.max(0, Math.min(1, (now - lastFireAt) / reloadMs));\n}\n","import { arenaBounds, arenaObstacles } from './liveView.js';\n\n/** Lightweight top-down fallback, with the same render/picking lifecycle as WebGL. */\nexport function createLiveScene2d(container, { arena } = {}) {\n const canvas = document.createElement('canvas');\n canvas.style.cssText = 'width:100%;height:100%;display:block';\n container.appendChild(canvas);\n const ctx = canvas.getContext('2d');\n if (!ctx) { canvas.remove(); throw new Error('Canvas 2D unavailable'); }\n const bounds = arenaBounds(arena);\n let w = 1; let h = 1; let scale = 1; let ox = 0; let oz = 0;\n function resize() {\n w = Math.max(1, container.clientWidth); h = Math.max(1, container.clientHeight);\n const dpr = Math.min(window.devicePixelRatio || 1, 2);\n canvas.width = w * dpr; canvas.height = h * dpr;\n ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n scale = Math.min(w / bounds.width, h / bounds.depth);\n ox = (w - bounds.width * scale) / 2; oz = (h - bounds.depth * scale) / 2;\n }\n resize();\n const ro = typeof ResizeObserver === 'function' ? new ResizeObserver(resize) : null;\n ro?.observe(container);\n return {\n kind: '2d', resize,\n screenToGround(nx, ny) { return { x: ((nx + 1) * w / 2 - ox) / scale + bounds.minX, z: ((1 - ny) * h / 2 - oz) / scale + bounds.minZ }; },\n render(state) {\n ctx.fillStyle = '#152519'; ctx.fillRect(0, 0, w, h);\n ctx.save(); ctx.translate(ox, oz); ctx.scale(scale, scale); ctx.translate(-bounds.minX, -bounds.minZ);\n ctx.fillStyle = '#526348'; ctx.fillRect(bounds.minX, bounds.minZ, bounds.width, bounds.depth);\n for (const obstacle of arenaObstacles(arena)) { ctx.fillStyle = obstacle.kind === 'tree' ? '#24472d' : '#929285'; ctx.beginPath(); ctx.arc(obstacle.x, obstacle.z, obstacle.r, 0, Math.PI * 2); ctx.fill(); }\n for (const tank of state.tanks || []) {\n ctx.save(); ctx.translate(tank.x, tank.z); ctx.rotate(tank.yaw);\n ctx.fillStyle = tank.alive === false ? '#333' : tank.color || '#73ce68';\n ctx.fillRect(-3, -1.8, 6, 3.6); ctx.restore();\n ctx.save(); ctx.translate(tank.x, tank.z); ctx.rotate(tank.turretYaw); ctx.strokeStyle = '#dce8cf'; ctx.lineWidth = 0.8; ctx.beginPath(); ctx.moveTo(0, 0); ctx.lineTo(5, 0); ctx.stroke(); ctx.restore();\n if (tank.self) { ctx.strokeStyle = '#fff'; ctx.lineWidth = 0.3; ctx.beginPath(); ctx.arc(tank.x, tank.z, 4, 0, Math.PI * 2); ctx.stroke(); }\n }\n ctx.fillStyle = '#ffe097';\n for (const shell of state.shells || []) { ctx.beginPath(); ctx.arc(shell.x, shell.z, 0.7, 0, Math.PI * 2); ctx.fill(); }\n ctx.restore();\n },\n dispose() { ro?.disconnect(); canvas.remove(); },\n };\n}\n","/* eslint-disable react/prop-types */\nimport { memo, useContext, useEffect, useRef, useState } from 'react';\nimport { AlertTriangle, CheckCircle2, Link2, Loader2, Settings2 } from 'lucide-react';\nimport ManualTurnDialog from './ManualTurnDialog.jsx';\nimport { ChatContext } from '../../provider/ChatContext.js';\nimport useChatGames from '../shared/useChatGames.js';\nimport GameSoundControls from '../shared/GameSoundControls.jsx';\nimport { connectionDiagnostics, connectionHint } from './net/connectionDiagnostics.js';\nimport { createLiveMatch } from './net/createLiveMatch.js';\nimport { createLiveScene2d } from './scene/createLiveScene2d.js';\nimport { createSelfTracker, outcomeFor, selfTank, soundEventsFor } from './scene/liveView.js';\nimport { getTanksSoundManager, startTanksSounds, handleSceneEvent, playOutcome, stopAllTanksLoops } from '../tanks/sound/tanksSounds.js';\nimport '../connect4/games.css';\nimport './tanks-live.css';\n\nconst act = (key, type) => { void useChatGames.getState().act(key, type).catch(() => {}); };\nconst stopInput = (input) => { input.throttle = 0; input.steer = 0; input.fire = false; };\nfunction connectionText(net, prolonged) {\n const manual = net?.manualTurn;\n if (manual?.status === 'applying') return 'Aplicando configuración…';\n if (manual?.status === 'sharing') return 'Sincronizando con el otro jugador…';\n if (manual?.status === 'waiting_peer') return 'Esperando al otro jugador para compartir la configuración…';\n if (net?.phase === 'connected') return '¡Conexión establecida!';\n if (manual?.status === 'failed' || net?.phase === 'failed' || net?.ice === 'failed') return 'No pudimos conectar. Puedes reintentar.';\n if (prolonged) return 'La conexión está tardando más de lo esperado';\n if (net?.phase === 'restarting' || net?.phase === 'reconnecting') return 'Reconectando…';\n if (net?.phase === 'listening') return 'Esperando la conexión del otro jugador…';\n if (net?.phase === 'calling') return 'Buscando al otro jugador…';\n if (net?.phase === 'negotiating') return 'Buscando una conexión entre los jugadores…';\n return 'Preparando partida…';\n}\n\nfunction TanksLiveGameCard({ gameKey, currentUserId, onMinimize, onDismiss, suspended = false }) {\n const rtcOptions = useContext(ChatContext)?.config?.webrtc;\n const game = useChatGames((state) => state.games[gameKey]);\n const suspendedRef = useRef(suspended);\n suspendedRef.current = suspended;\n const stage = useRef(null); const match = useRef(null); const renderer = useRef(null);\n const input = useRef({ throttle: 0, steer: 0, fire: false });\n const [view, setView] = useState(null); const [error, setError] = useState(''); const [prefer2d, setPrefer2d] = useState(false);\n const [mode, setMode] = useState('loading');\n const [turnOpen, setTurnOpen] = useState(false);\n const [waitingMs, setWaitingMs] = useState(0);\n const connected = view?.net?.phase === 'connected';\n useEffect(() => {\n if (!game || game.status !== 'active' || connected) { setWaitingMs(0); return undefined; }\n const started = Date.now();\n const timer = setInterval(() => setWaitingMs(Date.now() - started), 1000);\n return () => clearInterval(timer);\n }, [gameKey, game?.status, connected]);\n useEffect(() => { setTurnOpen(false); }, [gameKey, game?.status]);\n\n useEffect(() => {\n if (suspended) { stopInput(input.current); stopAllTanksLoops(); }\n else renderer.current?.resize();\n }, [suspended]);\n const active = ['active', 'won'].includes(game?.status);\n const [arena, setArena] = useState(null);\n useEffect(() => {\n if (!active || !arena || !stage.current) return undefined;\n let disposed = false; let scene = null;\n const options = { arena, lowPower: matchMedia('(pointer: coarse)').matches, reducedMotion: matchMedia('(prefers-reduced-motion: reduce)').matches, onEvent: (event) => { if (event.type === 'context_lost') setPrefer2d(true); } };\n const fallback = () => { if (!disposed) { scene = createLiveScene2d(stage.current, options); renderer.current = scene; setMode('2d'); } };\n if (prefer2d) fallback();\n else import('./scene/createLiveScene.js').then(({ createLiveScene }) => { if (!disposed) { try { scene = createLiveScene(stage.current, options); renderer.current = scene; setMode('3d'); } catch { fallback(); } } }).catch(fallback);\n return () => { disposed = true; scene?.dispose(); if (renderer.current === scene) renderer.current = null; };\n }, [active, arena, prefer2d]);\n useEffect(() => {\n if (!active || game.status !== 'active' || !stage.current) return undefined;\n let disposed = false; let frame = 0; let last = performance.now(); let published = 0; let outcome = null;\n const tracker = createSelfTracker(); const keys = new Set();\n startTanksSounds();\n let session;\n try {\n const signaling = useChatGames.getState().createLiveSignaling(gameKey);\n session = createLiveMatch({ iceServers: rtcOptions?.iceServers, iceTransportPolicy: rtcOptions?.iceTransportPolicy, game, selfId: String(currentUserId), isHost: String(game.hostId) === String(currentUserId), signaling });\n match.current = session;\n } catch (e) { setError(e.message || 'No se pudo iniciar WebRTC'); return undefined; }\n setArena(session.getRender().arena);\n function clear() { keys.clear(); stopInput(input.current); stopAllTanksLoops(); }\n function key(event, down) {\n if (/^(INPUT|TEXTAREA|SELECT)$/.test(event.target?.tagName)) return;\n if (!['KeyW', 'KeyA', 'KeyS', 'KeyD', 'ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Space'].includes(event.code)) return;\n event.preventDefault(); if (down) keys.add(event.code); else keys.delete(event.code);\n input.current.throttle = Number(keys.has('KeyW') || keys.has('ArrowUp')) - Number(keys.has('KeyS') || keys.has('ArrowDown'));\n input.current.steer = Number(keys.has('KeyD') || keys.has('ArrowRight')) - Number(keys.has('KeyA') || keys.has('ArrowLeft'));\n input.current.fire = keys.has('Space');\n }\n const down = (e) => key(e, true); const up = (e) => key(e, false);\n const host = stage.current;\n host.addEventListener('keydown', down); host.addEventListener('keyup', up); host.addEventListener('blur', clear);\n const visibility = () => { if (document.hidden) clear(); };\n document.addEventListener('visibilitychange', visibility);\n handleSceneEvent({ type: 'engine_start' }, gameKey);\n function tick(now) {\n if (disposed) return;\n const dt = Math.min(80, now - last); last = now;\n const paused = suspendedRef.current || document.hidden;\n session.setInput(paused ? { throttle: 0, steer: 0, fire: false } : input.current);\n session.step(dt); const state = session.getRender();\n if (!paused) renderer.current?.render(state, dt);\n if (paused) { keys.clear(); tracker.reset(); stopAllTanksLoops(); }\n if (!paused) for (const event of state.events || []) for (const sound of soundEventsFor(event)) handleSceneEvent(sound, event.id);\n if (!paused) for (const event of tracker.update(selfTank(state.tanks), dt)) handleSceneEvent(event);\n const nextOutcome = outcomeFor(state);\n if (nextOutcome && !outcome) { setView(state); outcome = nextOutcome; if (!paused) playOutcome(outcome, gameKey); useChatGames.getState().liveFinish?.(gameKey, state.winner); }\n if (now - published > 100) { published = now; setView(state); }\n frame = requestAnimationFrame(tick);\n }\n frame = requestAnimationFrame(tick);\n return () => {\n disposed = true; cancelAnimationFrame(frame); clear(); session.destroy(); match.current = null;\n host.removeEventListener('keydown', down); host.removeEventListener('keyup', up); host.removeEventListener('blur', clear); document.removeEventListener('visibilitychange', visibility);\n };\n }, [active, gameKey, currentUserId]);\n if (!game) return null;\n const guest = String(currentUserId) === String(game.guestId);\n const over = view?.status === 'over' || game.status === 'won';\n const net = view?.net;\n const manual = net?.manualTurn;\n const configuring = ['waiting_peer', 'sharing', 'applying'].includes(manual?.status);\n const connectionProblem = !connected && (waitingMs >= 12000 || net?.phase === 'failed' || net?.ice === 'failed' || manual?.status === 'failed' || Boolean(error));\n const routeText = connected ? (net?.route?.relay === true ? 'TURN Relay' : net?.route?.relay === false ? 'P2P' : null) : null;\n const applyTurn = async (json, options) => {\n if (!match.current?.configureTurn) throw new Error('La partida aún no está preparada. Espera un momento y vuelve a intentarlo.');\n await match.current.configureTurn(json, options);\n };\n\n function aim(event) {\n const rect = stage.current?.getBoundingClientRect(); const me = selfTank(view?.tanks);\n if (!rect || !me) return;\n const ground = renderer.current?.screenToGround((event.clientX - rect.left) / rect.width * 2 - 1, 1 - (event.clientY - rect.top) / rect.height * 2);\n if (ground) input.current.turretYaw = Math.atan2(ground.z - me.z, ground.x - me.x);\n }\n const hold = (field, value) => ({ onPointerDown: (e) => { e.preventDefault(); e.currentTarget.setPointerCapture(e.pointerId); input.current[field] = value; }, onPointerUp: () => { input.current[field] = field === 'fire' ? false : 0; }, onPointerCancel: () => { input.current[field] = field === 'fire' ? false : 0; }, onLostPointerCapture: () => { input.current[field] = field === 'fire' ? false : 0; } });\n return <section className={`chat-game-card tl-card${active ? ' tl-card--active' : ''}`} aria-label=\"Tanques LIVE 3D\">\n <header className=\"tl-header\"><strong>Tanques LIVE 3D</strong><div className=\"tl-header-actions\"><GameSoundControls manager={getTanksSoundManager()} />{onMinimize && <button onClick={onMinimize} aria-label=\"Minimizar\">−</button>}{onDismiss && <button onClick={onDismiss} aria-label=\"Ocultar\">×</button>}</div></header>\n {game.status === 'invited' && <div className=\"tl-invite\"><span className=\"tl-invite-icon\" aria-hidden=\"true\">🪖</span><strong>{guest ? '¿Listo para combatir?' : 'Invitación enviada'}</strong><p>{guest ? 'Te invitaron a un combate en tiempo real.' : 'Esperando que el rival acepte…'}</p>{guest && <div className=\"tl-invite-actions\"><button className=\"tl-button-primary\" onClick={() => act(gameKey, 'game_accept')}>Aceptar combate</button><button onClick={() => act(gameKey, 'game_decline')}>Rechazar</button></div>}</div>}\n {active && !over && <div className={`tl-connection tl-connection--${connected ? 'connected' : connectionProblem ? 'problem' : 'pending'}`}>\n <div className=\"tl-connection-heading\">{connected ? <CheckCircle2 size={18} aria-hidden=\"true\" /> : connectionProblem ? <AlertTriangle size={18} aria-hidden=\"true\" /> : <Loader2 size={18} className=\"tl-connection-spinner\" aria-hidden=\"true\" />}<div><strong>{connectionProblem ? 'Problemas de conexión' : connectionText(net, false)}</strong>{connectionProblem && <p>No pudimos establecer una conexión con el otro jugador. Puedes configurar una conexión alternativa para continuar.</p>}</div>{routeText && <span className=\"tl-route-badge\">{routeText}</span>}</div>\n {!connected && <p className=\"tl-connection-message\" role=\"status\">{connectionProblem ? connectionText(net, waitingMs >= 12000) : connectionHint(net)}</p>}\n {manual?.status === 'synchronized' && <p className=\"tl-connection-shared\" role=\"status\">{manual.received ? 'Configuración recibida del otro jugador y aplicada en ambos.' : 'Configuración compartida y aplicada en ambos jugadores.'}</p>}\n {manual?.expiresAt != null && manual.expiresAt <= Date.now() && <p className=\"tl-connection-expired\" role=\"status\">La validez indicada para las credenciales terminó. Introduce una configuración nueva si necesitas reconectar.</p>}\n <div className=\"tl-connection-actions\"><button type=\"button\" className={connectionProblem ? 'tl-button-primary' : ''} onClick={() => setTurnOpen(true)}><Settings2 size={15} aria-hidden=\"true\" />Configurar conexión alternativa</button>{!connected && <button type=\"button\" disabled={configuring} onClick={() => match.current?.reconnect()}><Link2 size={15} aria-hidden=\"true\" />Reintentar conexión</button>}</div>\n </div>}\n <ManualTurnDialog open={turnOpen && active && !over} onClose={() => setTurnOpen(false)} onApply={applyTurn} manualTurn={manual} />\n {(active || view) && <><div className=\"tl-hud\">{(view?.tanks || []).map((tank) => <span key={tank.id}>{tank.self ? 'Tú' : 'Rival'} <meter min=\"0\" max=\"100\" value={tank.hp} aria-label={tank.self ? 'Tu vida' : 'Vida del rival'} /> {tank.hp} HP</span>)}<span role=\"status\">{connected ? routeText || 'Conectado' : connectionText(net, waitingMs >= 12000)} {Number.isFinite(net?.rtt) ? `· ${Math.round(net.rtt)} ms` : ''}</span></div>\n <div className=\"tl-stage\" ref={stage} tabIndex={0} aria-label=\"Arena. WASD o flechas para conducir, ratón para apuntar, clic o espacio para disparar\" onPointerMove={aim} onPointerDown={(e) => { aim(e); if (e.pointerType === 'mouse') { e.currentTarget.focus(); e.currentTarget.setPointerCapture(e.pointerId); aim(e); input.current.fire = true; } }} onPointerUp={() => { input.current.fire = false; }} onPointerCancel={() => { stopInput(input.current); }} onLostPointerCapture={() => { input.current.fire = false; }} />\n <div className=\"tl-controls\"><div className=\"tl-joystick\" role=\"group\" aria-label=\"Joystick de conducción\" onPointerDown={(e) => { e.preventDefault(); e.currentTarget.setPointerCapture(e.pointerId); const r = e.currentTarget.getBoundingClientRect(); input.current.steer = Math.max(-1, Math.min(1, (e.clientX - r.left - r.width / 2) / (r.width / 2))); input.current.throttle = Math.max(-1, Math.min(1, -(e.clientY - r.top - r.height / 2) / (r.height / 2))); }} onPointerMove={(e) => { if (!e.currentTarget.hasPointerCapture(e.pointerId)) return; const r = e.currentTarget.getBoundingClientRect(); input.current.steer = Math.max(-1, Math.min(1, (e.clientX - r.left - r.width / 2) / (r.width / 2))); input.current.throttle = Math.max(-1, Math.min(1, -(e.clientY - r.top - r.height / 2) / (r.height / 2))); }} onPointerUp={() => stopInput(input.current)} onPointerCancel={() => stopInput(input.current)} onLostPointerCapture={() => stopInput(input.current)}>✥</div><div className=\"tl-drive\" aria-label=\"Controles de conducción\"><button aria-label=\"Avanzar\" {...hold('throttle', 1)}>▲</button><button aria-label=\"Girar izquierda\" {...hold('steer', -1)}>◀</button><button aria-label=\"Retroceder\" {...hold('throttle', -1)}>▼</button><button aria-label=\"Girar derecha\" {...hold('steer', 1)}>▶</button></div><button className=\"tl-fire\" {...hold('fire', true)}>Disparar</button></div>\n <div className=\"tl-reload\"><label>Recarga <progress max=\"1\" value={selfTank(view?.tanks)?.reload ?? 1} /> {(selfTank(view?.tanks)?.reload ?? 1) >= 1 ? 'Listo' : 'Recargando…'}</label></div>\n <small>WASD / flechas · ratón o toca la arena para apuntar · espacio / clic para disparar</small><button onClick={() => setPrefer2d((v) => !v)}>{mode === '2d' ? 'Probar 3D' : 'Vista 2D'}</button>\n </>}\n {over && <p role=\"status\">{String(view?.winner ?? game.winnerId) === String(currentUserId) ? '¡Victoria!' : 'Fin del combate'} <button onClick={() => { void Promise.resolve(useChatGames.getState().liveRematch?.(gameKey)).catch(() => {}); }}>Revancha</button></p>}\n {active && <details className=\"tl-diagnostics\"><summary>Diagnóstico de conexión</summary><pre>{JSON.stringify(connectionDiagnostics(view?.net), null, 2)}</pre></details>}\n {active && !over && <button onClick={() => match.current?.resign()}>Rendirse</button>}\n {game.pending && <p role=\"status\">Enviando…</p>}{game.pendingEvent && game.error && <button onClick={() => { void useChatGames.getState().retry(gameKey).catch(() => {}); }}>Reintentar envío</button>}\n {error && <p role=\"alert\">{error}</p>}{game.error && <p role=\"alert\">{game.error}</p>}\n {!['closed', 'declined'].includes(game.status) && <footer className=\"tl-footer\"><button onClick={() => act(gameKey, 'game_end')}>Cerrar partida</button></footer>}\n </section>;\n}\nexport default memo(TanksLiveGameCard);\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { n as e, t } from "./createPeerLink-CL7VZuHS.js";
1
+ import { n as e, t } from "./createPeerLink-DBVs_yvQ.js";
2
2
  import { t as n } from "./signalFaults-Dv2YjjKy.js";
3
3
  import { useEffect as r, useRef as i, useState as a } from "react";
4
4
  import { jsx as o, jsxs as s } from "react/jsx-runtime";
@@ -507,4 +507,4 @@ function f({ selfId: f, selfName: p, peers: m = [], defaultPeerId: h = "", creat
507
507
  }
508
508
  export { f as default };
509
509
 
510
- //# sourceMappingURL=WebRtcLab-lijo_Rta.js.map
510
+ //# sourceMappingURL=WebRtcLab-ClRSYt4E.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"WebRtcLab-lijo_Rta.js","names":["createPeerLink","withSignalFaults","PHASE_CLASS","HZ","STYLES","iceServersFrom","servers","stun","form","WebRtcLab","DEFAULT_ICE_SERVERS","setForm","useState","defaultPeerId","iceServers","server","state","setState","running","setRunning","starting","setStarting","sending","setSending","logs","setLogs","burst","setBurst","linkRef","useRef","signalingRef","formRef","remoteRef","localRef","canvasRef","burstRef","useEffect","current","log","items","line","update","value","event","key","stop","start","f","peerId","selfId","base","createSignaling","signaling","payload","received","b","selfName","error","onHide","startedAt","timer","me","frame","draw","canvas","w","h","ratio","ctx","dot","p","color","label","sendBurst","n","s","phase","peerName","peers","peer","title","disabledReason","children","socketStatus","hz","v"],"sources":["../../src/net/webrtc/WebRtcLab.jsx"],"sourcesContent":["import { useEffect, useRef, useState } from 'react';\nimport { createPeerLink, DEFAULT_ICE_SERVERS } from './createPeerLink.js';\nimport { withSignalFaults } from './signalFaults.js';\n\n// WebRTC lab (TANQUES LIVE groundwork): two users connect a DataChannel pair while\n// the chat carries only the signaling. Host-agnostic: the host passes who the user\n// is, who the peers are and createSignaling({ peerId }) → { send, subscribe }.\n// Exposes window.__rtcLab for automated checks.\n\nconst PHASE_CLASS = { connected: 'ok', listening: 'warn', calling: 'warn', negotiating: 'warn', restarting: 'warn', reconnecting: 'warn', failed: 'bad' };\nconst HZ = [10, 15, 20, 30, 60];\n\nconst STYLES = `\n.lira-rtc-lab { --bg:#0d1117; --panel:#161b22; --line:#30363d; --text:#e6edf3; --muted:#8b949e;\n color-scheme: dark; background: var(--bg); color: var(--text); font: 13px/1.45 system-ui, sans-serif; padding: 12px 16px 32px; border-radius: 12px; }\n.lira-rtc-lab h1 { font-size: 18px; margin: 4px 0 2px; }\n.lira-rtc-lab .sub { color: var(--muted); margin: 0 0 12px; }\n.lira-rtc-lab .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 12px; }\n.lira-rtc-lab section { background: var(--panel); border: 1px solid var(--line); border-radius: 10px; padding: 10px 12px; min-width: 0; }\n.lira-rtc-lab section h2 { font-size: 12px; margin: 0 0 8px; color: #c9d1d9; text-transform: uppercase; letter-spacing: .05em; }\n.lira-rtc-lab label { display: flex; gap: 6px; align-items: center; margin: 4px 0; flex-wrap: wrap; }\n.lira-rtc-lab label > span { min-width: 92px; color: var(--muted); }\n.lira-rtc-lab input, .lira-rtc-lab select { background: var(--bg); color: var(--text); border: 1px solid var(--line); border-radius: 6px; padding: 4px 6px; font: inherit; min-width: 0; }\n.lira-rtc-lab input[type=text], .lira-rtc-lab input[type=password] { flex: 1; }\n.lira-rtc-lab input[type=number] { width: 80px; }\n.lira-rtc-lab button { background: #238636; color: #fff; border: 0; border-radius: 6px; padding: 6px 10px; font: inherit; font-weight: 600; cursor: pointer; }\n.lira-rtc-lab button.secondary { background: var(--line); }\n.lira-rtc-lab button.danger { background: #b62324; }\n.lira-rtc-lab button:disabled { opacity: .45; cursor: not-allowed; }\n.lira-rtc-lab .row { display: flex; flex-wrap: wrap; gap: 6px; margin: 6px 0; align-items: center; }\n.lira-rtc-lab dl { display: grid; grid-template-columns: auto 1fr; gap: 2px 10px; margin: 0; }\n.lira-rtc-lab dt { color: var(--muted); }\n.lira-rtc-lab dd { margin: 0; font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }\n.lira-rtc-lab .pill { display: inline-block; padding: 1px 8px; border-radius: 999px; background: var(--line); font-weight: 600; }\n.lira-rtc-lab .ok { background: #1f6f3a; } .lira-rtc-lab .warn { background: #8a5a00; } .lira-rtc-lab .bad { background: #8e1f1f; }\n.lira-rtc-lab canvas { width: 100%; height: 220px; background: #0b1020; border-radius: 8px; display: block; }\n.lira-rtc-lab .log { height: 200px; overflow: auto; background: var(--bg); border-radius: 6px; padding: 6px; font: 11px ui-monospace, monospace; white-space: pre-wrap; }\n.lira-rtc-lab .wide { grid-column: 1 / -1; }\n`;\n\nfunction iceServersFrom(form) {\n const servers = [];\n const stun = form.stun.split(/[\\s,]+/).filter(Boolean);\n if (stun.length) servers.push({ urls: stun });\n if (form.turnUrl.trim()) servers.push({ urls: form.turnUrl.split(/[\\s,]+/).filter(Boolean), username: form.turnUser, credential: form.turnPass });\n return servers;\n}\n\n/**\n * @param {{\n * selfId: string|null, selfName?: string,\n * peers?: { id: string, name?: string }[], defaultPeerId?: string,\n * createSignaling: (opts: { peerId: string, log: (line: string) => void }) => any,\n * socketStatus?: string, disabledReason?: string, title?: string, children?: any,\n * iceServers?: RTCIceServer[],\n * }} props\n */\nexport default function WebRtcLab({\n selfId, selfName, peers = [], defaultPeerId = '', createSignaling, socketStatus = '—',\n disabledReason = '', title = 'WebRTC Lab · TANQUES LIVE', children = null, iceServers = DEFAULT_ICE_SERVERS,\n}) {\n const [form, setForm] = useState({\n peerId: defaultPeerId,\n stun: [].concat(iceServers.find((server) => !server.username)?.urls ?? []).join(' '),\n turnUrl: '', turnUser: '', turnPass: '', relayOnly: false,\n drop: 0, duplicate: 0, jitter: 0, hz: 20,\n });\n const [state, setState] = useState(null);\n const [running, setRunning] = useState(false);\n const [starting, setStarting] = useState(false);\n const [sending, setSending] = useState(false);\n const [logs, setLogs] = useState([]);\n const [burst, setBurst] = useState({ expected: 0, received: 0, orderErrors: 0, last: 0, ms: null, sentAt: 0 });\n const linkRef = useRef(null);\n const signalingRef = useRef(null);\n const formRef = useRef(form);\n const remoteRef = useRef(null);\n const localRef = useRef(null);\n const canvasRef = useRef(null);\n const burstRef = useRef(burst);\n formRef.current = form;\n burstRef.current = burst;\n\n useEffect(() => {\n if (!form.peerId && defaultPeerId) setForm((current) => ({ ...current, peerId: defaultPeerId }));\n }, [defaultPeerId, form.peerId]);\n\n const log = (line) => setLogs((items) => [...items.slice(-199), `${new Date().toISOString().slice(11, 23)} ${line}`]);\n const update = (key) => (event) => {\n const value = event.target.type === 'checkbox' ? event.target.checked : event.target.value;\n setForm((current) => ({ ...current, [key]: ['drop', 'duplicate', 'jitter', 'hz'].includes(key) ? Number(value) : value }));\n };\n\n const stop = () => {\n linkRef.current?.destroy();\n signalingRef.current?.dispose();\n linkRef.current = null;\n signalingRef.current = null;\n remoteRef.current = null;\n setRunning(false);\n setSending(false);\n setState(null);\n log('laboratorio detenido y recursos liberados');\n };\n\n const start = async () => {\n const f = formRef.current;\n const peerId = String(f.peerId ?? '').trim();\n if (!selfId || !peerId) { log('faltan ids de usuario'); return; }\n if (String(peerId) === String(selfId)) { log('el rival debe ser otro usuario'); return; }\n setStarting(true);\n try {\n const base = await createSignaling({ peerId, log });\n const signaling = withSignalFaults(base, () => formRef.current);\n signalingRef.current = signaling;\n linkRef.current = createPeerLink({\n signaling, selfId, peerId,\n iceServers: iceServersFrom(f),\n iceTransportPolicy: f.relayOnly ? 'relay' : 'all',\n onChange: setState,\n onMove: (payload) => { remoteRef.current = payload; },\n onEvent: (payload) => {\n if (payload?.resetBurst) { setBurst({ expected: 0, received: 0, orderErrors: 0, last: 0, ms: null, sentAt: performance.now() }); return; }\n if (payload?.burst == null) { log(`evento: ${JSON.stringify(payload).slice(0, 120)}`); return; }\n setBurst((b) => {\n const received = b.received + 1;\n return {\n ...b, received, last: payload.burst, expected: payload.total,\n orderErrors: b.orderErrors + (payload.burst === b.last + 1 ? 0 : 1),\n ms: received === payload.total ? Math.round(performance.now() - b.sentAt) : b.ms,\n };\n });\n },\n log,\n });\n setRunning(true);\n log(`laboratorio iniciado: yo ${selfName ?? selfId} · rival ${peerId}`);\n } catch (error) {\n log(`no se pudo iniciar la señalización: ${error?.message ?? error}`);\n } finally {\n setStarting(false);\n }\n };\n\n useEffect(() => () => { linkRef.current?.destroy(); signalingRef.current?.dispose(); }, []);\n useEffect(() => {\n const onHide = () => linkRef.current?.destroy();\n window.addEventListener('pagehide', onHide);\n return () => window.removeEventListener('pagehide', onHide);\n }, []);\n // A different user (logout/login) must not keep the old link.\n useEffect(() => () => { if (linkRef.current) stop(); }, [selfId]); // eslint-disable-line react-hooks/exhaustive-deps\n\n // Simulated tank: moves on a curve and streams its position at form.hz.\n useEffect(() => {\n if (!sending) return undefined;\n const startedAt = performance.now();\n const timer = setInterval(() => {\n const t = (performance.now() - startedAt) / 1000;\n const me = { x: 0.5 + 0.35 * Math.cos(t * 0.9), y: 0.5 + 0.3 * Math.sin(t * 1.3), a: t };\n localRef.current = me;\n linkRef.current?.sendMove({ x: Math.round(me.x * 1e4) / 1e4, y: Math.round(me.y * 1e4) / 1e4, a: Math.round(me.a * 100) / 100 });\n }, 1000 / form.hz);\n return () => clearInterval(timer);\n }, [sending, form.hz]);\n\n useEffect(() => {\n let frame = 0;\n const draw = () => {\n frame = requestAnimationFrame(draw);\n const canvas = canvasRef.current;\n if (!canvas) return;\n const { clientWidth: w, clientHeight: h } = canvas;\n const ratio = window.devicePixelRatio || 1;\n if (canvas.width !== Math.round(w * ratio)) { canvas.width = Math.round(w * ratio); canvas.height = Math.round(h * ratio); }\n const ctx = canvas.getContext('2d');\n ctx.setTransform(ratio, 0, 0, ratio, 0, 0);\n ctx.clearRect(0, 0, w, h);\n const dot = (p, color, label) => {\n if (!p) return;\n ctx.fillStyle = color;\n ctx.beginPath();\n ctx.arc(p.x * w, p.y * h, 9, 0, Math.PI * 2);\n ctx.fill();\n ctx.fillStyle = '#e6edf3';\n ctx.fillText(label, p.x * w + 12, p.y * h + 4);\n };\n dot(localRef.current, '#22c55e', 'yo');\n dot(remoteRef.current, '#ef4444', 'rival');\n };\n draw();\n return () => cancelAnimationFrame(frame);\n }, []);\n\n const sendBurst = () => {\n const total = 200;\n setBurst({ expected: total, received: 0, orderErrors: 0, last: 0, ms: null, sentAt: performance.now() });\n linkRef.current?.sendEvent({ resetBurst: true });\n for (let n = 1; n <= total; n += 1) linkRef.current?.sendEvent({ burst: n, total });\n log(`ráfaga de ${total} eventos fiables enviada`);\n };\n\n useEffect(() => {\n window.__rtcLab = { getState: () => linkRef.current?.getState() ?? null, burst: () => burstRef.current };\n });\n\n const s = state;\n const phase = s?.phase ?? 'idle';\n const peerName = peers.find((peer) => String(peer.id) === String(form.peerId))?.name ?? form.peerId;\n return (\n <div className=\"lira-rtc-lab\">\n <style>{STYLES}</style>\n <h1>{title}</h1>\n <p className=\"sub\">Señalización por el chat (<code>LIRA_WEBRTC_V1:</code> en <code>CHAT_MESSAGE</code>), datos por DataChannel.</p>\n {disabledReason ? <p className=\"sub\"><span className=\"pill bad\">{disabledReason}</span></p> : null}\n <div className=\"grid\">\n <section>\n <h2>Configuración</h2>\n {children}\n <label><span>Yo</span><strong>{selfName ?? selfId ?? '—'}</strong>{selfName && selfId ? <small> ({selfId})</small> : null}</label>\n <label><span>Rival</span>\n {peers.length ? (\n <select value={form.peerId} onChange={update('peerId')} disabled={running}>\n <option value=\"\">— elige —</option>\n {peers.filter((peer) => String(peer.id) !== String(selfId)).map((peer) => <option key={peer.id} value={peer.id}>{peer.name ?? peer.id}</option>)}\n </select>\n ) : null}\n <input type=\"text\" value={form.peerId} onChange={update('peerId')} placeholder=\"user_id del rival\" disabled={running} />\n </label>\n <label><span>STUN</span><input type=\"text\" value={form.stun} onChange={update('stun')} disabled={running} /></label>\n <label><span>TURN</span><input type=\"text\" value={form.turnUrl} onChange={update('turnUrl')} placeholder=\"turn:host:3478 (opcional)\" disabled={running} /></label>\n <label><span>TURN usuario</span><input type=\"text\" value={form.turnUser} onChange={update('turnUser')} autoComplete=\"off\" disabled={running} /></label>\n <label><span>TURN clave</span><input type=\"password\" value={form.turnPass} onChange={update('turnPass')} autoComplete=\"off\" disabled={running} /></label>\n <label><input type=\"checkbox\" checked={form.relayOnly} onChange={update('relayOnly')} disabled={running} /> Forzar solo TURN (relay)</label>\n <div className=\"row\">\n {!running\n ? <button type=\"button\" onClick={start} disabled={starting || Boolean(disabledReason)}>{starting ? 'Iniciando…' : 'Iniciar laboratorio'}</button>\n : <button type=\"button\" className=\"danger\" onClick={stop}>Detener y limpiar</button>}\n </div>\n </section>\n\n <section>\n <h2>Conexión</h2>\n <div className=\"row\">\n <button type=\"button\" onClick={() => linkRef.current?.connect()} disabled={!running}>Conectar con {peerName || 'rival'}</button>\n <button type=\"button\" className=\"secondary\" onClick={() => linkRef.current?.hangup()} disabled={!running}>Colgar</button>\n <button type=\"button\" className=\"secondary\" onClick={() => linkRef.current?.restartIce()} disabled={!running || s?.role !== 'caller'}>Reiniciar ICE</button>\n <button type=\"button\" className=\"secondary\" onClick={() => { signalingRef.current?.pause(8000); log('señalización cortada 8 s'); }} disabled={!running}>Cortar señalización 8 s</button>\n </div>\n <dl>\n <dt>Fase</dt><dd><span className={`pill ${PHASE_CLASS[phase] ?? ''}`} data-testid=\"phase\">{phase}</span>{s?.error ? ` · ${s.error}` : ''}</dd>\n <dt>WebSocket</dt><dd>{socketStatus}</dd>\n <dt>Ruta</dt><dd data-testid=\"route\">{s?.route ? <span className={`pill ${s.route.relay ? 'warn' : 'ok'}`}>{s.route.label}</span> : '—'}{s?.route ? ` · ${s.route.local}/${s.route.remote} · ${s.route.protocol}` : ''}</dd>\n <dt>Rol</dt><dd>{s?.role ?? '—'} · sesión {s?.sid?.slice(0, 8) ?? '—'} · gen {s?.gen ?? 0}</dd>\n <dt>ICE</dt><dd>{s?.ice ?? '—'} · conexión {s?.connection ?? '—'} · gathering {s?.gathering ?? '—'}</dd>\n <dt>Signaling</dt><dd>{s?.signalingState ?? '—'}</dd>\n <dt>Reintentos</dt><dd>reconexiones {s?.reconnects ?? 0} · ICE restarts {s?.restarts ?? 0}</dd>\n </dl>\n </section>\n\n <section>\n <h2>Métricas</h2>\n <dl>\n <dt>RTT (ping)</dt><dd data-testid=\"rtt\">{s?.rtt != null ? `${s.rtt} ms` : '—'}</dd>\n <dt>RTT (ICE)</dt><dd>{s?.statsRtt != null ? `${s.statsRtt} ms` : '—'}</dd>\n <dt>Movimiento</dt><dd>salida {s?.move.hzOut ?? 0} Hz · entrada {s?.move.hzIn ?? 0} Hz</dd>\n <dt>Paquetes</dt><dd data-testid=\"loss\">enviados {s?.move.sent ?? 0} · recibidos {s?.move.received ?? 0} · perdidos {s?.move.lossPct ?? 0} % · desordenados {s?.move.outOfOrder ?? 0} · descartados {s?.move.dropped ?? 0}</dd>\n <dt>Eventos</dt><dd>enviados {s?.events.sent ?? 0} · recibidos {s?.events.received ?? 0}</dd>\n <dt>Ráfaga</dt><dd data-testid=\"burst\">{burst.received}/{burst.expected} · errores de orden {burst.orderErrors}{burst.ms != null ? ` · ${burst.ms} ms` : ''}</dd>\n <dt>Señales</dt><dd>env {s?.signals.sent ?? 0} · rec {s?.signals.received ?? 0} · retrans {s?.signals.retransmits ?? 0} · dup {s?.signals.duplicates ?? 0} · ignor {s?.signals.ignored ?? 0} · inválidas {s?.signals.invalid ?? 0} · máx {s?.signals.maxLength ?? 0} chars</dd>\n </dl>\n <div className=\"row\">\n <label><span>Frecuencia</span>\n <select value={form.hz} onChange={update('hz')}>{HZ.map((hz) => <option key={hz} value={hz}>{hz} Hz</option>)}</select>\n </label>\n <button type=\"button\" onClick={() => setSending((v) => !v)} disabled={phase !== 'connected' && !sending}>{sending ? 'Parar posiciones' : 'Enviar posiciones'}</button>\n <button type=\"button\" className=\"secondary\" onClick={sendBurst} disabled={phase !== 'connected'}>Ráfaga 200 eventos</button>\n </div>\n </section>\n\n <section>\n <h2>Fallos de señalización (recepción)</h2>\n <label><span>Pérdida %</span><input type=\"number\" min=\"0\" max=\"90\" value={form.drop} onChange={update('drop')} /></label>\n <label><span>Duplicados %</span><input type=\"number\" min=\"0\" max=\"100\" value={form.duplicate} onChange={update('duplicate')} /></label>\n <label><span>Jitter ms</span><input type=\"number\" min=\"0\" max=\"5000\" value={form.jitter} onChange={update('jitter')} /></label>\n <p className=\"sub\">El jitter desordena los mensajes. Solo afectan a las señales, no al DataChannel.</p>\n </section>\n\n <section className=\"wide\">\n <h2>Simulación</h2>\n <canvas ref={canvasRef} />\n </section>\n\n <section className=\"wide\">\n <h2>Registro</h2>\n <div className=\"log\">{logs.join('\\n')}</div>\n </section>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"WebRtcLab-ClRSYt4E.js","names":["createPeerLink","withSignalFaults","PHASE_CLASS","HZ","STYLES","iceServersFrom","servers","stun","form","WebRtcLab","DEFAULT_ICE_SERVERS","setForm","useState","defaultPeerId","iceServers","server","state","setState","running","setRunning","starting","setStarting","sending","setSending","logs","setLogs","burst","setBurst","linkRef","useRef","signalingRef","formRef","remoteRef","localRef","canvasRef","burstRef","useEffect","current","log","items","line","update","value","event","key","stop","start","f","peerId","selfId","base","createSignaling","signaling","payload","received","b","selfName","error","onHide","startedAt","timer","me","frame","draw","canvas","w","h","ratio","ctx","dot","p","color","label","sendBurst","n","s","phase","peerName","peers","peer","title","disabledReason","children","socketStatus","hz","v"],"sources":["../../src/net/webrtc/WebRtcLab.jsx"],"sourcesContent":["import { useEffect, useRef, useState } from 'react';\nimport { createPeerLink, DEFAULT_ICE_SERVERS } from './createPeerLink.js';\nimport { withSignalFaults } from './signalFaults.js';\n\n// WebRTC lab (TANQUES LIVE groundwork): two users connect a DataChannel pair while\n// the chat carries only the signaling. Host-agnostic: the host passes who the user\n// is, who the peers are and createSignaling({ peerId }) → { send, subscribe }.\n// Exposes window.__rtcLab for automated checks.\n\nconst PHASE_CLASS = { connected: 'ok', listening: 'warn', calling: 'warn', negotiating: 'warn', restarting: 'warn', reconnecting: 'warn', failed: 'bad' };\nconst HZ = [10, 15, 20, 30, 60];\n\nconst STYLES = `\n.lira-rtc-lab { --bg:#0d1117; --panel:#161b22; --line:#30363d; --text:#e6edf3; --muted:#8b949e;\n color-scheme: dark; background: var(--bg); color: var(--text); font: 13px/1.45 system-ui, sans-serif; padding: 12px 16px 32px; border-radius: 12px; }\n.lira-rtc-lab h1 { font-size: 18px; margin: 4px 0 2px; }\n.lira-rtc-lab .sub { color: var(--muted); margin: 0 0 12px; }\n.lira-rtc-lab .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 12px; }\n.lira-rtc-lab section { background: var(--panel); border: 1px solid var(--line); border-radius: 10px; padding: 10px 12px; min-width: 0; }\n.lira-rtc-lab section h2 { font-size: 12px; margin: 0 0 8px; color: #c9d1d9; text-transform: uppercase; letter-spacing: .05em; }\n.lira-rtc-lab label { display: flex; gap: 6px; align-items: center; margin: 4px 0; flex-wrap: wrap; }\n.lira-rtc-lab label > span { min-width: 92px; color: var(--muted); }\n.lira-rtc-lab input, .lira-rtc-lab select { background: var(--bg); color: var(--text); border: 1px solid var(--line); border-radius: 6px; padding: 4px 6px; font: inherit; min-width: 0; }\n.lira-rtc-lab input[type=text], .lira-rtc-lab input[type=password] { flex: 1; }\n.lira-rtc-lab input[type=number] { width: 80px; }\n.lira-rtc-lab button { background: #238636; color: #fff; border: 0; border-radius: 6px; padding: 6px 10px; font: inherit; font-weight: 600; cursor: pointer; }\n.lira-rtc-lab button.secondary { background: var(--line); }\n.lira-rtc-lab button.danger { background: #b62324; }\n.lira-rtc-lab button:disabled { opacity: .45; cursor: not-allowed; }\n.lira-rtc-lab .row { display: flex; flex-wrap: wrap; gap: 6px; margin: 6px 0; align-items: center; }\n.lira-rtc-lab dl { display: grid; grid-template-columns: auto 1fr; gap: 2px 10px; margin: 0; }\n.lira-rtc-lab dt { color: var(--muted); }\n.lira-rtc-lab dd { margin: 0; font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }\n.lira-rtc-lab .pill { display: inline-block; padding: 1px 8px; border-radius: 999px; background: var(--line); font-weight: 600; }\n.lira-rtc-lab .ok { background: #1f6f3a; } .lira-rtc-lab .warn { background: #8a5a00; } .lira-rtc-lab .bad { background: #8e1f1f; }\n.lira-rtc-lab canvas { width: 100%; height: 220px; background: #0b1020; border-radius: 8px; display: block; }\n.lira-rtc-lab .log { height: 200px; overflow: auto; background: var(--bg); border-radius: 6px; padding: 6px; font: 11px ui-monospace, monospace; white-space: pre-wrap; }\n.lira-rtc-lab .wide { grid-column: 1 / -1; }\n`;\n\nfunction iceServersFrom(form) {\n const servers = [];\n const stun = form.stun.split(/[\\s,]+/).filter(Boolean);\n if (stun.length) servers.push({ urls: stun });\n if (form.turnUrl.trim()) servers.push({ urls: form.turnUrl.split(/[\\s,]+/).filter(Boolean), username: form.turnUser, credential: form.turnPass });\n return servers;\n}\n\n/**\n * @param {{\n * selfId: string|null, selfName?: string,\n * peers?: { id: string, name?: string }[], defaultPeerId?: string,\n * createSignaling: (opts: { peerId: string, log: (line: string) => void }) => any,\n * socketStatus?: string, disabledReason?: string, title?: string, children?: any,\n * iceServers?: RTCIceServer[],\n * }} props\n */\nexport default function WebRtcLab({\n selfId, selfName, peers = [], defaultPeerId = '', createSignaling, socketStatus = '—',\n disabledReason = '', title = 'WebRTC Lab · TANQUES LIVE', children = null, iceServers = DEFAULT_ICE_SERVERS,\n}) {\n const [form, setForm] = useState({\n peerId: defaultPeerId,\n stun: [].concat(iceServers.find((server) => !server.username)?.urls ?? []).join(' '),\n turnUrl: '', turnUser: '', turnPass: '', relayOnly: false,\n drop: 0, duplicate: 0, jitter: 0, hz: 20,\n });\n const [state, setState] = useState(null);\n const [running, setRunning] = useState(false);\n const [starting, setStarting] = useState(false);\n const [sending, setSending] = useState(false);\n const [logs, setLogs] = useState([]);\n const [burst, setBurst] = useState({ expected: 0, received: 0, orderErrors: 0, last: 0, ms: null, sentAt: 0 });\n const linkRef = useRef(null);\n const signalingRef = useRef(null);\n const formRef = useRef(form);\n const remoteRef = useRef(null);\n const localRef = useRef(null);\n const canvasRef = useRef(null);\n const burstRef = useRef(burst);\n formRef.current = form;\n burstRef.current = burst;\n\n useEffect(() => {\n if (!form.peerId && defaultPeerId) setForm((current) => ({ ...current, peerId: defaultPeerId }));\n }, [defaultPeerId, form.peerId]);\n\n const log = (line) => setLogs((items) => [...items.slice(-199), `${new Date().toISOString().slice(11, 23)} ${line}`]);\n const update = (key) => (event) => {\n const value = event.target.type === 'checkbox' ? event.target.checked : event.target.value;\n setForm((current) => ({ ...current, [key]: ['drop', 'duplicate', 'jitter', 'hz'].includes(key) ? Number(value) : value }));\n };\n\n const stop = () => {\n linkRef.current?.destroy();\n signalingRef.current?.dispose();\n linkRef.current = null;\n signalingRef.current = null;\n remoteRef.current = null;\n setRunning(false);\n setSending(false);\n setState(null);\n log('laboratorio detenido y recursos liberados');\n };\n\n const start = async () => {\n const f = formRef.current;\n const peerId = String(f.peerId ?? '').trim();\n if (!selfId || !peerId) { log('faltan ids de usuario'); return; }\n if (String(peerId) === String(selfId)) { log('el rival debe ser otro usuario'); return; }\n setStarting(true);\n try {\n const base = await createSignaling({ peerId, log });\n const signaling = withSignalFaults(base, () => formRef.current);\n signalingRef.current = signaling;\n linkRef.current = createPeerLink({\n signaling, selfId, peerId,\n iceServers: iceServersFrom(f),\n iceTransportPolicy: f.relayOnly ? 'relay' : 'all',\n onChange: setState,\n onMove: (payload) => { remoteRef.current = payload; },\n onEvent: (payload) => {\n if (payload?.resetBurst) { setBurst({ expected: 0, received: 0, orderErrors: 0, last: 0, ms: null, sentAt: performance.now() }); return; }\n if (payload?.burst == null) { log(`evento: ${JSON.stringify(payload).slice(0, 120)}`); return; }\n setBurst((b) => {\n const received = b.received + 1;\n return {\n ...b, received, last: payload.burst, expected: payload.total,\n orderErrors: b.orderErrors + (payload.burst === b.last + 1 ? 0 : 1),\n ms: received === payload.total ? Math.round(performance.now() - b.sentAt) : b.ms,\n };\n });\n },\n log,\n });\n setRunning(true);\n log(`laboratorio iniciado: yo ${selfName ?? selfId} · rival ${peerId}`);\n } catch (error) {\n log(`no se pudo iniciar la señalización: ${error?.message ?? error}`);\n } finally {\n setStarting(false);\n }\n };\n\n useEffect(() => () => { linkRef.current?.destroy(); signalingRef.current?.dispose(); }, []);\n useEffect(() => {\n const onHide = () => linkRef.current?.destroy();\n window.addEventListener('pagehide', onHide);\n return () => window.removeEventListener('pagehide', onHide);\n }, []);\n // A different user (logout/login) must not keep the old link.\n useEffect(() => () => { if (linkRef.current) stop(); }, [selfId]); // eslint-disable-line react-hooks/exhaustive-deps\n\n // Simulated tank: moves on a curve and streams its position at form.hz.\n useEffect(() => {\n if (!sending) return undefined;\n const startedAt = performance.now();\n const timer = setInterval(() => {\n const t = (performance.now() - startedAt) / 1000;\n const me = { x: 0.5 + 0.35 * Math.cos(t * 0.9), y: 0.5 + 0.3 * Math.sin(t * 1.3), a: t };\n localRef.current = me;\n linkRef.current?.sendMove({ x: Math.round(me.x * 1e4) / 1e4, y: Math.round(me.y * 1e4) / 1e4, a: Math.round(me.a * 100) / 100 });\n }, 1000 / form.hz);\n return () => clearInterval(timer);\n }, [sending, form.hz]);\n\n useEffect(() => {\n let frame = 0;\n const draw = () => {\n frame = requestAnimationFrame(draw);\n const canvas = canvasRef.current;\n if (!canvas) return;\n const { clientWidth: w, clientHeight: h } = canvas;\n const ratio = window.devicePixelRatio || 1;\n if (canvas.width !== Math.round(w * ratio)) { canvas.width = Math.round(w * ratio); canvas.height = Math.round(h * ratio); }\n const ctx = canvas.getContext('2d');\n ctx.setTransform(ratio, 0, 0, ratio, 0, 0);\n ctx.clearRect(0, 0, w, h);\n const dot = (p, color, label) => {\n if (!p) return;\n ctx.fillStyle = color;\n ctx.beginPath();\n ctx.arc(p.x * w, p.y * h, 9, 0, Math.PI * 2);\n ctx.fill();\n ctx.fillStyle = '#e6edf3';\n ctx.fillText(label, p.x * w + 12, p.y * h + 4);\n };\n dot(localRef.current, '#22c55e', 'yo');\n dot(remoteRef.current, '#ef4444', 'rival');\n };\n draw();\n return () => cancelAnimationFrame(frame);\n }, []);\n\n const sendBurst = () => {\n const total = 200;\n setBurst({ expected: total, received: 0, orderErrors: 0, last: 0, ms: null, sentAt: performance.now() });\n linkRef.current?.sendEvent({ resetBurst: true });\n for (let n = 1; n <= total; n += 1) linkRef.current?.sendEvent({ burst: n, total });\n log(`ráfaga de ${total} eventos fiables enviada`);\n };\n\n useEffect(() => {\n window.__rtcLab = { getState: () => linkRef.current?.getState() ?? null, burst: () => burstRef.current };\n });\n\n const s = state;\n const phase = s?.phase ?? 'idle';\n const peerName = peers.find((peer) => String(peer.id) === String(form.peerId))?.name ?? form.peerId;\n return (\n <div className=\"lira-rtc-lab\">\n <style>{STYLES}</style>\n <h1>{title}</h1>\n <p className=\"sub\">Señalización por el chat (<code>LIRA_WEBRTC_V1:</code> en <code>CHAT_MESSAGE</code>), datos por DataChannel.</p>\n {disabledReason ? <p className=\"sub\"><span className=\"pill bad\">{disabledReason}</span></p> : null}\n <div className=\"grid\">\n <section>\n <h2>Configuración</h2>\n {children}\n <label><span>Yo</span><strong>{selfName ?? selfId ?? '—'}</strong>{selfName && selfId ? <small> ({selfId})</small> : null}</label>\n <label><span>Rival</span>\n {peers.length ? (\n <select value={form.peerId} onChange={update('peerId')} disabled={running}>\n <option value=\"\">— elige —</option>\n {peers.filter((peer) => String(peer.id) !== String(selfId)).map((peer) => <option key={peer.id} value={peer.id}>{peer.name ?? peer.id}</option>)}\n </select>\n ) : null}\n <input type=\"text\" value={form.peerId} onChange={update('peerId')} placeholder=\"user_id del rival\" disabled={running} />\n </label>\n <label><span>STUN</span><input type=\"text\" value={form.stun} onChange={update('stun')} disabled={running} /></label>\n <label><span>TURN</span><input type=\"text\" value={form.turnUrl} onChange={update('turnUrl')} placeholder=\"turn:host:3478 (opcional)\" disabled={running} /></label>\n <label><span>TURN usuario</span><input type=\"text\" value={form.turnUser} onChange={update('turnUser')} autoComplete=\"off\" disabled={running} /></label>\n <label><span>TURN clave</span><input type=\"password\" value={form.turnPass} onChange={update('turnPass')} autoComplete=\"off\" disabled={running} /></label>\n <label><input type=\"checkbox\" checked={form.relayOnly} onChange={update('relayOnly')} disabled={running} /> Forzar solo TURN (relay)</label>\n <div className=\"row\">\n {!running\n ? <button type=\"button\" onClick={start} disabled={starting || Boolean(disabledReason)}>{starting ? 'Iniciando…' : 'Iniciar laboratorio'}</button>\n : <button type=\"button\" className=\"danger\" onClick={stop}>Detener y limpiar</button>}\n </div>\n </section>\n\n <section>\n <h2>Conexión</h2>\n <div className=\"row\">\n <button type=\"button\" onClick={() => linkRef.current?.connect()} disabled={!running}>Conectar con {peerName || 'rival'}</button>\n <button type=\"button\" className=\"secondary\" onClick={() => linkRef.current?.hangup()} disabled={!running}>Colgar</button>\n <button type=\"button\" className=\"secondary\" onClick={() => linkRef.current?.restartIce()} disabled={!running || s?.role !== 'caller'}>Reiniciar ICE</button>\n <button type=\"button\" className=\"secondary\" onClick={() => { signalingRef.current?.pause(8000); log('señalización cortada 8 s'); }} disabled={!running}>Cortar señalización 8 s</button>\n </div>\n <dl>\n <dt>Fase</dt><dd><span className={`pill ${PHASE_CLASS[phase] ?? ''}`} data-testid=\"phase\">{phase}</span>{s?.error ? ` · ${s.error}` : ''}</dd>\n <dt>WebSocket</dt><dd>{socketStatus}</dd>\n <dt>Ruta</dt><dd data-testid=\"route\">{s?.route ? <span className={`pill ${s.route.relay ? 'warn' : 'ok'}`}>{s.route.label}</span> : '—'}{s?.route ? ` · ${s.route.local}/${s.route.remote} · ${s.route.protocol}` : ''}</dd>\n <dt>Rol</dt><dd>{s?.role ?? '—'} · sesión {s?.sid?.slice(0, 8) ?? '—'} · gen {s?.gen ?? 0}</dd>\n <dt>ICE</dt><dd>{s?.ice ?? '—'} · conexión {s?.connection ?? '—'} · gathering {s?.gathering ?? '—'}</dd>\n <dt>Signaling</dt><dd>{s?.signalingState ?? '—'}</dd>\n <dt>Reintentos</dt><dd>reconexiones {s?.reconnects ?? 0} · ICE restarts {s?.restarts ?? 0}</dd>\n </dl>\n </section>\n\n <section>\n <h2>Métricas</h2>\n <dl>\n <dt>RTT (ping)</dt><dd data-testid=\"rtt\">{s?.rtt != null ? `${s.rtt} ms` : '—'}</dd>\n <dt>RTT (ICE)</dt><dd>{s?.statsRtt != null ? `${s.statsRtt} ms` : '—'}</dd>\n <dt>Movimiento</dt><dd>salida {s?.move.hzOut ?? 0} Hz · entrada {s?.move.hzIn ?? 0} Hz</dd>\n <dt>Paquetes</dt><dd data-testid=\"loss\">enviados {s?.move.sent ?? 0} · recibidos {s?.move.received ?? 0} · perdidos {s?.move.lossPct ?? 0} % · desordenados {s?.move.outOfOrder ?? 0} · descartados {s?.move.dropped ?? 0}</dd>\n <dt>Eventos</dt><dd>enviados {s?.events.sent ?? 0} · recibidos {s?.events.received ?? 0}</dd>\n <dt>Ráfaga</dt><dd data-testid=\"burst\">{burst.received}/{burst.expected} · errores de orden {burst.orderErrors}{burst.ms != null ? ` · ${burst.ms} ms` : ''}</dd>\n <dt>Señales</dt><dd>env {s?.signals.sent ?? 0} · rec {s?.signals.received ?? 0} · retrans {s?.signals.retransmits ?? 0} · dup {s?.signals.duplicates ?? 0} · ignor {s?.signals.ignored ?? 0} · inválidas {s?.signals.invalid ?? 0} · máx {s?.signals.maxLength ?? 0} chars</dd>\n </dl>\n <div className=\"row\">\n <label><span>Frecuencia</span>\n <select value={form.hz} onChange={update('hz')}>{HZ.map((hz) => <option key={hz} value={hz}>{hz} Hz</option>)}</select>\n </label>\n <button type=\"button\" onClick={() => setSending((v) => !v)} disabled={phase !== 'connected' && !sending}>{sending ? 'Parar posiciones' : 'Enviar posiciones'}</button>\n <button type=\"button\" className=\"secondary\" onClick={sendBurst} disabled={phase !== 'connected'}>Ráfaga 200 eventos</button>\n </div>\n </section>\n\n <section>\n <h2>Fallos de señalización (recepción)</h2>\n <label><span>Pérdida %</span><input type=\"number\" min=\"0\" max=\"90\" value={form.drop} onChange={update('drop')} /></label>\n <label><span>Duplicados %</span><input type=\"number\" min=\"0\" max=\"100\" value={form.duplicate} onChange={update('duplicate')} /></label>\n <label><span>Jitter ms</span><input type=\"number\" min=\"0\" max=\"5000\" value={form.jitter} onChange={update('jitter')} /></label>\n <p className=\"sub\">El jitter desordena los mensajes. Solo afectan a las señales, no al DataChannel.</p>\n </section>\n\n <section className=\"wide\">\n <h2>Simulación</h2>\n <canvas ref={canvasRef} />\n </section>\n\n <section className=\"wide\">\n <h2>Registro</h2>\n <div className=\"log\">{logs.join('\\n')}</div>\n </section>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;AASA,IAAME,IAAc;CAAE,WAAW;CAAM,WAAW;CAAQ,SAAS;CAAQ,aAAa;CAAQ,YAAY;CAAQ,cAAc;CAAQ,QAAQ;AAAM,GAClJC,IAAK;CAAC;CAAI;CAAI;CAAI;CAAI;AAAE,GAExBC,IAAS;AA4Bf,SAASC,EAAe,GAAM;CAC5B,IAAMC,IAAU,CAAC,GACXC,IAAOC,EAAK,KAAK,MAAM,QAAQ,CAAC,CAAC,OAAO,OAAO;CAGrD,OAFID,EAAK,UAAQD,EAAQ,KAAK,EAAE,MAAMC,EAAK,CAAC,GACxCC,EAAK,QAAQ,KAAK,KAAGF,EAAQ,KAAK;EAAE,MAAME,EAAK,QAAQ,MAAM,QAAQ,CAAC,CAAC,OAAO,OAAO;EAAG,UAAUA,EAAK;EAAU,YAAYA,EAAK;CAAS,CAAC,GACzIF;AACT;AAWA,SAAwBG,EAAU,EAChC,WAAQ,aAAU,WAAQ,CAAC,GAAG,mBAAgB,IAAI,oBAAiB,kBAAe,KAClF,oBAAiB,IAAI,WAAQ,6BAA6B,cAAW,MAAM,gBAAaC,KACvF;CACD,IAAM,CAACF,GAAMG,KAAWC,EAAS;EAC/B,QAAQC;EACR,MAAM,CAAC,CAAC,CAAC,OAAOC,EAAW,MAAM,MAAW,CAACC,EAAO,QAAQ,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG;EACnF,SAAS;EAAI,UAAU;EAAI,UAAU;EAAI,WAAW;EACpD,MAAM;EAAG,WAAW;EAAG,QAAQ;EAAG,IAAI;CACxC,CAAC,GACK,CAACC,GAAOC,KAAYL,EAAS,IAAI,GACjC,CAACM,GAASC,KAAcP,EAAS,EAAK,GACtC,CAACQ,GAAUC,KAAeT,EAAS,EAAK,GACxC,CAACU,GAASC,KAAcX,EAAS,EAAK,GACtC,CAACY,GAAMC,KAAWb,EAAS,CAAC,CAAC,GAC7B,CAACc,GAAOC,KAAYf,EAAS;EAAE,UAAU;EAAG,UAAU;EAAG,aAAa;EAAG,MAAM;EAAG,IAAI;EAAM,QAAQ;CAAE,CAAC,GACvGgB,IAAUC,EAAO,IAAI,GACrBC,IAAeD,EAAO,IAAI,GAC1BE,IAAUF,EAAOrB,CAAI,GACrBwB,IAAYH,EAAO,IAAI,GACvBI,IAAWJ,EAAO,IAAI,GACtBK,IAAYL,EAAO,IAAI,GACvBM,IAAWN,EAAOH,CAAK;CAI7B,AAHA,EAAQ,UAAUlB,GAClB,EAAS,UAAUkB,GAEnBU,QAAgB;EACd,AAAI,CAAC5B,EAAK,UAAUK,KAAeF,GAAS,OAAa;GAAE,GAAG0B;GAAS,QAAQxB;EAAc,EAAE;CACjG,GAAG,CAACA,GAAeL,EAAK,MAAM,CAAC;CAE/B,IAAM8B,KAAO,MAASb,GAAS,MAAU,CAAC,GAAGc,EAAM,MAAM,IAAI,GAAG,oBAAG,IAAI,KAAK,EAAA,CAAE,YAAY,CAAC,CAAC,MAAM,IAAI,EAAE,EAAE,GAAGC,GAAM,CAAC,GAC9GC,KAAU,OAAS,MAAU;EACjC,IAAMC,IAAQC,EAAM,OAAO,SAAS,aAAaA,EAAM,OAAO,UAAUA,EAAM,OAAO;EACrF,GAAS,OAAa;GAAE,GAAGN;IAAUO,IAAM;IAAC;IAAQ;IAAa;IAAU;GAAI,CAAC,CAAC,SAASA,CAAG,IAAI,OAAOF,CAAK,IAAIA;EAAM,EAAE;CAC3H,GAEMG,UAAa;EASjB,AARAjB,EAAQ,SAAS,QAAQ,GACzBE,EAAa,SAAS,QAAQ,GAC9B,EAAQ,UAAU,MAClB,EAAa,UAAU,MACvB,EAAU,UAAU,MACpBX,EAAW,EAAK,GAChBI,EAAW,EAAK,GAChBN,EAAS,IAAI,GACbqB,EAAI,2CAA2C;CACjD,GAEMQ,IAAQ,YAAY;EACxB,IAAMC,IAAIhB,EAAQ,SACZiB,IAAS,OAAOD,EAAE,UAAU,EAAE,CAAC,CAAC,KAAK;EAC3C,IAAI,CAACE,KAAU,CAACD,GAAU,EAAI,uBAAuB;OACrD,IAAI,OAAOA,CAAM,MAAM,OAAOC,CAAM,GAAK,EAAI,gCAAgC;OAC7E;KAAY,EAAI;GAChB,IAAI;IACF,IAAMC,IAAO,MAAMC,EAAgB;KAAE;KAAQ;IAAI,CAAC,GAC5CC,IAAYnD,EAAiBiD,SAAYnB,EAAQ,OAAO;IAuB9D,AAtBA,EAAa,UAAUqB,GACvB,EAAQ,UAAUpD,EAAe;KAC/B;KAAW;KAAQ;KACnB,YAAYK,EAAe0C,CAAC;KAC5B,oBAAoBA,EAAE,YAAY,UAAU;KAC5C,UAAU9B;KACV,SAAS,MAAY;MAAE,EAAU,UAAUoC;KAAS;KACpD,UAAU,MAAY;MACpB,AAAIA,GAAS,aAAc1B,EAAS;OAAE,UAAU;OAAG,UAAU;OAAG,aAAa;OAAG,MAAM;OAAG,IAAI;OAAM,QAAQ,YAAY,IAAI;MAAE,CAAC,IAC1H0B,GAAS,SAAS,OAAQf,EAAI,WAAW,KAAK,UAAUe,CAAO,CAAC,CAAC,MAAM,GAAG,GAAG,GAAG,IACpF1B,GAAU,MAAM;OACd,IAAM2B,IAAWC,EAAE,WAAW;OAC9B,OAAO;QACL,GAAGA;QAAG;QAAU,MAAMF,EAAQ;QAAO,UAAUA,EAAQ;QACvD,aAAaE,EAAE,eAAeF,EAAQ,UAAUE,EAAE,OAAO,IAAI,IAAI;QACjE,IAAID,MAAaD,EAAQ,QAAQ,KAAK,MAAM,YAAY,IAAI,IAAIE,EAAE,MAAM,IAAIA,EAAE;OAChF;MACF,CAAC;KACH;KACA;IACF,CAAC,GACDpC,EAAW,EAAI,GACfmB,EAAI,4BAA4BkB,KAAYP,EAAO,WAAWD,GAAQ;GACxE,SAASS,GAAO;IACd,EAAI,uCAAuCA,GAAO,WAAWA,GAAO;GACtE,UAAU;IACR,EAAY,EAAK;GACnB;EA/BgB;CAgClB;CAwBA,AAtBArB,cAAsB;EAA8B,AAA5BR,EAAQ,SAAS,QAAQ,GAAGE,EAAa,SAAS,QAAQ;CAAG,GAAG,CAAC,CAAC,GAC1FM,QAAgB;EACd,IAAMsB,UAAe9B,EAAQ,SAAS,QAAQ;EAE9C,OADA,OAAO,iBAAiB,YAAY8B,CAAM,SAC7B,OAAO,oBAAoB,YAAYA,CAAM;CAC5D,GAAG,CAAC,CAAC,GAELtB,cAAsB;EAAE,AAAIR,EAAQ,WAASiB,EAAK;CAAG,GAAG,CAACI,CAAM,CAAC,GAGhEb,QAAgB;EACd,IAAI,CAACd,GAAS;EACd,IAAMqC,IAAY,YAAY,IAAI,GAC5BC,IAAQ,kBAAkB;GAC9B,IAAM,KAAK,YAAY,IAAI,IAAID,KAAa,KACtCE,IAAK;IAAE,GAAG,KAAM,MAAO,KAAK,IAAI,IAAI,EAAG;IAAG,GAAG,KAAM,KAAM,KAAK,IAAI,IAAI,GAAG;IAAG,GAAG;GAAE;GAEvF,AADA,EAAS,UAAUA,GACnBjC,EAAQ,SAAS,SAAS;IAAE,GAAG,KAAK,MAAMiC,EAAG,IAAI,GAAG,IAAI;IAAK,GAAG,KAAK,MAAMA,EAAG,IAAI,GAAG,IAAI;IAAK,GAAG,KAAK,MAAMA,EAAG,IAAI,GAAG,IAAI;GAAI,CAAC;EACjI,GAAG,MAAOrD,EAAK,EAAE;EACjB,aAAa,cAAcoD,CAAK;CAClC,GAAG,CAACtC,GAASd,EAAK,EAAE,CAAC,GAErB4B,QAAgB;EACd,IAAI0B,IAAQ,GACNC,UAAa;GACjB,IAAQ,sBAAsBA,CAAI;GAClC,IAAMC,IAAS9B,EAAU;GACzB,IAAI,CAAC8B,GAAQ;GACb,IAAM,EAAE,aAAaC,GAAG,cAAcC,MAAMF,GACtCG,IAAQ,OAAO,oBAAoB;GACzC,AAAIH,EAAO,UAAU,KAAK,MAAMC,IAAIE,CAAK,MAAK,EAAO,QAAQ,KAAK,MAAMF,IAAIE,CAAK,GAAG,EAAO,SAAS,KAAK,MAAMD,IAAIC,CAAK;GACxH,IAAMC,IAAMJ,EAAO,WAAW,IAAI;GAElC,AADAI,EAAI,aAAaD,GAAO,GAAG,GAAGA,GAAO,GAAG,CAAC,GACzCC,EAAI,UAAU,GAAG,GAAGH,GAAGC,CAAC;GACxB,IAAMG,KAAO,GAAG,GAAO,MAAU;IAC/B,AAAKC,MACL,EAAI,YAAYC,GAChBH,EAAI,UAAU,GACdA,EAAI,IAAIE,EAAE,IAAIL,GAAGK,EAAE,IAAIJ,GAAG,GAAG,GAAG,KAAK,KAAK,CAAC,GAC3CE,EAAI,KAAK,GACT,EAAI,YAAY,WAChBA,EAAI,SAASI,GAAOF,EAAE,IAAIL,IAAI,IAAIK,EAAE,IAAIJ,IAAI,CAAC;GAC/C;GAEA,AADAG,EAAIpC,EAAS,SAAS,WAAW,IAAI,GACrCoC,EAAIrC,EAAU,SAAS,WAAW,OAAO;EAC3C;EAEA,OADA+B,EAAK,SACQ,qBAAqBD,CAAK;CACzC,GAAG,CAAC,CAAC;CAEL,IAAMW,UAAkB;EAGtB,AADA9C,EAAS;GAAE,UAAU;GAAO,UAAU;GAAG,aAAa;GAAG,MAAM;GAAG,IAAI;GAAM,QAAQ,YAAY,IAAI;EAAE,CAAC,GACvGC,EAAQ,SAAS,UAAU,EAAE,YAAY,GAAK,CAAC;EAC/C,KAAK,IAAI8C,IAAI,GAAGA,KAAK,KAAO,KAAK,GAAG,EAAQ,SAAS,UAAU;GAAE,OAAOA;GAAG;EAAM,CAAC;EAClF,EAAI,uCAA4C;CAClD;CAEA,QAAgB;EACd,OAAO,WAAW;GAAE,gBAAgB9C,EAAQ,SAAS,SAAS,KAAK;GAAM,aAAaO,EAAS;EAAQ;CACzG,CAAC;CAED,IAAMwC,IAAI3D,GACJ4D,IAAQD,GAAG,SAAS,QACpBE,IAAWC,EAAM,MAAM,MAAS,OAAOC,EAAK,EAAE,MAAM,OAAOvE,EAAK,MAAM,CAAC,CAAC,EAAE,QAAQA,EAAK;CAC7F,OACE,kBAAC,OAAD;EAAK,WAAU;EAAf,UAAA;GACE,kBAAC,SAAD,EAAA,UAAQJ,EAAc,CAAA;GACtB,kBAAC,MAAD,EAAA,UAAK4E,EAAU,CAAA;GACf,kBAAC,KAAD;IAAG,WAAU;IAAb,UAAA;KAAmB;KAA0B,kBAAC,QAAD,EAAA,UAAM,kBAAqB,CAAA;KAAC;KAAI,kBAAC,QAAD,EAAA,UAAM,eAAkB,CAAA;KAAC;IAA4B;;GACjIC,IAAiB,kBAAC,KAAD;IAAG,WAAU;IAAM,UAAA,kBAAC,QAAD;KAAM,WAAU;KAAY,UAAAA;IAAqB,CAAA;GAAI,CAAA,IAAI;GAC9F,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA;KACE,kBAAC,WAAD,EAAA,UAAA;MACE,kBAAC,MAAD,EAAA,UAAI,gBAAiB,CAAA;MACpBC;MACD,kBAAC,SAAD,EAAA,UAAA;OAAO,kBAAC,QAAD,EAAA,UAAM,KAAQ,CAAA;OAAC,kBAAC,UAAD,EAAA,UAAS1B,KAAYP,KAAU,IAAY,CAAA;OAAEO,KAAYP,IAAS,kBAAC,SAAD,EAAA,UAAA;QAAO;QAAGA;QAAO;OAAQ,EAAA,CAAA,IAAI;MAAY,EAAA,CAAA;MACjI,kBAAC,SAAD,EAAA,UAAA;OAAO,kBAAC,QAAD,EAAA,UAAM,QAAW,CAAA;OACrB6B,EAAM,SACL,kBAAC,UAAD;QAAQ,OAAOtE,EAAK;QAAQ,UAAUiC,EAAO,QAAQ;QAAG,UAAUvB;QAAlE,UAAA,CACE,kBAAC,UAAD;SAAQ,OAAM;SAAG,UAAA;QAAiB,CAAA,GACjC4D,EAAM,QAAQ,MAAS,OAAOC,EAAK,EAAE,MAAM,OAAO9B,CAAM,CAAC,CAAC,CAAC,KAAK,MAAS,kBAAC,UAAD;SAAsB,OAAO8B,EAAK;SAAK,UAAAA,EAAK,QAAQA,EAAK;QAAW,GAAvDA,EAAK,EAAkD,CAAC,CACzI;OACN,CAAA,IAAA;OACJ,kBAAC,SAAD;QAAO,MAAK;QAAO,OAAOvE,EAAK;QAAQ,UAAUiC,EAAO,QAAQ;QAAG,aAAY;QAAoB,UAAUvB;OAAU,CAAA;MAClH,EAAA,CAAA;MACP,kBAAC,SAAD,EAAA,UAAA,CAAO,kBAAC,QAAD,EAAA,UAAM,OAAU,CAAA,GAAC,kBAAC,SAAD;OAAO,MAAK;OAAO,OAAOV,EAAK;OAAM,UAAUiC,EAAO,MAAM;OAAG,UAAUvB;MAAU,CAAA,CAAQ,EAAA,CAAA;MACnH,kBAAC,SAAD,EAAA,UAAA,CAAO,kBAAC,QAAD,EAAA,UAAM,OAAU,CAAA,GAAC,kBAAC,SAAD;OAAO,MAAK;OAAO,OAAOV,EAAK;OAAS,UAAUiC,EAAO,SAAS;OAAG,aAAY;OAA4B,UAAUvB;MAAU,CAAA,CAAQ,EAAA,CAAA;MACjK,kBAAC,SAAD,EAAA,UAAA,CAAO,kBAAC,QAAD,EAAA,UAAM,eAAkB,CAAA,GAAC,kBAAC,SAAD;OAAO,MAAK;OAAO,OAAOV,EAAK;OAAU,UAAUiC,EAAO,UAAU;OAAG,cAAa;OAAM,UAAUvB;MAAU,CAAA,CAAQ,EAAA,CAAA;MACtJ,kBAAC,SAAD,EAAA,UAAA,CAAO,kBAAC,QAAD,EAAA,UAAM,aAAgB,CAAA,GAAC,kBAAC,SAAD;OAAO,MAAK;OAAW,OAAOV,EAAK;OAAU,UAAUiC,EAAO,UAAU;OAAG,cAAa;OAAM,UAAUvB;MAAU,CAAA,CAAQ,EAAA,CAAA;MACxJ,kBAAC,SAAD,EAAA,UAAA,CAAO,kBAAC,SAAD;OAAO,MAAK;OAAW,SAASV,EAAK;OAAW,UAAUiC,EAAO,WAAW;OAAG,UAAUvB;MAAU,CAAA,GAAC,2BAAgC,EAAA,CAAA;MAC3I,kBAAC,OAAD;OAAK,WAAU;OACZ,UAACA,IAEE,kBAAC,UAAD;QAAQ,MAAK;QAAS,WAAU;QAAS,SAAS2B;QAAM,UAAA;OAAyB,CAAA,IADjF,kBAAC,UAAD;QAAQ,MAAK;QAAS,SAASC;QAAO,UAAU1B,KAAY,EAAQ6D;QAAkB,UAAA7D,IAAW,eAAe;OAA8B,CAAA;MAE/I,CAAA;KACE,EAAA,CAAA;KAET,kBAAC,WAAD,EAAA,UAAA;MACE,kBAAC,MAAD,EAAA,UAAI,WAAY,CAAA;MAChB,kBAAC,OAAD;OAAK,WAAU;OAAf,UAAA;QACE,kBAAC,UAAD;SAAQ,MAAK;SAAS,eAAeQ,EAAQ,SAAS,QAAQ;SAAG,UAAU,CAACV;SAA5E,UAAA,CAAqF,iBAAc2D,KAAY,OAAgB;;QAC/H,kBAAC,UAAD;SAAQ,MAAK;SAAS,WAAU;SAAY,eAAejD,EAAQ,SAAS,OAAO;SAAG,UAAU,CAACV;SAAS,UAAA;QAAc,CAAA;QACxH,kBAAC,UAAD;SAAQ,MAAK;SAAS,WAAU;SAAY,eAAeU,EAAQ,SAAS,WAAW;SAAG,UAAU,CAACV,KAAWyD,GAAG,SAAS;SAAU,UAAA;QAAqB,CAAA;QAC3J,kBAAC,UAAD;SAAQ,MAAK;SAAS,WAAU;SAAY,eAAe;UAAqC,AAAnC7C,EAAa,SAAS,MAAM,GAAI,GAAGQ,EAAI,0BAA0B;SAAG;SAAG,UAAU,CAACpB;SAAS,UAAA;QAA+B,CAAA;OACpL;;MACL,kBAAC,MAAD,EAAA,UAAA;OACE,kBAAC,MAAD,EAAA,UAAI,OAAQ,CAAA;OAAC,kBAAC,MAAD,EAAA,UAAA,CAAI,kBAAC,QAAD;QAAM,WAAW,QAAQhB,EAAY0E,MAAU;QAAM,eAAY;QAAS,UAAAA;OAAY,CAAA,GAAED,GAAG,QAAQ,MAAMA,EAAE,UAAU,EAAO,EAAA,CAAA;OAC7I,kBAAC,MAAD,EAAA,UAAI,YAAa,CAAA;OAAC,kBAAC,MAAD,EAAA,UAAKQ,EAAiB,CAAA;OACxC,kBAAC,MAAD,EAAA,UAAI,OAAQ,CAAA;OAAC,kBAAC,MAAD;QAAI,eAAY;QAAhB,UAAA,CAAyBR,GAAG,QAAQ,kBAAC,QAAD;SAAM,WAAW,QAAQA,EAAE,MAAM,QAAQ,SAAS;SAAS,UAAAA,EAAE,MAAM;QAAY,CAAA,IAAI,KAAKA,GAAG,QAAQ,MAAMA,EAAE,MAAM,MAAM,GAAGA,EAAE,MAAM,OAAO,KAAKA,EAAE,MAAM,aAAa,EAAO;;OAC3N,kBAAC,MAAD,EAAA,UAAI,MAAO,CAAA;OAAC,kBAAC,MAAD,EAAA,UAAA;QAAKA,GAAG,QAAQ;QAAI;QAAWA,GAAG,KAAK,MAAM,GAAG,CAAC,KAAK;QAAI;QAAQA,GAAG,OAAO;OAAM,EAAA,CAAA;OAC9F,kBAAC,MAAD,EAAA,UAAI,MAAO,CAAA;OAAC,kBAAC,MAAD,EAAA,UAAA;QAAKA,GAAG,OAAO;QAAI;QAAaA,GAAG,cAAc;QAAI;QAAcA,GAAG,aAAa;OAAQ,EAAA,CAAA;OACvG,kBAAC,MAAD,EAAA,UAAI,YAAa,CAAA;OAAC,kBAAC,MAAD,EAAA,UAAKA,GAAG,kBAAkB,IAAQ,CAAA;OACpD,kBAAC,MAAD,EAAA,UAAI,aAAc,CAAA;OAAC,kBAAC,MAAD,EAAA,UAAA;QAAI;QAAcA,GAAG,cAAc;QAAE;QAAiBA,GAAG,YAAY;OAAM,EAAA,CAAA;MAC5F,EAAA,CAAA;KACG,EAAA,CAAA;KAET,kBAAC,WAAD,EAAA,UAAA;MACE,kBAAC,MAAD,EAAA,UAAI,WAAY,CAAA;MAChB,kBAAC,MAAD,EAAA,UAAA;OACE,kBAAC,MAAD,EAAA,UAAI,aAAc,CAAA;OAAC,kBAAC,MAAD;QAAI,eAAY;QAAO,UAAAA,GAAG,OAAO,OAAuB,MAAhB,GAAGA,EAAE,IAAI;OAAe,CAAA;OACnF,kBAAC,MAAD,EAAA,UAAI,YAAa,CAAA;OAAC,kBAAC,MAAD,EAAA,UAAKA,GAAG,YAAY,OAA4B,MAArB,GAAGA,EAAE,SAAS,KAAe,CAAA;OAC1E,kBAAC,MAAD,EAAA,UAAI,aAAc,CAAA;OAAC,kBAAC,MAAD,EAAA,UAAA;QAAI;QAAQA,GAAG,KAAK,SAAS;QAAE;QAAeA,GAAG,KAAK,QAAQ;QAAE;OAAO,EAAA,CAAA;OAC1F,kBAAC,MAAD,EAAA,UAAI,WAAY,CAAA;OAAC,kBAAC,MAAD;QAAI,eAAY;QAAhB,UAAA;SAAuB;SAAUA,GAAG,KAAK,QAAQ;SAAE;SAAcA,GAAG,KAAK,YAAY;SAAE;SAAaA,GAAG,KAAK,WAAW;SAAE;SAAmBA,GAAG,KAAK,cAAc;SAAE;SAAgBA,GAAG,KAAK,WAAW;QAAM;;OAC9N,kBAAC,MAAD,EAAA,UAAI,UAAW,CAAA;OAAC,kBAAC,MAAD,EAAA,UAAA;QAAI;QAAUA,GAAG,OAAO,QAAQ;QAAE;QAAcA,GAAG,OAAO,YAAY;OAAM,EAAA,CAAA;OAC5F,kBAAC,MAAD,EAAA,UAAI,SAAU,CAAA;OAAC,kBAAC,MAAD;QAAI,eAAY;QAAhB,UAAA;SAAyBjD,EAAM;SAAS;SAAEA,EAAM;SAAS;SAAqBA,EAAM;SAAaA,EAAM,MAAM,OAA6B,KAAtB,MAAMA,EAAM,GAAG;QAAc;;OAChK,kBAAC,MAAD,EAAA,UAAI,UAAW,CAAA;OAAC,kBAAC,MAAD,EAAA,UAAA;QAAI;QAAKiD,GAAG,QAAQ,QAAQ;QAAE;QAAQA,GAAG,QAAQ,YAAY;QAAE;QAAYA,GAAG,QAAQ,eAAe;QAAE;QAAQA,GAAG,QAAQ,cAAc;QAAE;QAAUA,GAAG,QAAQ,WAAW;QAAE;QAAcA,GAAG,QAAQ,WAAW;QAAE;QAAQA,GAAG,QAAQ,aAAa;QAAE;OAAU,EAAA,CAAA;MAC5Q,EAAA,CAAA;MACJ,kBAAC,OAAD;OAAK,WAAU;OAAf,UAAA;QACE,kBAAC,SAAD,EAAA,UAAA,CAAO,kBAAC,QAAD,EAAA,UAAM,aAAgB,CAAA,GAC3B,kBAAC,UAAD;SAAQ,OAAOnE,EAAK;SAAI,UAAUiC,EAAO,IAAI;SAAI,UAAAtC,EAAG,KAAK,MAAO,kBAAC,UAAD;UAAiB,OAAOiF;UAAxB,UAAA,CAA6BA,GAAG,KAAW;SAA9B,GAAAA,CAA8B,CAAC;QAAU,CAAA,CACjH,EAAA,CAAA;QACP,kBAAC,UAAD;SAAQ,MAAK;SAAS,eAAe7D,GAAY,MAAM,CAAC8D,CAAC;SAAG,UAAUT,MAAU,eAAe,CAACtD;SAAU,UAAAA,IAAU,qBAAqB;QAA4B,CAAA;QACrK,kBAAC,UAAD;SAAQ,MAAK;SAAS,WAAU;SAAY,SAASmD;SAAW,UAAUG,MAAU;SAAa,UAAA;QAA0B,CAAA;OACxH;;KACE,EAAA,CAAA;KAET,kBAAC,WAAD,EAAA,UAAA;MACE,kBAAC,MAAD,EAAA,UAAI,qCAAsC,CAAA;MAC1C,kBAAC,SAAD,EAAA,UAAA,CAAO,kBAAC,QAAD,EAAA,UAAM,YAAe,CAAA,GAAC,kBAAC,SAAD;OAAO,MAAK;OAAS,KAAI;OAAI,KAAI;OAAK,OAAOpE,EAAK;OAAM,UAAUiC,EAAO,MAAM;MAAI,CAAA,CAAQ,EAAA,CAAA;MACxH,kBAAC,SAAD,EAAA,UAAA,CAAO,kBAAC,QAAD,EAAA,UAAM,eAAkB,CAAA,GAAC,kBAAC,SAAD;OAAO,MAAK;OAAS,KAAI;OAAI,KAAI;OAAM,OAAOjC,EAAK;OAAW,UAAUiC,EAAO,WAAW;MAAI,CAAA,CAAQ,EAAA,CAAA;MACtI,kBAAC,SAAD,EAAA,UAAA,CAAO,kBAAC,QAAD,EAAA,UAAM,YAAe,CAAA,GAAC,kBAAC,SAAD;OAAO,MAAK;OAAS,KAAI;OAAI,KAAI;OAAO,OAAOjC,EAAK;OAAQ,UAAUiC,EAAO,QAAQ;MAAI,CAAA,CAAQ,EAAA,CAAA;MAC9H,kBAAC,KAAD;OAAG,WAAU;OAAM,UAAA;MAAmF,CAAA;KAC/F,EAAA,CAAA;KAET,kBAAC,WAAD;MAAS,WAAU;MAAnB,UAAA,CACE,kBAAC,MAAD,EAAA,UAAI,aAAc,CAAA,GAClB,kBAAC,UAAD,EAAQ,KAAKP,EAAY,CAAA,CAClB;;KAET,kBAAC,WAAD;MAAS,WAAU;MAAnB,UAAA,CACE,kBAAC,MAAD,EAAA,UAAI,WAAY,CAAA,GAChB,kBAAC,OAAD;OAAK,WAAU;OAAO,UAAAV,EAAK,KAAK,IAAI;MAAO,CAAA,CACpC;;IACN;;EACF;;AAET"}
@@ -1,4 +1,4 @@
1
- import { a as e, c as t, i as n, l as r, n as i, o as a, r as o, s } from "./TanksLiveGameCard-BNJqWt1z.js";
1
+ import { a as e, c as t, i as n, l as r, n as i, o as a, r as o, s } from "./TanksLiveGameCard-DGsnMD3j.js";
2
2
  import { _ as c, a as l, c as u, d, f, h as p, i as m, l as ee, m as te, n as h, o as ne, p as re, r as ie, s as ae, t as oe, u as se } from "./fx-BHsl4S_J.js";
3
3
  import { ACESFilmicToneMapping as ce, DirectionalLight as le, DynamicDrawUsage as ue, Fog as de, Group as fe, HemisphereLight as pe, InstancedMesh as me, Matrix4 as he, MeshBasicMaterial as ge, MeshLambertMaterial as _e, MeshStandardMaterial as ve, PCFSoftShadowMap as ye, PerspectiveCamera as be, Plane as xe, PlaneGeometry as Se, Raycaster as Ce, Scene as we, Vector2 as Te, Vector3 as g, WebGLRenderer as Ee, sRGBEncoding as De } from "three";
4
4
  // src/games/tanks-live/scene/createLiveScene.js
@@ -361,4 +361,4 @@ function y(y, { arena: Fe, lowPower: b = !1, reducedMotion: x = !1, onEvent: Ie
361
361
  }
362
362
  export { y as createLiveScene, y as default };
363
363
 
364
- //# sourceMappingURL=createLiveScene-CJQtq54t.js.map
364
+ //# sourceMappingURL=createLiveScene-BqI7qV4n.js.map