| --- |
| // TrackioWrapper.astro |
| import Trackio from './trackio/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('./trackio/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); |
| } |
| |
| .theme-select { |
| padding: 6px 12px; |
| border: 1px solid var(--border-color); |
| border-radius: 4px; |
| background: var(--input-bg, var(--surface-bg)); |
| color: var(--text-color); |
| font-size: 14px; |
| cursor: pointer; |
| transition: border-color 0.15s ease; |
| } |
| |
| .theme-select:focus { |
| outline: none; |
| border-color: var(--accent-color, #007acc); |
| } |
| |
| .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); |
| 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> |