| | --- |
| | // TrackioWrapper.astro |
| | import Trackio from "./Trackio.svelte"; |
| | --- |
| |
|
| | |
| | <link rel="preconnect" href="https://fonts.googleapis.com" /> |
| | <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> |
| | <link |
| | href="https://fonts.googleapis.com/css2?family=Roboto+Mono:wght@400;600;700&display=swap" |
| | rel="stylesheet" |
| | /> |
| |
|
| | <div class="trackio-wrapper"> |
| | <div class="trackio-controls"> |
| | <div class="controls-left"> |
| | <div class="theme-selector"> |
| | <label for="theme-select">Theme</label> |
| | <select id="theme-select" class="theme-select"> |
| | <option value="classic">Classic</option> |
| | <option value="oblivion">Oblivion</option> |
| | </select> |
| | </div> |
| | <div class="scale-controls"> |
| | <label> |
| | <input type="checkbox" id="log-scale-x" checked /> |
| | Log Scale X |
| | </label> |
| | <label> |
| | <input type="checkbox" id="smooth-data" checked /> |
| | Smooth |
| | </label> |
| | </div> |
| | </div> |
| | <div class="controls-right"> |
| | <button class="button button--ghost" type="button" id="randomize-btn"> |
| | Randomize Data |
| | </button> |
| | <button |
| | class="button button--primary" |
| | type="button" |
| | id="start-simulation-btn" |
| | > |
| | Live Run |
| | </button> |
| | <button |
| | class="button button--danger" |
| | type="button" |
| | id="stop-simulation-btn" |
| | style="display: none;" |
| | > |
| | Stop |
| | </button> |
| | </div> |
| | </div> |
| |
|
| | <div class="trackio-container"> |
| | <Trackio client:load variant="classic" logScaleX={true} smoothing={true} /> |
| | </div> |
| | </div> |
| |
|
| | <script> |
| | |
| | document.addEventListener("DOMContentLoaded", async () => { |
| | const themeSelect = document.getElementById("theme-select"); |
| | const randomizeBtn = document.getElementById("randomize-btn"); |
| | const startSimulationBtn = document.getElementById("start-simulation-btn"); |
| | const stopSimulationBtn = document.getElementById("stop-simulation-btn"); |
| | const logScaleXCheckbox = document.getElementById("log-scale-x"); |
| | const smoothDataCheckbox = document.getElementById("smooth-data"); |
| | const trackioContainer = document.querySelector(".trackio-container"); |
| | |
| | if ( |
| | !themeSelect || |
| | !randomizeBtn || |
| | !startSimulationBtn || |
| | !stopSimulationBtn || |
| | !logScaleXCheckbox || |
| | !smoothDataCheckbox || |
| | !trackioContainer |
| | ) |
| | return; |
| | |
| | |
| | let simulationInterval = null; |
| | let currentSimulationRun = null; |
| | let currentStep = 0; |
| | |
| | |
| | const { triggerJitter } = await import("./core/store.js"); |
| | |
| | |
| | themeSelect.addEventListener("change", (e) => { |
| | const target = e.target; |
| | if (!target || !("value" in target)) return; |
| | |
| | const newVariant = target.value; |
| | console.log(`Theme changed to: ${newVariant}`); |
| | |
| | |
| | const trackioEl = debugTrackioState(); |
| | if (trackioEl && trackioEl.__trackioInstance) { |
| | console.log("✅ Calling setTheme on Trackio instance"); |
| | trackioEl.__trackioInstance.setTheme(newVariant); |
| | } else { |
| | console.warn("❌ No Trackio instance found for theme change"); |
| | } |
| | }); |
| | |
| | |
| | logScaleXCheckbox.addEventListener("change", (e) => { |
| | const target = e.target; |
| | if (!target || !("checked" in target)) return; |
| | |
| | const isLogScale = target.checked; |
| | console.log(`Log scale X changed to: ${isLogScale}`); |
| | |
| | |
| | const trackioEl = debugTrackioState(); |
| | if (trackioEl && trackioEl.__trackioInstance) { |
| | console.log("✅ Calling setLogScaleX on Trackio instance"); |
| | trackioEl.__trackioInstance.setLogScaleX(isLogScale); |
| | } else { |
| | console.warn("❌ Trackio instance not found for log scale change"); |
| | } |
| | }); |
| | |
| | |
| | smoothDataCheckbox.addEventListener("change", (e) => { |
| | const target = e.target; |
| | if (!target || !("checked" in target)) return; |
| | |
| | const isSmooth = target.checked; |
| | console.log(`Smooth data changed to: ${isSmooth}`); |
| | |
| | |
| | const trackioEl = debugTrackioState(); |
| | if (trackioEl && trackioEl.__trackioInstance) { |
| | console.log("✅ Calling setSmoothing on Trackio instance"); |
| | trackioEl.__trackioInstance.setSmoothing(isSmooth); |
| | } else { |
| | console.warn("❌ Trackio instance not found for smooth change"); |
| | } |
| | }); |
| | |
| | |
| | function debugTrackioState() { |
| | const trackioEl = trackioContainer.querySelector(".trackio"); |
| | console.log("🔍 Debug Trackio state:", { |
| | container: !!trackioContainer, |
| | trackioEl: !!trackioEl, |
| | hasInstance: !!(trackioEl && trackioEl.__trackioInstance), |
| | availableMethods: |
| | trackioEl && trackioEl.__trackioInstance |
| | ? Object.keys(trackioEl.__trackioInstance) |
| | : "none", |
| | windowInstance: !!window.trackioInstance, |
| | }); |
| | return trackioEl; |
| | } |
| | |
| | |
| | function initializeTrackio(attempt = 1) { |
| | console.log(`🚀 Initializing Trackio (attempt ${attempt})`); |
| | |
| | const trackioEl = debugTrackioState(); |
| | |
| | if (trackioEl && trackioEl.__trackioInstance) { |
| | console.log("✅ Trackio instance found, applying initial settings"); |
| | |
| | if (logScaleXCheckbox.checked) { |
| | console.log("Initializing with log scale X enabled"); |
| | trackioEl.__trackioInstance.setLogScaleX(true); |
| | } |
| | |
| | if (smoothDataCheckbox.checked) { |
| | console.log("Initializing with smoothing enabled"); |
| | trackioEl.__trackioInstance.setSmoothing(true); |
| | } |
| | } else { |
| | console.log("❌ Trackio instance not ready yet"); |
| | if (attempt < 10) { |
| | setTimeout(() => initializeTrackio(attempt + 1), 200 * attempt); |
| | } else { |
| | console.error("Failed to initialize Trackio after 10 attempts"); |
| | } |
| | } |
| | } |
| | |
| | |
| | setTimeout(() => initializeTrackio(), 100); |
| | |
| | |
| | function generateSimulatedValue(step, metric) { |
| | const baseProgress = Math.min(1, step / 100); |
| | |
| | if (metric === "loss") { |
| | |
| | const baseLoss = 2.0 * Math.exp(-0.05 * step); |
| | const noise = (Math.random() - 0.5) * 0.2; |
| | return Math.max(0.01, baseLoss + noise); |
| | } else if (metric === "accuracy") { |
| | |
| | const baseAcc = 0.1 + 0.8 * (1 - Math.exp(-0.04 * step)); |
| | const noise = (Math.random() - 0.5) * 0.05; |
| | return Math.max(0, Math.min(1, baseAcc + noise)); |
| | } |
| | return Math.random(); |
| | } |
| | |
| | |
| | function startSimulation() { |
| | if (simulationInterval) { |
| | clearInterval(simulationInterval); |
| | } |
| | |
| | |
| | const adjectives = [ |
| | "live", |
| | "real-time", |
| | "streaming", |
| | "dynamic", |
| | "active", |
| | "running", |
| | ]; |
| | const nouns = [ |
| | "experiment", |
| | "trial", |
| | "session", |
| | "training", |
| | "run", |
| | "test", |
| | ]; |
| | const randomAdj = |
| | adjectives[Math.floor(Math.random() * adjectives.length)]; |
| | const randomNoun = nouns[Math.floor(Math.random() * nouns.length)]; |
| | currentSimulationRun = `${randomAdj}-${randomNoun}-${Date.now().toString().slice(-4)}`; |
| | currentStep = 1; |
| | |
| | console.log(`Starting simulation for run: ${currentSimulationRun}`); |
| | |
| | |
| | startSimulationBtn.style.display = "none"; |
| | stopSimulationBtn.style.display = "inline-flex"; |
| | startSimulationBtn.disabled = true; |
| | |
| | |
| | addSimulationStep(); |
| | |
| | |
| | simulationInterval = setInterval(() => { |
| | currentStep++; |
| | addSimulationStep(); |
| | |
| | |
| | if (currentStep > 200) { |
| | stopSimulation(); |
| | } |
| | }, 1000); |
| | } |
| | |
| | |
| | function addSimulationStep() { |
| | const trackioEl = trackioContainer.querySelector(".trackio"); |
| | if (trackioEl && trackioEl.__trackioInstance) { |
| | const newDataPoint = { |
| | step: currentStep, |
| | loss: generateSimulatedValue(currentStep, "loss"), |
| | accuracy: generateSimulatedValue(currentStep, "accuracy"), |
| | }; |
| | |
| | console.log( |
| | `Adding simulation step ${currentStep} for run ${currentSimulationRun}:`, |
| | newDataPoint, |
| | ); |
| | |
| | |
| | if ( |
| | typeof trackioEl.__trackioInstance.addLiveDataPoint === "function" |
| | ) { |
| | trackioEl.__trackioInstance.addLiveDataPoint( |
| | currentSimulationRun, |
| | newDataPoint, |
| | ); |
| | } else { |
| | console.warn("addLiveDataPoint method not found on Trackio instance"); |
| | } |
| | } |
| | } |
| | |
| | |
| | function stopSimulation() { |
| | if (simulationInterval) { |
| | clearInterval(simulationInterval); |
| | simulationInterval = null; |
| | } |
| | |
| | console.log(`Stopping simulation for run: ${currentSimulationRun}`); |
| | |
| | |
| | startSimulationBtn.style.display = "inline-flex"; |
| | stopSimulationBtn.style.display = "none"; |
| | startSimulationBtn.disabled = false; |
| | |
| | currentSimulationRun = null; |
| | currentStep = 0; |
| | } |
| | |
| | |
| | startSimulationBtn.addEventListener("click", startSimulation); |
| | stopSimulationBtn.addEventListener("click", stopSimulation); |
| | |
| | |
| | window.addEventListener("beforeunload", stopSimulation); |
| | |
| | |
| | randomizeBtn.addEventListener("click", () => { |
| | console.log("Randomize button clicked - triggering jitter via store"); |
| | |
| | |
| | if (simulationInterval) { |
| | stopSimulation(); |
| | } |
| | |
| | |
| | randomizeBtn.classList.add("vibrating"); |
| | setTimeout(() => { |
| | randomizeBtn.classList.remove("vibrating"); |
| | }, 600); |
| | |
| | |
| | if ( |
| | window.trackioInstance && |
| | typeof window.trackioInstance.jitterData === "function" |
| | ) { |
| | console.log( |
| | "Found window.trackioInstance, calling jitterData directly", |
| | ); |
| | window.trackioInstance.jitterData(); |
| | } else { |
| | console.log("No window.trackioInstance found, using store trigger"); |
| | triggerJitter(); |
| | } |
| | }); |
| | }); |
| | </script> |
| |
|
| | <style> |
| | .trackio-wrapper { |
| | width: 100%; |
| | margin: 0px 0 20px 0; |
| | } |
| | |
| | .trackio-controls { |
| | display: flex; |
| | justify-content: space-between; |
| | align-items: center; |
| | margin-bottom: 16px; |
| | padding: 12px 0px; |
| | |
| | gap: 16px; |
| | flex-wrap: nowrap; |
| | } |
| | |
| | .controls-left { |
| | display: flex; |
| | align-items: center; |
| | gap: 24px; |
| | flex-wrap: wrap; |
| | } |
| | |
| | .controls-right { |
| | display: flex; |
| | align-items: center; |
| | gap: 12px; |
| | flex-wrap: wrap; |
| | } |
| | |
| | .btn-randomize { |
| | display: inline-flex; |
| | align-items: center; |
| | gap: 6px; |
| | padding: 8px 16px; |
| | background: var(--accent-color, #007acc); |
| | color: white; |
| | border: none; |
| | border-radius: 6px; |
| | font-size: 14px; |
| | font-weight: 500; |
| | cursor: pointer; |
| | transition: all 0.15s ease; |
| | } |
| | |
| | .btn-randomize:hover { |
| | background: var(--accent-hover, #005a9e); |
| | transform: translateY(-1px); |
| | } |
| | |
| | .btn-randomize:active { |
| | transform: translateY(0); |
| | } |
| | |
| | .theme-selector { |
| | display: flex; |
| | align-items: center; |
| | gap: 8px; |
| | font-size: 14px; |
| | flex-shrink: 0; |
| | white-space: nowrap; |
| | } |
| | |
| | .theme-selector label { |
| | font-weight: 500; |
| | color: var(--text-color); |
| | } |
| | |
| | .scale-controls { |
| | display: flex; |
| | align-items: center; |
| | gap: 16px; |
| | flex-shrink: 0; |
| | white-space: nowrap; |
| | } |
| | |
| | |
| | @keyframes vibrate { |
| | 0% { |
| | transform: translateX(0); |
| | } |
| | 10% { |
| | transform: translateX(-2px) rotate(-1deg); |
| | } |
| | 20% { |
| | transform: translateX(2px) rotate(1deg); |
| | } |
| | 30% { |
| | transform: translateX(-2px) rotate(-1deg); |
| | } |
| | 40% { |
| | transform: translateX(2px) rotate(1deg); |
| | } |
| | 50% { |
| | transform: translateX(-1px) rotate(-0.5deg); |
| | } |
| | 60% { |
| | transform: translateX(1px) rotate(0.5deg); |
| | } |
| | 70% { |
| | transform: translateX(-1px) rotate(-0.5deg); |
| | } |
| | 80% { |
| | transform: translateX(1px) rotate(0.5deg); |
| | } |
| | 90% { |
| | transform: translateX(-0.5px) rotate(-0.25deg); |
| | } |
| | 100% { |
| | transform: translateX(0) rotate(0); |
| | } |
| | } |
| | |
| | .button.vibrating { |
| | animation: vibrate 0.6s ease-in-out; |
| | } |
| | |
| | .trackio-container { |
| | width: 100%; |
| | margin-top: 10px; |
| | border: 1px solid var(--border-color); |
| | border-radius: 8px; |
| | padding: 24px 12px; |
| | } |
| | |
| | @media (max-width: 768px) { |
| | .trackio-controls { |
| | flex-direction: column; |
| | align-items: stretch; |
| | gap: 12px; |
| | } |
| | |
| | .controls-left { |
| | flex-direction: column; |
| | align-items: stretch; |
| | gap: 12px; |
| | } |
| | |
| | .theme-selector { |
| | justify-content: space-between; |
| | } |
| | |
| | .scale-controls { |
| | justify-content: space-between; |
| | } |
| | } |
| | </style> |
| |
|