Skip to content

Commit 2af6ba0

Browse files
committed
Add dark/light mode support with dynamic canvas background
1 parent 87ed0b0 commit 2af6ba0

1 file changed

Lines changed: 53 additions & 18 deletions

File tree

docs/src/tutorial-continuation.md

Lines changed: 53 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ Base.show(io::IO, ::MIME"text/html", h::RawHTML) = print(io, h.raw)
286286
html_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

Comments
 (0)