Prompt utilisé pour régénérer cette page :
Page: Solar System - Orbital Mechanics Simulation
Title: "Solar System"
Description: "Orbital mechanics simulation of our cosmic neighborhood"
Icon: earth
Tags: physics, simulation, solar-system, astronomy
Status: validated
Category: computer-science
Front matter: js: default (no scss key — uses default convention)
HTML structure in index.md:
<section class="container visual size-1000 ratio-1-1 canvas-contain">
<canvas id="simulation-canvas"></canvas>
</section>
Widget files:
_presets.left.md (weight: 5, title: "Presets"):
### Presets
div#preset-list.preset-list with 2 preset items:
div.preset-item[data-preset="inner"]: .title "Inner System" + .desc "Mercury, Venus, Earth, Mars"
div.preset-item[data-preset="outer"]: .title "Outer System" + .desc "Jupiter, Saturn, Uranus, Neptune, Pluto"
_planets.left.md (weight: 10, title: "Planets"):
### Planets
div#planet-list (font-size 0.8rem, monospace) — populated dynamically by JS
_controls.right.md (weight: 10, title: "Controls"):
### Controls
Checkbox: <input type="checkbox" id="show-trails" checked> "Show trails"
Speed slider: <input type="range" id="speed-slider" min="0.1" max="2" step="0.1" value="0.5"> with <span id="speed-value">0.5</span>
Button group (flex, gap 0.5rem, center, margin-top 1rem):
{{< button id="btn-play" label="Pause" >}}
{{< button id="btn-reset" label="Reset" >}}
Architecture (4 JS files):
default.js — Main orchestrator (IIFE, ES module imports):
Imports: Body from ./_physics-body.lib.js, VerletEngine from ./_physics-verlet.lib.js, { PRESETS, SOLAR_SYSTEM } from ./_presets.lib.js, panic from /_lib/panic_v3.js
CONFIG: width=1000, height=1000, dt=0.5, tickInterval=16, trailFade=0.985
State: canvas, ctx, bodies[], engine (VerletEngine), running, tickTimer, trailCanvas, trailCtx, currentPreset='inner'
DOM elements: canvas (#simulation-canvas), btnPlay (#btn-play), btnReset (#btn-reset), presetList (#preset-list), showTrails (#show-trails), speedSlider (#speed-slider), speedValue (#speed-value), planetList (#planet-list)
createSolarSystem(): Creates bodies from SOLAR_SYSTEM data filtered by current preset
- Sun: fixed at center (cx=500, cy=500), mass=sunMass from preset, color=#FDB813, visualRadius=15
- Sun has body.fixed=true, body.fixedX=cx, body.fixedY=cy
- Planets: positioned on positive x-axis (x = cx + distance*distanceScale, y = cy)
- Orbital velocity: v = sqrt(sunMass / distance), applied as vy (perpendicular to radius)
- Each planet gets name, visualRadius, mass, color from SOLAR_SYSTEM data
initCanvas(): Sets canvas.width/height = CONFIG.width/height (1000x1000, NO devicePixelRatio scaling)
initTrailCanvas(): Creates offscreen canvas (document.createElement), same dimensions, gets 2d context
reset(): stop(), recreate bodies, new VerletEngine, clear trail canvas, initCanvas, render, panic.info
Simulation control:
start(): Sets running=true, updates button text to "Pause", adds .is-running class, starts setInterval(tick, 16ms)
stop(): Sets running=false, button text "Play", removes .is-running, clearInterval
toggle(): Calls start() or stop() based on running state
tick(): Reads dt from speedSlider value (or CONFIG.dt fallback), calls engine.step(bodies, dt), resets fixed bodies (x=fixedX, y=fixedY, vx=vy=0), calls render()
Trail system:
drawTrails(): Skips if !showTrails.checked. Fades existing trails via destination-out compositing (globalAlpha = 1 - 0.985 = 0.015). Draws 1px arc circles at each body position (skips Sun)
Trail canvas drawn beneath main canvas each frame via ctx.drawImage(trailCanvas, 0, 0)
Rendering:
render(): Calls drawTrails if checked, clears main canvas (transparent), draws trailCanvas, iterates bodies:
Sun: radial gradient glow (color -> color+'80' -> 'transparent', radius = visualRadius*2)
All bodies: filled circle at visualRadius, name label below (#888, 10px monospace, center-aligned, y + radius + 12)
Calls updatePlanetList() after each render
updatePlanetList(): Builds inline HTML for each body — color dot (10px circle), name, distance from sun in AU (calculated as sqrt(dx²+dy²) / preset.distanceScale, displayed with 2 decimals)
switchPreset(presetName): Validates preset exists, sets currentPreset, calls updatePresetList(), reset()
updatePresetList(): Toggles .is-active class on [data-preset] elements matching currentPreset
Event handlers:
btnPlay click → toggle()
btnReset click → reset()
speedSlider input → updates speedValue textContent with 1 decimal
presetList click → event delegation on closest [data-preset], calls switchPreset()
Init sequence: initTrailCanvas(), updatePresetList(), reset(), panic.notice. NO auto-start — waits for Play click
_physics-body.lib.js — Body class (ES module, default export):
constructor(x, y, vx, vy, mass, color='#fff'): Position, velocity, mass, color. Acceleration ax/ay=0. Trail array, maxTrail=500
recordTrail(): Pushes {x,y}, shifts if > maxTrail
clearTrail(): Resets trail=[]
Additional properties set externally: name, visualRadius, fixed, fixedX, fixedY
_physics-verlet.lib.js — VerletEngine class (ES module, default export):
Constants: G=1.0, SOFTENING=0.5
constructor(options={}): this.g (default G), this.softening (default SOFTENING), this._initialized=false
calculateAcceleration(body, bodies): N-body gravitational force. distSq = dx²+dy²+softening², accel = G*other.mass/distSq, direction normalized by dist. Returns {ax,ay}
initialize(bodies): Computes initial accelerations for all bodies, sets _initialized=true
step(bodies, dt): Velocity Verlet integration (3-step):
1. x(t+dt) = x(t) + v*dt + 0.5*a*dt² (position update)
2. Calculate new accelerations at new positions (stores old accelerations)
3. v(t+dt) = v(t) + 0.5*(a_old + a_new)*dt (velocity update with average acceleration)
Records trail for each body after velocity update
Energy methods: kineticEnergy (0.5*m*v²), potentialEnergy (-G*m1*m2/r for all pairs), totalEnergy (KE+PE)
reset(): Sets _initialized=false
_presets.lib.js — Presets and solar system data (ES module, named exports):
PRESETS object with 2 entries:
inner: name "Inner System (Telluric)", distanceScale=315, sunMass=3330, planets=['Mercury','Venus','Earth','Mars']
outer: name "Outer System (Gas Giants)", distanceScale=12, sunMass=3330, planets=['Jupiter','Saturn','Uranus','Neptune','Pluto']
SOLAR_SYSTEM object:
sun: name='Sun', distance=0, mass=333000, radius=15, color='#FDB813'
planets array (9 entries, distance in AU, mass relative to Earth scaled down 100x):
Mercury: distance=0.387, mass=0.00055, radius=3, color=#B5B5B5
Venus: distance=0.723, mass=0.00815, radius=5, color=#E6C87A
Earth: distance=1.0, mass=0.01, radius=5, color=#6B93D6
Mars: distance=1.524, mass=0.00107, radius=4, color=#C1440E
Jupiter: distance=5.203, mass=3.178, radius=12, color=#D4A574
Saturn: distance=9.537, mass=0.952, radius=10, color=#F4D59E
Uranus: distance=19.19, mass=0.145, radius=7, color=#B5E3E3
Neptune: distance=30.07, mass=0.171, radius=7, color=#5B7FDE
Pluto: distance=39.48, mass=0.000022, radius=3, color=#C9B8A0
Exported as: export { PRESETS, SOLAR_SYSTEM }
default.scss:
.preset-list: flex column, gap 0.5rem
.preset-item: padding 0.75rem, background var(--background-color-surface), border 1px solid var(--draw-color-surface), border-radius 0.5rem, cursor pointer, transition border-color 200ms
&:hover: border-color var(--draw-color-primary)
&.is-active: border-color var(--draw-color-primary), background var(--background-color-primary)
.title: font-weight bold, 0.9rem, margin-bottom 0.25rem
.desc: font-size 0.75rem, color #888
Important implementation notes:
- Canvas fixed 1000x1000 (NO devicePixelRatio scaling)
- Simulation loop is setInterval-based (16ms tick), NOT requestAnimationFrame
- No auto-start — simulation waits for user to click Play
- Sun is fixed at center: body.fixed=true, position reset to fixedX/fixedY each tick
- Speed slider value is used directly as dt in engine.step() (range 0.1-2.0)
- Planet distance displayed as raw pixel distance / preset.distanceScale (AU-like units)
- Trail fade uses destination-out compositing with globalAlpha = 1 - trailFade (0.015)
- Uses panic logging library (/_lib/panic_v3.js) for info/warning/notice messages
- Two presets share the same sunMass (3330) but different distanceScale (315 vs 12) for appropriate visualization scale
- Orbital velocity computed as v = sqrt(G*M/r) where G=1, ensuring circular orbits
Page entièrement générée et maintenue par IA, sans intervention humaine.