lerobot/robot-learning-tutorial
508
1---2// TrackioWrapper.astro3import Trackio from './trackio/Trackio.svelte';4---5 6<!-- Ensure Roboto Mono is loaded for Oblivion theme -->7<link rel="preconnect" href="https://fonts.googleapis.com">8<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>9<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono:wght@400;600;700&display=swap" rel="stylesheet">10 11<div class="trackio-wrapper">12 <div class="trackio-controls">13 <div class="controls-left">14 <div class="theme-selector">15 <label for="theme-select">Theme</label>16 <select id="theme-select" class="theme-select">17 <option value="classic">Classic</option>18 <option value="oblivion">Oblivion</option>19 </select>20 </div>21 <div class="scale-controls">22 <label>23 <input type="checkbox" id="log-scale-x" checked>24 Log Scale X25 </label>26 <label>27 <input type="checkbox" id="smooth-data" checked>28 Smooth29 </label>30 </div>31 </div>32 <div class="controls-right">33 <button class="button button--ghost" type="button" id="randomize-btn">34 Randomize Data35 </button>36 <button class="button button--primary" type="button" id="start-simulation-btn">37 Live Run38 </button>39 <button class="button button--danger" type="button" id="stop-simulation-btn" style="display: none;">40 Stop41 </button>42 </div>43 </div>44 45 <div class="trackio-container">46 <Trackio client:load variant="classic" logScaleX={true} smoothing={true} />47 </div>48</div>49 50<script>51 // @ts-nocheck52 document.addEventListener('DOMContentLoaded', async () => {53 const themeSelect = document.getElementById('theme-select');54 const randomizeBtn = document.getElementById('randomize-btn');55 const startSimulationBtn = document.getElementById('start-simulation-btn');56 const stopSimulationBtn = document.getElementById('stop-simulation-btn');57 const logScaleXCheckbox = document.getElementById('log-scale-x');58 const smoothDataCheckbox = document.getElementById('smooth-data');59 const trackioContainer = document.querySelector('.trackio-container');60 61 if (!themeSelect || !randomizeBtn || !startSimulationBtn || !stopSimulationBtn || 62 !logScaleXCheckbox || !smoothDataCheckbox || !trackioContainer) return;63 64 // Variables pour la simulation65 let simulationInterval = null;66 let currentSimulationRun = null;67 let currentStep = 0;68 69 // Import the store function70 const { triggerJitter } = await import('./trackio/core/store.js');71 72 // Theme change handler73 themeSelect.addEventListener('change', (e) => {74 const target = e.target;75 if (!target || !('value' in target)) return;76 77 const newVariant = target.value;78 console.log(`Theme changed to: ${newVariant}`); // Debug log79 80 // Find the trackio element and call setTheme on the Svelte instance81 const trackioEl = debugTrackioState();82 if (trackioEl && trackioEl.__trackioInstance) {83 console.log('✅ Calling setTheme on Trackio instance');84 trackioEl.__trackioInstance.setTheme(newVariant);85 } else {86 console.warn('❌ No Trackio instance found for theme change');87 }88 });89 90 // Log scale X change handler91 logScaleXCheckbox.addEventListener('change', (e) => {92 const target = e.target;93 if (!target || !('checked' in target)) return;94 95 const isLogScale = target.checked;96 console.log(`Log scale X changed to: ${isLogScale}`); // Debug log97 98 // Find the trackio element and call setLogScaleX on the Svelte instance99 const trackioEl = debugTrackioState();100 if (trackioEl && trackioEl.__trackioInstance) {101 console.log('✅ Calling setLogScaleX on Trackio instance');102 trackioEl.__trackioInstance.setLogScaleX(isLogScale);103 } else {104 console.warn('❌ Trackio instance not found for log scale change');105 }106 });107 108 // Smooth data change handler109 smoothDataCheckbox.addEventListener('change', (e) => {110 const target = e.target;111 if (!target || !('checked' in target)) return;112 113 const isSmooth = target.checked;114 console.log(`Smooth data changed to: ${isSmooth}`); // Debug log115 116 // Find the trackio element and call setSmoothing on the Svelte instance117 const trackioEl = debugTrackioState();118 if (trackioEl && trackioEl.__trackioInstance) {119 console.log('✅ Calling setSmoothing on Trackio instance');120 trackioEl.__trackioInstance.setSmoothing(isSmooth);121 } else {122 console.warn('❌ Trackio instance not found for smooth change');123 }124 });125 126 // Debug function to check trackio state127 function debugTrackioState() {128 const trackioEl = trackioContainer.querySelector('.trackio');129 console.log('🔍 Debug Trackio state:', {130 container: !!trackioContainer,131 trackioEl: !!trackioEl,132 hasInstance: !!(trackioEl && trackioEl.__trackioInstance),133 availableMethods: trackioEl && trackioEl.__trackioInstance ? Object.keys(trackioEl.__trackioInstance) : 'none',134 windowInstance: !!window.trackioInstance135 });136 return trackioEl;137 }138 139 // Initialize with default checked states - increased delay and retry logic140 function initializeTrackio(attempt = 1) {141 console.log(`🚀 Initializing Trackio (attempt ${attempt})`);142 143 const trackioEl = debugTrackioState();144 145 if (trackioEl && trackioEl.__trackioInstance) {146 console.log('✅ Trackio instance found, applying initial settings');147 148 if (logScaleXCheckbox.checked) {149 console.log('Initializing with log scale X enabled');150 trackioEl.__trackioInstance.setLogScaleX(true);151 }152 153 if (smoothDataCheckbox.checked) {154 console.log('Initializing with smoothing enabled');155 trackioEl.__trackioInstance.setSmoothing(true);156 }157 } else {158 console.log('❌ Trackio instance not ready yet');159 if (attempt < 10) {160 setTimeout(() => initializeTrackio(attempt + 1), 200 * attempt);161 } else {162 console.error('Failed to initialize Trackio after 10 attempts');163 }164 }165 }166 167 // Start initialization168 setTimeout(() => initializeTrackio(), 100);169 170 // Fonction pour générer une nouvelle valeur de métrique simulée171 function generateSimulatedValue(step, metric) {172 const baseProgress = Math.min(1, step / 100); // Normalise sur 100 steps173 174 if (metric === 'loss') {175 // Loss qui décroit avec du bruit176 const baseLoss = 2.0 * Math.exp(-0.05 * step);177 const noise = (Math.random() - 0.5) * 0.2;178 return Math.max(0.01, baseLoss + noise);179 } else if (metric === 'accuracy') {180 // Accuracy qui augmente avec du bruit181 const baseAcc = 0.1 + 0.8 * (1 - Math.exp(-0.04 * step));182 const noise = (Math.random() - 0.5) * 0.05;183 return Math.max(0, Math.min(1, baseAcc + noise));184 }185 return Math.random();186 }187 188 // Gestionnaire pour démarrer la simulation189 function startSimulation() {190 if (simulationInterval) {191 clearInterval(simulationInterval);192 }193 194 // Générer un nouveau nom de run195 const adjectives = ['live', 'real-time', 'streaming', 'dynamic', 'active', 'running'];196 const nouns = ['experiment', 'trial', 'session', 'training', 'run', 'test'];197 const randomAdj = adjectives[Math.floor(Math.random() * adjectives.length)];198 const randomNoun = nouns[Math.floor(Math.random() * nouns.length)];199 currentSimulationRun = `${randomAdj}-${randomNoun}-${Date.now().toString().slice(-4)}`;200 currentStep = 1; // Commencer à step 1201 202 console.log(`Starting simulation for run: ${currentSimulationRun}`);203 204 // Interface UI205 startSimulationBtn.style.display = 'none';206 stopSimulationBtn.style.display = 'inline-flex';207 startSimulationBtn.disabled = true;208 209 // Ajouter le premier point210 addSimulationStep();211 212 // Continuer chaque seconde213 simulationInterval = setInterval(() => {214 currentStep++;215 addSimulationStep();216 217 // Arrêter après 200 steps pour éviter l'infini218 if (currentStep > 200) {219 stopSimulation();220 }221 }, 1000); // Chaque seconde222 }223 224 // Fonction pour ajouter un nouveau point de données225 function addSimulationStep() {226 const trackioEl = trackioContainer.querySelector('.trackio');227 if (trackioEl && trackioEl.__trackioInstance) {228 const newDataPoint = {229 step: currentStep,230 loss: generateSimulatedValue(currentStep, 'loss'),231 accuracy: generateSimulatedValue(currentStep, 'accuracy')232 };233 234 console.log(`Adding simulation step ${currentStep} for run ${currentSimulationRun}:`, newDataPoint);235 236 // Ajouter le point via l'instance Trackio237 if (typeof trackioEl.__trackioInstance.addLiveDataPoint === 'function') {238 trackioEl.__trackioInstance.addLiveDataPoint(currentSimulationRun, newDataPoint);239 } else {240 console.warn('addLiveDataPoint method not found on Trackio instance');241 }242 }243 }244 245 // Gestionnaire pour arrêter la simulation 246 function stopSimulation() {247 if (simulationInterval) {248 clearInterval(simulationInterval);249 simulationInterval = null;250 }251 252 console.log(`Stopping simulation for run: ${currentSimulationRun}`);253 254 // Interface UI255 startSimulationBtn.style.display = 'inline-flex';256 stopSimulationBtn.style.display = 'none';257 startSimulationBtn.disabled = false;258 259 currentSimulationRun = null;260 currentStep = 0;261 }262 263 // Event listeners pour les boutons de simulation264 startSimulationBtn.addEventListener('click', startSimulation);265 stopSimulationBtn.addEventListener('click', stopSimulation);266 267 // Arrêter la simulation si l'utilisateur quitte la page268 window.addEventListener('beforeunload', stopSimulation);269 270 // Randomize data handler - now uses the store271 randomizeBtn.addEventListener('click', () => {272 console.log('Randomize button clicked - triggering jitter via store'); // Debug log273 274 // Arrêter la simulation en cours si elle tourne275 if (simulationInterval) {276 stopSimulation();277 }278 279 // Add vibration animation280 randomizeBtn.classList.add('vibrating');281 setTimeout(() => {282 randomizeBtn.classList.remove('vibrating');283 }, 600);284 285 // Test direct window approach as well286 if (window.trackioInstance && typeof window.trackioInstance.jitterData === 'function') {287 console.log('Found window.trackioInstance, calling jitterData directly'); // Debug log288 window.trackioInstance.jitterData();289 } else {290 console.log('No window.trackioInstance found, using store trigger'); // Debug log291 triggerJitter();292 }293 });294 });295</script>296 297<style>298 .trackio-wrapper {299 width: 100%;300 margin: 0px 0 20px 0;301 }302 303 .trackio-controls {304 display: flex;305 justify-content: space-between;306 align-items: center;307 margin-bottom: 16px;308 padding: 12px 0px;309 /* border-bottom: 1px solid var(--border-color); */310 gap: 16px;311 flex-wrap: nowrap;312 }313 314 .controls-left {315 display: flex;316 align-items: center;317 gap: 24px;318 flex-wrap: wrap;319 }320 321 .controls-right {322 display: flex;323 align-items: center;324 gap: 12px;325 flex-wrap: wrap;326 }327 328 .btn-randomize {329 display: inline-flex;330 align-items: center;331 gap: 6px;332 padding: 8px 16px;333 background: var(--accent-color, #007acc);334 color: white;335 border: none;336 border-radius: 6px;337 font-size: 14px;338 font-weight: 500;339 cursor: pointer;340 transition: all 0.15s ease;341 }342 343 .btn-randomize:hover {344 background: var(--accent-hover, #005a9e);345 transform: translateY(-1px);346 }347 348 .btn-randomize:active {349 transform: translateY(0);350 }351 352 .theme-selector {353 display: flex;354 align-items: center;355 gap: 8px;356 font-size: 14px;357 flex-shrink: 0;358 white-space: nowrap;359 }360 361 .theme-selector label {362 font-weight: 500;363 color: var(--text-color);364 }365 366 .theme-select {367 padding: 6px 12px;368 border: 1px solid var(--border-color);369 border-radius: 4px;370 background: var(--input-bg, var(--surface-bg));371 color: var(--text-color);372 font-size: 14px;373 cursor: pointer;374 transition: border-color 0.15s ease;375 }376 377 .theme-select:focus {378 outline: none;379 border-color: var(--accent-color, #007acc);380 }381 382 .scale-controls {383 display: flex;384 align-items: center;385 gap: 16px;386 flex-shrink: 0;387 white-space: nowrap;388 }389 390 /* Animation de vibration pour le bouton */391 @keyframes vibrate {392 0% { transform: translateX(0); }393 10% { transform: translateX(-2px) rotate(-1deg); }394 20% { transform: translateX(2px) rotate(1deg); }395 30% { transform: translateX(-2px) rotate(-1deg); }396 40% { transform: translateX(2px) rotate(1deg); }397 50% { transform: translateX(-1px) rotate(-0.5deg); }398 60% { transform: translateX(1px) rotate(0.5deg); }399 70% { transform: translateX(-1px) rotate(-0.5deg); }400 80% { transform: translateX(1px) rotate(0.5deg); }401 90% { transform: translateX(-0.5px) rotate(-0.25deg); }402 100% { transform: translateX(0) rotate(0); }403 }404 405 .button.vibrating {406 animation: vibrate 0.6s ease-in-out;407 }408 409 .trackio-container {410 width: 100%;411 margin-top: 10px;412 border: 1px solid var(--border-color);413 padding: 24px 12px;414 415 }416 417 @media (max-width: 768px) {418 .trackio-controls {419 flex-direction: column;420 align-items: stretch;421 gap: 12px;422 }423 424 .controls-left {425 flex-direction: column;426 align-items: stretch;427 gap: 12px;428 }429 430 .theme-selector {431 justify-content: space-between;432 }433 434 .scale-controls {435 justify-content: space-between;436 }437 }438</style>