lerobot/robot-learning-tutorial
508
1---2// TrackioWrapper.astro3import Trackio from "./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<link10 href="https://fonts.googleapis.com/css2?family=Roboto+Mono:wght@400;600;700&display=swap"11 rel="stylesheet"12/>13 14<div class="trackio-wrapper">15 <div class="trackio-controls">16 <div class="controls-left">17 <div class="theme-selector">18 <label for="theme-select">Theme</label>19 <select id="theme-select" class="theme-select">20 <option value="classic">Classic</option>21 <option value="oblivion">Oblivion</option>22 </select>23 </div>24 <div class="scale-controls">25 <label>26 <input type="checkbox" id="log-scale-x" checked />27 Log Scale X28 </label>29 <label>30 <input type="checkbox" id="smooth-data" checked />31 Smooth32 </label>33 </div>34 </div>35 <div class="controls-right">36 <button class="button button--ghost" type="button" id="randomize-btn">37 Randomize Data38 </button>39 <button40 class="button button--primary"41 type="button"42 id="start-simulation-btn"43 >44 Live Run45 </button>46 <button47 class="button button--danger"48 type="button"49 id="stop-simulation-btn"50 style="display: none;"51 >52 Stop53 </button>54 </div>55 </div>56 57 <div class="trackio-container">58 <Trackio client:load variant="classic" logScaleX={true} smoothing={true} />59 </div>60</div>61 62<script>63 // @ts-nocheck64 document.addEventListener("DOMContentLoaded", async () => {65 const themeSelect = document.getElementById("theme-select");66 const randomizeBtn = document.getElementById("randomize-btn");67 const startSimulationBtn = document.getElementById("start-simulation-btn");68 const stopSimulationBtn = document.getElementById("stop-simulation-btn");69 const logScaleXCheckbox = document.getElementById("log-scale-x");70 const smoothDataCheckbox = document.getElementById("smooth-data");71 const trackioContainer = document.querySelector(".trackio-container");72 73 if (74 !themeSelect ||75 !randomizeBtn ||76 !startSimulationBtn ||77 !stopSimulationBtn ||78 !logScaleXCheckbox ||79 !smoothDataCheckbox ||80 !trackioContainer81 )82 return;83 84 // Variables for simulation85 let simulationInterval = null;86 let currentSimulationRun = null;87 let currentStep = 0;88 89 // Import the store function90 const { triggerJitter } = await import("./core/store.js");91 92 // Theme change handler93 themeSelect.addEventListener("change", (e) => {94 const target = e.target;95 if (!target || !("value" in target)) return;96 97 const newVariant = target.value;98 console.log(`Theme changed to: ${newVariant}`); // Debug log99 100 // Find the trackio element and call setTheme on the Svelte instance101 const trackioEl = debugTrackioState();102 if (trackioEl && trackioEl.__trackioInstance) {103 console.log("✅ Calling setTheme on Trackio instance");104 trackioEl.__trackioInstance.setTheme(newVariant);105 } else {106 console.warn("❌ No Trackio instance found for theme change");107 }108 });109 110 // Log scale X change handler111 logScaleXCheckbox.addEventListener("change", (e) => {112 const target = e.target;113 if (!target || !("checked" in target)) return;114 115 const isLogScale = target.checked;116 console.log(`Log scale X changed to: ${isLogScale}`); // Debug log117 118 // Find the trackio element and call setLogScaleX on the Svelte instance119 const trackioEl = debugTrackioState();120 if (trackioEl && trackioEl.__trackioInstance) {121 console.log("✅ Calling setLogScaleX on Trackio instance");122 trackioEl.__trackioInstance.setLogScaleX(isLogScale);123 } else {124 console.warn("❌ Trackio instance not found for log scale change");125 }126 });127 128 // Smooth data change handler129 smoothDataCheckbox.addEventListener("change", (e) => {130 const target = e.target;131 if (!target || !("checked" in target)) return;132 133 const isSmooth = target.checked;134 console.log(`Smooth data changed to: ${isSmooth}`); // Debug log135 136 // Find the trackio element and call setSmoothing on the Svelte instance137 const trackioEl = debugTrackioState();138 if (trackioEl && trackioEl.__trackioInstance) {139 console.log("✅ Calling setSmoothing on Trackio instance");140 trackioEl.__trackioInstance.setSmoothing(isSmooth);141 } else {142 console.warn("❌ Trackio instance not found for smooth change");143 }144 });145 146 // Debug function to check trackio state147 function debugTrackioState() {148 const trackioEl = trackioContainer.querySelector(".trackio");149 console.log("🔍 Debug Trackio state:", {150 container: !!trackioContainer,151 trackioEl: !!trackioEl,152 hasInstance: !!(trackioEl && trackioEl.__trackioInstance),153 availableMethods:154 trackioEl && trackioEl.__trackioInstance155 ? Object.keys(trackioEl.__trackioInstance)156 : "none",157 windowInstance: !!window.trackioInstance,158 });159 return trackioEl;160 }161 162 // Initialize with default checked states - increased delay and retry logic163 function initializeTrackio(attempt = 1) {164 console.log(`🚀 Initializing Trackio (attempt ${attempt})`);165 166 const trackioEl = debugTrackioState();167 168 if (trackioEl && trackioEl.__trackioInstance) {169 console.log("✅ Trackio instance found, applying initial settings");170 171 if (logScaleXCheckbox.checked) {172 console.log("Initializing with log scale X enabled");173 trackioEl.__trackioInstance.setLogScaleX(true);174 }175 176 if (smoothDataCheckbox.checked) {177 console.log("Initializing with smoothing enabled");178 trackioEl.__trackioInstance.setSmoothing(true);179 }180 } else {181 console.log("❌ Trackio instance not ready yet");182 if (attempt < 10) {183 setTimeout(() => initializeTrackio(attempt + 1), 200 * attempt);184 } else {185 console.error("Failed to initialize Trackio after 10 attempts");186 }187 }188 }189 190 // Start initialization191 setTimeout(() => initializeTrackio(), 100);192 193 // Function to generate a new simulated metric value194 function generateSimulatedValue(step, metric) {195 const baseProgress = Math.min(1, step / 100); // Normalise sur 100 steps196 197 if (metric === "loss") {198 // Loss that decreases with noise199 const baseLoss = 2.0 * Math.exp(-0.05 * step);200 const noise = (Math.random() - 0.5) * 0.2;201 return Math.max(0.01, baseLoss + noise);202 } else if (metric === "accuracy") {203 // Accuracy that increases with noise204 const baseAcc = 0.1 + 0.8 * (1 - Math.exp(-0.04 * step));205 const noise = (Math.random() - 0.5) * 0.05;206 return Math.max(0, Math.min(1, baseAcc + noise));207 }208 return Math.random();209 }210 211 // Handler to start simulation212 function startSimulation() {213 if (simulationInterval) {214 clearInterval(simulationInterval);215 }216 217 // Générer un nouveau nom de run218 const adjectives = [219 "live",220 "real-time",221 "streaming",222 "dynamic",223 "active",224 "running",225 ];226 const nouns = [227 "experiment",228 "trial",229 "session",230 "training",231 "run",232 "test",233 ];234 const randomAdj =235 adjectives[Math.floor(Math.random() * adjectives.length)];236 const randomNoun = nouns[Math.floor(Math.random() * nouns.length)];237 currentSimulationRun = `${randomAdj}-${randomNoun}-${Date.now().toString().slice(-4)}`;238 currentStep = 1; // Commencer à step 1239 240 console.log(`Starting simulation for run: ${currentSimulationRun}`);241 242 // Interface UI243 startSimulationBtn.style.display = "none";244 stopSimulationBtn.style.display = "inline-flex";245 startSimulationBtn.disabled = true;246 247 // Ajouter le premier point248 addSimulationStep();249 250 // Continuer chaque seconde251 simulationInterval = setInterval(() => {252 currentStep++;253 addSimulationStep();254 255 // Stop after 200 steps to avoid infinity256 if (currentStep > 200) {257 stopSimulation();258 }259 }, 1000); // Chaque seconde260 }261 262 // Function to add a new data point263 function addSimulationStep() {264 const trackioEl = trackioContainer.querySelector(".trackio");265 if (trackioEl && trackioEl.__trackioInstance) {266 const newDataPoint = {267 step: currentStep,268 loss: generateSimulatedValue(currentStep, "loss"),269 accuracy: generateSimulatedValue(currentStep, "accuracy"),270 };271 272 console.log(273 `Adding simulation step ${currentStep} for run ${currentSimulationRun}:`,274 newDataPoint,275 );276 277 // Ajouter le point via l'instance Trackio278 if (279 typeof trackioEl.__trackioInstance.addLiveDataPoint === "function"280 ) {281 trackioEl.__trackioInstance.addLiveDataPoint(282 currentSimulationRun,283 newDataPoint,284 );285 } else {286 console.warn("addLiveDataPoint method not found on Trackio instance");287 }288 }289 }290 291 // Handler to stop simulation292 function stopSimulation() {293 if (simulationInterval) {294 clearInterval(simulationInterval);295 simulationInterval = null;296 }297 298 console.log(`Stopping simulation for run: ${currentSimulationRun}`);299 300 // Interface UI301 startSimulationBtn.style.display = "inline-flex";302 stopSimulationBtn.style.display = "none";303 startSimulationBtn.disabled = false;304 305 currentSimulationRun = null;306 currentStep = 0;307 }308 309 // Event listeners for simulation buttons310 startSimulationBtn.addEventListener("click", startSimulation);311 stopSimulationBtn.addEventListener("click", stopSimulation);312 313 // Arrêter la simulation si l'utilisateur quitte la page314 window.addEventListener("beforeunload", stopSimulation);315 316 // Randomize data handler - now uses the store317 randomizeBtn.addEventListener("click", () => {318 console.log("Randomize button clicked - triggering jitter via store"); // Debug log319 320 // Arrêter la simulation en cours si elle tourne321 if (simulationInterval) {322 stopSimulation();323 }324 325 // Add vibration animation326 randomizeBtn.classList.add("vibrating");327 setTimeout(() => {328 randomizeBtn.classList.remove("vibrating");329 }, 600);330 331 // Test direct window approach as well332 if (333 window.trackioInstance &&334 typeof window.trackioInstance.jitterData === "function"335 ) {336 console.log(337 "Found window.trackioInstance, calling jitterData directly",338 ); // Debug log339 window.trackioInstance.jitterData();340 } else {341 console.log("No window.trackioInstance found, using store trigger"); // Debug log342 triggerJitter();343 }344 });345 });346</script>347 348<style>349 .trackio-wrapper {350 width: 100%;351 margin: 0px 0 20px 0;352 }353 354 .trackio-controls {355 display: flex;356 justify-content: space-between;357 align-items: center;358 margin-bottom: 16px;359 padding: 12px 0px;360 /* border-bottom: 1px solid var(--border-color); */361 gap: 16px;362 flex-wrap: nowrap;363 }364 365 .controls-left {366 display: flex;367 align-items: center;368 gap: 24px;369 flex-wrap: wrap;370 }371 372 .controls-right {373 display: flex;374 align-items: center;375 gap: 12px;376 flex-wrap: wrap;377 }378 379 .btn-randomize {380 display: inline-flex;381 align-items: center;382 gap: 6px;383 padding: 8px 16px;384 background: var(--accent-color, #007acc);385 color: white;386 border: none;387 border-radius: 6px;388 font-size: 14px;389 font-weight: 500;390 cursor: pointer;391 transition: all 0.15s ease;392 }393 394 .btn-randomize:hover {395 background: var(--accent-hover, #005a9e);396 transform: translateY(-1px);397 }398 399 .btn-randomize:active {400 transform: translateY(0);401 }402 403 .theme-selector {404 display: flex;405 align-items: center;406 gap: 8px;407 font-size: 14px;408 flex-shrink: 0;409 white-space: nowrap;410 }411 412 .theme-selector label {413 font-weight: 500;414 color: var(--text-color);415 }416 417 .theme-select {418 padding: 6px 12px;419 border: 1px solid var(--border-color);420 border-radius: 4px;421 background: var(--input-bg, var(--surface-bg));422 color: var(--text-color);423 font-size: 14px;424 cursor: pointer;425 transition: border-color 0.15s ease;426 }427 428 .theme-select:focus {429 outline: none;430 border-color: var(--accent-color, #007acc);431 }432 433 .scale-controls {434 display: flex;435 align-items: center;436 gap: 16px;437 flex-shrink: 0;438 white-space: nowrap;439 }440 441 /* Vibration animation for button */442 @keyframes vibrate {443 0% {444 transform: translateX(0);445 }446 10% {447 transform: translateX(-2px) rotate(-1deg);448 }449 20% {450 transform: translateX(2px) rotate(1deg);451 }452 30% {453 transform: translateX(-2px) rotate(-1deg);454 }455 40% {456 transform: translateX(2px) rotate(1deg);457 }458 50% {459 transform: translateX(-1px) rotate(-0.5deg);460 }461 60% {462 transform: translateX(1px) rotate(0.5deg);463 }464 70% {465 transform: translateX(-1px) rotate(-0.5deg);466 }467 80% {468 transform: translateX(1px) rotate(0.5deg);469 }470 90% {471 transform: translateX(-0.5px) rotate(-0.25deg);472 }473 100% {474 transform: translateX(0) rotate(0);475 }476 }477 478 .button.vibrating {479 animation: vibrate 0.6s ease-in-out;480 }481 482 .trackio-container {483 width: 100%;484 margin-top: 10px;485 border: 1px solid var(--border-color);486 padding: 24px 12px;487 }488 489 @media (max-width: 768px) {490 .trackio-controls {491 flex-direction: column;492 align-items: stretch;493 gap: 12px;494 }495 496 .controls-left {497 flex-direction: column;498 align-items: stretch;499 gap: 12px;500 }501 502 .theme-selector {503 justify-content: space-between;504 }505 506 .scale-controls {507 justify-content: space-between;508 }509 }510</style>511 