{"id":50943341,"url":"https://github.com/gtktsc/particles-canvas","last_synced_at":"2026-06-17T17:06:26.104Z","repository":{"id":360530087,"uuid":"975766563","full_name":"gtktsc/particles-canvas","owner":"gtktsc","description":"A real-time 3D atomic particle simulation rendered with the HTML Canvas API and powered by a modular CPU-based physics engine.","archived":false,"fork":false,"pushed_at":"2026-05-26T19:12:25.000Z","size":210,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-05-26T21:11:23.163Z","etag":null,"topics":["graphics","javascript","particles","physics","rendering-engine","typescript"],"latest_commit_sha":null,"homepage":"https://particles-canvas-six.vercel.app","language":"TypeScript","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gtktsc.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-04-30T21:35:38.000Z","updated_at":"2026-05-26T19:12:32.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/gtktsc/particles-canvas","commit_stats":null,"previous_names":["gtktsc/particles-canvas"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/gtktsc/particles-canvas","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gtktsc%2Fparticles-canvas","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gtktsc%2Fparticles-canvas/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gtktsc%2Fparticles-canvas/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gtktsc%2Fparticles-canvas/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gtktsc","download_url":"https://codeload.github.com/gtktsc/particles-canvas/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gtktsc%2Fparticles-canvas/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34457745,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-17T02:00:05.408Z","response_time":127,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["graphics","javascript","particles","physics","rendering-engine","typescript"],"created_at":"2026-06-17T17:06:25.476Z","updated_at":"2026-06-17T17:06:26.090Z","avatar_url":"https://github.com/gtktsc.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Intro University Forces Lab\n\nCPU Canvas 3D particle sandbox for teaching force laws by direct manipulation. It keeps the scene visual and interactive: enable one force, change constants, step time, and watch particles respond.\n\nNot a real atomic, molecular, orbital, or SI-unit simulator. Units are toy units. Accuracy goal: stable, honest, teachable behavior.\n\n## Stack\n\n- Next.js 16 App Router\n- React 19\n- TypeScript strict mode\n- Vitest\n- ESLint flat config\n- Canvas 2D API\n\n## Run\n\n```bash\nnpm install\nnpm run dev\nnpm run check\n```\n\nOpen `http://localhost:3000`.\n\n## Architecture\n\n- `src/features/simulation/model`: settings, constants, force metadata, particles, physics, presets, stats.\n- `src/features/simulation/renderer`: projection, world frame, grid, axes, particles, vectors, FPS.\n- `src/features/simulation/components`: control panel, force cards, stats, sliders, canvas host.\n- `src/features/simulation/hooks`: animation loop, refs, mouse events, initialization.\n\n## Physics Model\n\nFixed-step semi-implicit Euler:\n\n```text\ndt = 1 / 60\na = sum(F) / m\nv = clamp(v + a dt)\nx = x + v dt\n```\n\nPer step:\n\n1. Clear accelerations.\n2. Index particles in a spatial grid.\n3. Apply enabled field forces.\n4. Apply enabled pair forces.\n5. Apply constraints.\n6. Clamp acceleration and speed.\n7. Integrate particles.\n8. Resolve boundaries.\n9. Re-index.\n10. Resolve enabled collisions.\n\nLarge frame gaps are capped so a paused tab does not explode the simulation.\n\n## Force Equations\n\n| Force | Equation | Lesson |\n| --- | --- | --- |\n| Uniform acceleration | `F = m a` | Same acceleration for every mass. |\n| Electric field | `F = qE` | Positive and negative particles accelerate opposite ways. |\n| Magnetic field | `F = q(v x B)` | Force is perpendicular to velocity. |\n| Central inverse-square | `F = -k m r / (r^2 + e^2)^(3/2)` | Softened orbit-like attraction to the center. |\n| Point charge field | `F = q k Q r / (r^2 + e^2)^(3/2)` | External center charge attracts or repels by sign. |\n| Center spring | `F = -k x` | Restoring force grows with displacement. |\n| Drag | `F = -c v` | Force opposes motion and removes energy. |\n| Charge pair | `F = k q1 q2 / (r^2 + e^2)` | Likes repel, opposites attract. |\n| Local gravity pair | `F = G m1 m2 / (r^2 + e^2)` | Masses attract inside a cutoff range. |\n| Lennard-Jones | `F = 24e/r (2(s/r)^12 - (s/r)^6)` | Short-range repulsion, medium-range attraction. |\n| Pair spring | `F = -k(r - L0) - c v_rel` | Nearby particles form damped Hooke springs. |\n| Nuclear toy force | `F = k(1 - r/R)` | Short-range attraction between positive and neutral particles. |\n| Shell constraint | `F = -k(r - R)` | Visual radial constraint, not quantum mechanics. |\n| Fluid drag | `F = -c1(v-u) - c2|v-u|(v-u)` | Particles move toward medium velocity. |\n| Buoyancy | `F = rho V g` | Toy upward force below a fluid surface. |\n| Collision | `J = -(1 + e)vn / invMass` | Contact impulse with restitution. |\n\n`e` means softening. It prevents infinite forces at zero distance.\n\n## Controls Map\n\n- Top controls: pause/resume, single-step, reset simulation, reset forces.\n- View controls: Front, Top, Side, Iso, Reset View.\n- Visualization toggles: axes, grid, field vectors, potential heatmap, velocity vectors, force vectors, labels, trails, depth shading.\n- Measurement toggles: live graphs and probe mode.\n- Initial layout: random, beam, orbit ring, two body, spring line, gas box, falling column.\n- World controls: box width, height, depth, FOV, zoom.\n- Force center controls: center point for spring and central gravity.\n- Particle controls: negative, positive, neutral counts.\n- Force cards: enable toggle, formula, classroom note, primary sliders, advanced constants, reset-one-force.\n\n## Measurements\n\n- Graphs show total energy, average speed, momentum, and angular momentum history.\n- Probe mode lets the next canvas click place a probe point.\n- Probe readout shows position, sampled acceleration, and potential estimate for the selected test particle type.\n- Potential heatmap samples position-only forces: center spring, central inverse-square, and point charge field.\n- Potential energy estimates include spring, central gravity, point charge field, Lennard-Jones, and pair spring terms.\n\nPotential is an estimate for classroom comparison. It is not valid for velocity-dependent forces like drag or magnetic force, and total energy changes when damping, drag, collisions, clamps, or boundaries act.\n\n## Visualization Legend\n\n- Red particles: positive charge.\n- Blue particles: negative charge.\n- White particles: neutral.\n- Red axis: X.\n- Green axis: Y.\n- Blue axis: Z.\n- Cyan arrows: sampled position-field acceleration for a positive test particle.\n- Yellow arrows: velocity vectors.\n- Cyan particle arrows: last acceleration vectors.\n- Orange heatmap: positive potential.\n- Blue heatmap: negative potential.\n- Yellow halo: recent collision.\n- Trails: finite history buffer, not canvas smearing.\n\n## Examples\n\n- Free Motion: no forces. Notice constant velocity until wall or impulse.\n- Constant Acceleration: uniform field. Notice all masses accelerate equally.\n- Electric Field Deflection: electric field only. Notice charge sign controls direction.\n- Magnetic Circular Motion: magnetic field only. Notice sideways force bends paths.\n- Orbit Attempt: central inverse-square. Notice speed decides fall, loop, or escape.\n- Point Charge Field: external center charge. Notice sign-dependent attraction and repulsion.\n- Spring Chain: damped pair springs. Notice wave-like energy transfer.\n- Orbit Ring: central force ring. Notice speed and softening effects.\n- Two-Body Attempt: two particles in a central field. Notice this is not mutual gravity.\n- Viscous Medium: drag toward still fluid. Notice speed decay.\n- Wind Tunnel: drag toward moving medium. Notice particles approach wind velocity.\n- Buoyant Rise: downward acceleration competes with buoyancy. Notice surface threshold.\n- Energy Exchange: spring potential trades with kinetic energy. Notice graph behavior.\n- Charge Dipole: equal positive and negative counts. Notice opposite signs pull together.\n- Charge Attraction: opposite charges. Notice equal and opposite pair forces.\n- Charge Repulsion: like charges. Notice spreading against walls or constraints.\n- Lennard-Jones Gas: preferred spacing. Notice repulsion at close range, attraction farther out.\n- Damped Spring: center spring plus drag. Notice oscillation decay.\n- Collision Momentum: collisions only. Notice momentum exchange through impulses.\n- Nuclear Core: short-range attraction plus charge repulsion. Notice competing ranges.\n- Full Mix: stress test. Good for discussion, poor for isolating one concept.\n\n## Numerical Stability\n\n- Softening avoids singular inverse-square forces.\n- Cutoff ranges keep pair forces fast on CPU.\n- Acceleration and velocity clamps prevent invalid values.\n- Restitution keeps wall and particle bounces bounded.\n- Drag removes energy when a preset needs settling.\n- Fixed timestep keeps motion more consistent across frame rates.\n- History buffers are capped to keep graphs cheap.\n\nTrade-off: these safeguards change exact energy and momentum. That is acceptable here because the lab is for force intuition, not measurement.\n\n## Known Limits\n\n- Toy units only.\n- No SI calibration.\n- No quantum orbitals, spin, radiation, decay, thermodynamics, or molecular chemistry.\n- Canvas 2D projection, not a full 3D camera engine.\n- Pair forces are spatial-grid accelerated and range-limited.\n- Energy is not conserved when drag, clamps, softening, boundaries, or restitution act.\n\n## Quality Gates\n\n```bash\nnpm run lint\nnpm run typecheck\nnpm run test\nnpm run build\nnpm run check\n```\n\nKeep force changes covered by tests near `model`. Keep visual projection changes covered near `renderer`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgtktsc%2Fparticles-canvas","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgtktsc%2Fparticles-canvas","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgtktsc%2Fparticles-canvas/lists"}