@@ -286,7 +286,7 @@ Base.show(io::IO, ::MIME"text/html", h::RawHTML) = print(io, h.raw)
286286html_anim = """
287287<div style="display: flex; justify-content: center; margin: 20px 0;">
288288 <canvas id="goddardCanvas" width="900" height="650"
289- style="border:1px solid #ddd; background:#fafafa; border-radius: 8px; max-width: 100%;">
289+ style="border:1px solid #ddd; border-radius: 8px; max-width: 100%;">
290290 </canvas>
291291</div>
292292
@@ -306,6 +306,40 @@ html_anim = """
306306 const canvas = document.getElementById('goddardCanvas');
307307 const ctx = canvas.getContext('2d');
308308
309+ // Detect dark/light mode
310+ const isDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
311+
312+ // Color palettes
313+ const colors = isDark ? {
314+ canvas_bg: '#1e1e2e',
315+ ground: '#4a4a4a',
316+ gauge_bg: '#3a3a3a',
317+ gauge_high: '#2ecc71',
318+ gauge_mid: '#f39c12',
319+ gauge_low: '#e74c3c',
320+ text: '#ecf0f1',
321+ text_secondary: '#bdc3c7',
322+ flame_outer: '#e67e22',
323+ flame_inner: '#f1c40f',
324+ window_fill: 'rgba(255,255,255,0.3)',
325+ window_stroke: 'rgba(255,255,255,0.6)',
326+ progress: '#4063D8'
327+ } : {
328+ canvas_bg: '#fafafa',
329+ ground: '#ccc',
330+ gauge_bg: '#ecf0f1',
331+ gauge_high: '#2ecc71',
332+ gauge_mid: '#f39c12',
333+ gauge_low: '#e74c3c',
334+ text: '#2c3e50',
335+ text_secondary: '#7f8c8d',
336+ flame_outer: '#e67e22',
337+ flame_inner: '#f1c40f',
338+ window_fill: 'rgba(255,255,255,0.55)',
339+ window_stroke: 'rgba(255,255,255,0.85)',
340+ progress: '#4063D8'
341+ };
342+
309343 // Animation duration in seconds (independent of real problem time)
310344 const animation_duration = 10.0;
311345
@@ -351,7 +385,7 @@ html_anim = """
351385 ctx.moveTo(zone_x + 20, baseline + 20);
352386 ctx.lineTo(zone_x + zone_width - 20, baseline + 20);
353387 ctx.lineWidth = 2;
354- ctx.strokeStyle = '#ccc' ;
388+ ctx.strokeStyle = colors.ground ;
355389 ctx.stroke();
356390
357391 // Draw fuel gauge (vertical bar to the right of rocket)
@@ -361,16 +395,16 @@ html_anim = """
361395 const fuel_level = (m - mf) / (m0 - mf); // 0 to 1
362396
363397 // Fuel gauge background
364- ctx.fillStyle = '#ecf0f1' ;
398+ ctx.fillStyle = colors.gauge_bg ;
365399 ctx.fillRect(fuel_x - 10, fuel_y, 20, fuel_height);
366400
367401 // Fuel gauge fill
368402 const fuel_fill_height = fuel_level * fuel_height;
369- ctx.fillStyle = fuel_level > 0.5 ? '#2ecc71' : (fuel_level > 0.2 ? '#f39c12' : '#e74c3c' );
403+ ctx.fillStyle = fuel_level > 0.5 ? colors.gauge_high : (fuel_level > 0.2 ? colors.gauge_mid : colors.gauge_low );
370404 ctx.fillRect(fuel_x - 10, fuel_y + (fuel_height - fuel_fill_height), 20, fuel_fill_height);
371405
372406 // Fuel gauge label
373- ctx.fillStyle = '#7f8c8d' ;
407+ ctx.fillStyle = colors.text_secondary ;
374408 ctx.font = '14px Arial';
375409 ctx.textAlign = 'center';
376410 ctx.fillText('Fuel', fuel_x, fuel_y - 8);
@@ -409,16 +443,16 @@ html_anim = """
409443 // Window
410444 ctx.beginPath();
411445 ctx.arc(center_x, rocket_y + 2, 5, 0, 2 * Math.PI);
412- ctx.fillStyle = 'rgba(255,255,255,0.55)' ;
446+ ctx.fillStyle = colors.window_fill ;
413447 ctx.fill();
414- ctx.strokeStyle = 'rgba(255,255,255,0.85)' ;
448+ ctx.strokeStyle = colors.window_stroke ;
415449 ctx.lineWidth = 1.5;
416450 ctx.stroke();
417451
418452 // Draw flame if thrust > 0.1
419453 if (u > 0.1) {
420454 const flame_size = 10 + 20 * u;
421- ctx.fillStyle = '#e67e22' ;
455+ ctx.fillStyle = colors.flame_outer ;
422456 ctx.beginPath();
423457 ctx.moveTo(center_x - 10, rocket_bottom);
424458 ctx.lineTo(center_x, rocket_bottom + flame_size);
@@ -427,7 +461,7 @@ html_anim = """
427461 ctx.fill();
428462
429463 // Inner flame
430- ctx.fillStyle = '#f1c40f' ;
464+ ctx.fillStyle = colors.flame_inner ;
431465 ctx.beginPath();
432466 ctx.moveTo(center_x - 5, rocket_bottom);
433467 ctx.lineTo(center_x, rocket_bottom + flame_size * 0.6);
@@ -437,7 +471,7 @@ html_anim = """
437471 }
438472
439473 // Draw altitude text
440- ctx.fillStyle = '#2c3e50' ;
474+ ctx.fillStyle = colors.text ;
441475 ctx.font = 'bold 14px Arial';
442476 ctx.textAlign = 'center';
443477 ctx.fillText('r = ' + r.toFixed(4), center_x, rocket_y - 40);
@@ -450,20 +484,20 @@ html_anim = """
450484 const v_level = Math.abs(v) / v_max_all;
451485
452486 // Velocity gauge background
453- ctx.fillStyle = '#ecf0f1' ;
487+ ctx.fillStyle = colors.gauge_bg ;
454488 ctx.fillRect(v_gauge_x, v_gauge_y, v_gauge_width, v_gauge_height);
455489
456490 // Velocity gauge fill
457- ctx.fillStyle = v_level > 0.7 ? '#e74c3c' : (v_level > 0.4 ? '#f39c12' : '#2ecc71' );
491+ ctx.fillStyle = v_level > 0.7 ? colors.gauge_low : (v_level > 0.4 ? colors.gauge_mid : colors.gauge_high );
458492 ctx.fillRect(v_gauge_x, v_gauge_y, v_level * v_gauge_width, v_gauge_height);
459493
460494 // Velocity label
461- ctx.fillStyle = '#7f8c8d' ;
495+ ctx.fillStyle = colors.text_secondary ;
462496 ctx.font = '12px Arial';
463497 ctx.fillText('v', center_x, v_gauge_y + 20);
464498
465499 // Draw Tmax label at bottom
466- ctx.fillStyle = '#2c3e50' ;
500+ ctx.fillStyle = colors.text ;
467501 ctx.font = 'bold 16px Arial';
468502 ctx.fillText('Tmax = ' + Tmax, center_x, baseline + 90);
469503 }
@@ -475,10 +509,11 @@ html_anim = """
475509 const progress = (elapsed % animation_duration) / animation_duration;
476510 const t_anim = progress * t_max_global;
477511
478- ctx.clearRect(0, 0, canvas.width, canvas.height);
512+ ctx.fillStyle = colors.canvas_bg;
513+ ctx.fillRect(0, 0, canvas.width, canvas.height);
479514
480515 // Draw time indicator at top
481- ctx.fillStyle = '#2c3e50' ;
516+ ctx.fillStyle = colors.text ;
482517 ctx.font = 'bold 18px Arial';
483518 ctx.textAlign = 'center';
484519 ctx.fillText('t = ' + t_anim.toFixed(3) + ' s', canvas.width / 2, 30);
@@ -504,9 +539,9 @@ html_anim = """
504539
505540 // Draw progress bar at bottom
506541 const bar_height = 4;
507- ctx.fillStyle = '#ecf0f1' ;
542+ ctx.fillStyle = colors.gauge_bg ;
508543 ctx.fillRect(0, canvas.height - bar_height, canvas.width, bar_height);
509- ctx.fillStyle = '#4063D8' ;
544+ ctx.fillStyle = colors.progress ;
510545 ctx.fillRect(0, canvas.height - bar_height, canvas.width * progress, bar_height);
511546
512547 requestAnimationFrame(draw);
0 commit comments