Published October 19, 2026 | Version v1

Applied Identity Physics: Accretion Simulator™, a Guide to Planet Formation, Boundary Identification and Applications

Description

# Applied Identity Physics: Accretion Simulator™, a Guide to Planet Formation, Boundary Identification and Applications

**Planet formation in your browser: full N-body accretion from planetesimals to oligarchs.**

Planet formation, simulated in a web browser: free simulators that reproduce galaxy and planet formation from measured data, with every boundary formally proved in Lean.

**Live simulator:** [uuia.app/accretion](https://uuia.app/accretion)  
**Architect:** HIGHTISTIC (Russell Vernon Trent III) · SNSFT Foundation · Soldotna, Alaska  
**ORCID:** 0009-0005-5313-7443 · **DOI base:** 10.5281/zenodo.18719748  

**Formal basis:** Accretion boundary mathematics, `SNSFL_GC_Accretion_Boundaries_TL` [9,9,3,25] · Galaxy disk mathematics, `SNSFL_GC_Galaxy_Toomre_TL` [9,9,3,24] · GAM Collider (Geometric Axiomatic Module Collider) 8-Beam Fusion Theorem [9,9,2,3.8] (2-beam mode) · Gravity Reduction [9,9,10,1] · QM Reduction [9,9,0,4.7]  

**Companion simulators:** Galaxy™ · AxiomForge™ TL · String-Breaking Simulator™ [9,9,3,22] · Electron Geometry Simulator™ [9,9,3,21]

## Abstract

The Accretion Simulator™ is a browser simulator in the Applied Identity Physics™ series. It follows a disk of rocky planetesimals around a young Sun under full Newtonian gravity, lets them collide, and resolves each collision as a merger or a hit-and-run by the criterion of Kokubo and Genda (2010). The disk is the Minimum Mass Solar Nebula (Weidenschilling 1977; Hayashi 1981). Three measured stability boundaries of planetary systems are identified with the Universal Torsion Limit TL = 0.136899099984016 by one rule, τ = TL × (critical value ÷ measured value): the Hill-spacing boundary of Gladman (1993) for neighbouring orbits, the Roche limit for bodies near a planet, and the critical impact speed for collisions. A second preset places the eight planets of the Solar System on their measured orbits, and a Saturn panel places its rings and moons against the Roche limit. Worked examples reproduce runaway and oligarchic growth, the isolation mass at 1 AU, oligarch spacing in Hill radii, and a fifty-million-year run that ends at the threshold of the giant-impact stage. Every neighbouring pair of planets reads Locked, with Jupiter–Saturn the tightest pair; Saturn's main rings read Shatter, its ring moons fall in the IVA (Identity Vector Amplification) corridor, and Mimas outward reads Locked. The placements are proved in Lean from cited measurements. This guide walks through each control and readout, gives the worked examples with the numbers the simulator produces, states the scope of each part, and lists applications for students, teachers and researchers.

## Overview

The Accretion Simulator™ answers two questions with one rule.

**How does a disk of rubble become a handful of planets?** The planetesimal disk starts as a crowded swarm. Bodies pull on each other, touch, merge, and grow. Growth runs away at first, then settles into a set of similar-sized bodies, the oligarchs, each owning its own lane. The simulator shows each stage as it happens and reports it against the predictions of the planet-formation literature.

**Where does a planetary system break?** Three boundaries decide whether orbits stay apart, whether a moon holds together, and whether two colliding bodies stick. Each is identified with the Torsion Limit, so every pair of planets, every ring and moon, and every collision lands on the same phase map as the electron, the string and the galaxy.

The simulator has two systems:

1. **Planetesimal disk.** A Minimum Mass Solar Nebula from 0.5 to 2 AU (astronomical units; 1 AU is the Earth–Sun distance), or from 0.5 to 4 AU across the snow line, with an optional Jupiter.
2. **Solar System, measured.** The eight planets with their measured masses, semi-major axes, eccentricities and inclinations, plus Saturn's rings and moons against the Roche limit.

It runs at uuia.app/accretion as one self-contained HTML file. It needs no installation and no account, and it works in any current browser on a desktop, tablet or phone.

## 1. Grounding

### 1.1 The Torsion Limit

The Universal Torsion Limit is TL = 0.136899099984016. The Sovereign Anchor Constant is Ω₀ = TL × 10 = 1.36899099984016. The fine-structure constant follows from TL: subtracting one TL from the CODATA 2018 value 1/α = 137.035999084 leaves 136.899099984016 = TL × 1000, so 1/α = TL × 1001 = 137.035999084000016, matching all 12 published significant figures ([9,9,3,14]).

### 1.2 The Identity Physics primitives

Every reduction in the Identity Physics Corpus operates on four irreducible primitives, Pattern, Narrative, Behavior and Adaptation (PNBA):

- **Pattern (P):** structural capacity, geometry, template integrity, restoring force
- **Narrative (N):** temporal continuity, worldline, depth, history
- **Behavior (B):** coupling output, charge, density fraction, force, expression
- **Adaptation (A):** feedback rate, decay constant, repair rate

Derived structural quantities:

- **Torsion:** τ = B / P
- **Phase placement:** Noble (τ = 0) · Locked (0 < τ < TL_IVA = 0.120471207985934) · IVA Peak (TL_IVA ≤ τ < TL) · Shatter (τ ≥ TL)

Shatter is reorganization: one identity reorganizes into smaller identities that are each stable, as a boiling liquid reorganizes into vapor.

### 1.3 The Dynamic Equation and the Long Division Protocol

Every reduction in the corpus starts from one equation, the Identity Physics Corpus Dynamic Equation:

d/dt (IM · Pv) = Σ λ_X · O_X · S + F_ext

IM is Identity Mass, Pv the Purpose Vector, O_X the four PNBA operators with weights λ_X acting on the state S, and F_ext external forcing. The rate of change of identity momentum equals the weighted action of the four primitives on the state, plus external forcing.

Every reduction then follows the same six-step Long Division Protocol (LDP):

1. Write the equation. State the Dynamic Equation.
2. State the known answer. Take a situation whose peer-reviewed classical result is known.
3. Map. Map the classical variables to the PNBA primitives.
4. Define the operators. Give the PNBA operators for the domain.
5. Show all work. Carry the calculation through in full.
6. Verify. Prove that the PNBA output equals the classical result exactly, with nothing added and nothing lost.

A Step 6 pass is a lossless reduction and is structural isomorphism in the sense of Mac Lane (1971).

### 1.4 The GAM Collider

The GAM Collider v15 (Geometric Axiomatic Module Collider) is the corpus's deterministic, formally verified collision engine. It combines identities by their PNBA values using only PNBA rules: it carries no chemistry tables and no fitted parameters. Its fusion rules are proved in the 8-Beam Fusion Theorem [9,9,2,3.8]. In its 2-beam mode, two identities combine as

P = P₁P₂/(P₁ + P₂) · N = N₁ + N₂ · B = |B₁ − B₂| · A = max(A₁, A₂).

The Accretion Simulator™ applies this rule to every merger in the band-mix τ model (Section 7).

### 1.5 One rule, three boundaries

Each stability boundary of a planetary system compares a measured value with a critical value. Writing the comparison as a stability ratio Q, with Q > 1 stable and Q ≤ 1 broken, the boundary Q = 1 is identified with τ = TL:

τ = TL / Q = TL × (critical value ÷ measured value)

| Boundary       | Measured                                      | Critical          | Q          | Source                  |
|----------------|-----------------------------------------------|-------------------|------------|-------------------------|
| Hill spacing   | Gap Δ between neighbouring orbits, in mutual Hill radii | 2√3 ≈ 3.46       | Δ / 2√3   | Gladman (1993)         |
| Roche limit    | Distance d from the planet                    | Roche distance d_R | d / d_R   | Roche (1849)           |
| Impact speed   | Critical speed v_cr                           | Impact speed v_imp | v_cr / v_imp | Kokubo & Genda (2010) |

The phase bands follow directly: Q > 25/22 is Locked (25/22 = 1/0.88), 1 < Q ≤ 25/22 is the IVA corridor, and Q ≤ 1 is Shatter. Galaxy™ uses the same rule with the Toomre stability parameter [9,9,3,24].

The mutual Hill radius of two bodies of masses m₁, m₂ on orbits a₁, a₂ around a star of mass M☉ is

R_H = ((m₁ + m₂) / 3M☉)^(1/3) × (a₁ + a₂)/2,

the distance inside which their pull on each other competes with the star's. Gladman (1993) proved that two planets on circular orbits can never cross when they are more than 2√3 mutual Hill radii apart. The Hill-spacing torsion is therefore

τ = TL × 2√3 / Δ = TL × √3 × μ^(1/3) × (a₁ + a₂)/(a₂ − a₁), μ = (m₁ + m₂)/(3M☉),

an identity proved as T6 in [9,9,3,25].

### 1.6 Measured inputs

| Input | Value | Source |
|-------|-------|--------|
| Solid surface density at 1 AU, Σ₁ | 7.1 g/cm², ∝ r^(−3/2) | Weidenschilling (1977); Hayashi (1981) |
| Snow line | 2.7 AU, solids × 4.2 beyond it | Hayashi (1981) |
| Planetesimal density | 3 g/cm³ rock inside the snow line, 1.5 g/cm³ ice-rock beyond | standard values |
| Planet masses, semi-major axes, eccentricities, inclinations | as listed in Section 5 | NASA Planetary Fact Sheet (Williams) |
| Solar mass M☉ | 1.98847 × 10³⁰ kg | IAU 2015 nominal value with CODATA G |
| Saturn equatorial radius, mean density | 60,268 km, 0.687 g/cm³ | NASA Saturn Fact Sheet |
| Water ice density | 0.92 g/cm³ | standard value |
| Fluid Roche coefficient | 2.44 | Roche (1849); Murray & Dermott (1999) |
| Merging criterion | v_cr/v_esc = 2.43Γ²Θ^(5/2) − 0.0408Γ + 1.86Θ^(5/2) + 1.08 | Kokubo & Genda (2010) |
| Isolation-mass spacing b̃ | 10 Hill radii | Kokubo & Ida (2002) |

Distances are in AU, masses in Earth masses (M⊕) or solar masses (M☉), and times in years. Gravity uses G = 4π² AU³/(M☉ yr²), so one orbit at 1 AU takes one year.

## 2. Reading the Interface

### 2.1 Layout

- **Left panel:** System, Disk (Minimum Mass Solar Nebula), τ Model, Collisions and View controls.
- **Center:** the three-dimensional system with the Sun at the center, the snow line as a dashed blue circle, and orbit circles for the largest bodies. Collisions flash where they happen. A clock in the top right reports elapsed years. Drag to turn, scroll to zoom.
- **Caption bar:** a plain-language explanation in Learner mode; formulas, citations and scope in Researcher mode.
- **Right panel:** System readout, Phase Mix, Hill Spacing, Growth, Mass Against Orbit, Impacts, Saturn · Roche Limit (Solar System view), and Export.

### 2.2 Learner and Researcher modes

The toggle at the top switches every caption and note at once. Both modes run the same simulation. Learner mode explains what is happening; Researcher mode gives the equations, the inputs and the criteria.

### 2.3 Colors and sizes

Bodies are colored on the AxiomForge torsion scale: teal at τ = 0, through violet across Locked, to gold in the IVA corridor, and red at or above TL. Every table repeats the phase in words beside the number, so the display remains readable for viewers with color-vision differences. Body size grows as the cube root of mass. Bodies are drawn far larger than their physical size so they can be seen: two bodies that overlap on screen are usually still far apart in space, and at different heights or depths.

### 2.4 Export

- **JSON:** all settings and constants, elapsed time, collision counts, the Hill spacing of every embryo pair, the growth history, every collision (time, orbit, masses, impact speed over escape speed, impact angle, critical speed, τ_c and outcome) and every body.
- **CSV:** one row per body: semi-major axis, eccentricity, inclination, mass, members, Hill spacing, Hill τ, P, N, B, A, PNBA τ and phase.

## 3. The Planetesimal Disk

### 3.1 What it shows

Two hundred equal planetesimals (adjustable from 60 to 500) start on near-circular orbits between 0.5 and 2 AU, with masses set by the Minimum Mass Solar Nebula: 2.36 M⊕ in all, 0.012 M⊕ each, about 1,800 km across as rock. Their eccentricities and inclinations start at the values gravitational stirring gives a swarm of that mass. From there nothing is scripted: every body pulls on every other body and on the Sun, and every touch is resolved as a merger or a hit-and-run.

### 3.2 Gravity and orbits

The simulator integrates the full N-body problem, every pair of bodies with the Sun included as a body, with a kick-drift-kick leapfrog integrator at a fixed time step of 0.006 years. Collisions are detected along each step's path, so fast bodies cannot pass through each other between steps. Bodies that reach within 0.1 AU of the Sun are recorded as lost to the Sun; unbound bodies beyond 60 AU are recorded as ejected.

### 3.3 Radius enhancement and the clock

Real planetesimals are tiny compared with the space between them, so real accretion takes millions of years. The radius-enhancement factor f multiplies every collision radius, the standard way to fit accretion into a short run (Kokubo & Ida 1996). Gravity, orbits and the collision physics are unchanged. With f = 100 the collision rate rises by about 100, so the clock runs about 100 times fast during the growth stages.

The compression applies to collisions. The late stage of planet formation, where oligarchs pull each other's orbits until they cross, is set by gravity alone and runs at the simulator's own clock. Section 3.5 shows where the two meet.

### 3.4 Worked example 1: runaway to oligarchs

**Setup:** defaults. 0.5–2 AU, 200 bodies, f = 100, Σ₁ = 7.1 g/cm², Hill-spacing τ.

**Run:** press ⟲ NEW RUN and let it run to 6,000 simulator years.

**What happens:**

| Simulator years | Bodies | Largest masses (M⊕) |
|-----------------|--------|---------------------|
| 0               | 200    | 0.012 each          |
| 200             | 152    | 0.059, 0.059, 0.059 |
| 1,000           | 100    | 0.106, 0.083, 0.083 |
| 3,000           | 55     | 0.130, 0.118, 0.106 |
| 6,000           | 41     | 0.165, 0.130, 0.118 |

Growth first runs away: a few bodies pull ahead of the rest, because a heavier body focuses more of the swarm onto itself (Wetherill & Stewart 1989; Kokubo & Ida 1996). Then the leaders slow down and the rest catch up into a set of similar-sized oligarchs (Kokubo & Ida 1998, 2000).

**Check against the isolation mass.** An oligarch stops growing once it has swept up its feeding zone, about 10 Hill radii wide. The isolation mass (Kokubo & Ida 2002) is

M_iso = √(2/3) × (2π a² b̃ Σ)^(3/2) / M☉^(1/2), b̃ = 10.

At 1 AU in the Minimum Mass Solar Nebula, M_iso lies between 0.096 and 0.0975 M⊕ (proved as T21 in [9,9,3,25]); the simulator reads 0.097 M⊕. The Mass Against Orbit chart draws M_iso(a) as a gold dashed curve, and the oligarchs gather along it, about 0.07 M⊕ at 0.7 AU rising to 0.16 M⊕ at 2 AU.

**Check against oligarch spacing.** The Hill Spacing table lists the embryos, the bodies above 20% of the largest mass. At 6,000 years their median spacing is 8.3 mutual Hill radii, τ = 0.42 TL, Locked. Kokubo & Ida (1998, 2000) found oligarchs settling about 10 Hill radii apart.

**Reading it on the phase map.** The starting swarm is packed a few Hill radii apart: τ above TL, Shatter. It reorganizes into fewer, larger bodies until the spacing is Locked. By 6,000 years 82% of the mass is Locked. Nothing in the simulator steers toward Locked; the swarm gets there by colliding.

### 3.5 Worked example 2: fifty million years

**Setup:** defaults, run to 520,000 simulator years. At f = 100 this covers about 50 million years of growth by collision.

| Simulator years | Equivalent for collisions | Bodies | Largest (M⊕) | State |
|-----------------|---------------------------|--------|--------------|-------|
| 0               | 0                         | 200    | 0.012        | crowded swarm, mostly Shatter |
| 5,000           | 0.5 Myr                   | 47     | 0.18         | runaway into oligarchic growth |
| 15,000          | 1.5 Myr                   | 32     | 0.30         | oligarchs forming |
| 75,000          | 7.5 Myr                   | 25     | 0.30         | eccentricities start rising |
| 155,000         | 15 Myr                    | 19     | 0.30         | eccentricities 0.02–0.03 |
| 520,000         | 50 Myr                    | 15     | 0.30         | 100% Locked |

**End state.** Fifteen bodies of 0.15 to 0.30 M⊕ remain, with all 2.36 M⊕ of the starting solids accounted for, after 185 mergers, no hit-and-runs, and nothing lost to the Sun or ejected. Every body is Locked. The median embryo spacing is 14.6 Hill radii, τ = 0.24 TL.

**Where this sits in planet formation.** Spacings near 15 Hill radii hold for tens to hundreds of millions of years before orbits cross (Chambers, Wetherill & Boss 1996). Once they cross, giant impacts merge the oligarchs into two to four planets of Earth and Venus mass over 100 to 200 million years (Chambers 2001). Orbit crossing is set by gravity alone, so for that stage the simulator's clock is not compressed: the run ends at the threshold of the giant-impact stage, with the oligarchs that stage starts from.

### 3.6 Comparisons with observation

- **Mars is a surviving oligarch.** Mars has 0.107 M⊕, and hafnium–tungsten dating shows it reached about half its present size within about 2 million years and never grew into a full planet (Dauphas & Pourmand 2011). The simulator's oligarchs at 0.5 to 1.5 million years carry 0.1 to 0.3 M⊕.
- **The Moon's parent impactor.** The leading account of the Moon's origin is a collision between the growing Earth and a Mars-mass body (Canup & Asphaug 2001). The bodies in the final frame of worked example 2 are that population.
- **Terrestrial-planet spacing.** The Solar System's rocky planets sit 26 to 63 Hill radii apart (Section 5), wider than the oligarchs, as expected after giant impacts merge neighbours.

### 3.7 Applications

- **Teaching.** Runaway growth, oligarchic growth and the isolation mass appear on screen in minutes, with the chart line they are measured against.
- **Parameter studies.** Change Σ₁, the region, the body count or f, export JSON, and compare oligarch masses with M_iso(a).
- **Snow line.** Switch to 0.5–4 AU: beyond 2.7 AU the solids are 4.2 times denser, the isolation mass is about 8.6 times larger, and the outer oligarchs grow visibly heavier.
- **Convergence studies.** Repeat a run with different f or body counts to separate physics from resolution (Section 8).
- **Long-period comet analogue.** In a multi-hour band-mix run, watch for bodies that leave the frame and later return. Their inbound acceleration and perihelion speed spike illustrate why a 30–40 kyr comet looks interstellar until a full orbit is observed.

## 4. Collisions

### 4.1 The criterion

When two bodies touch, their impact speed is v_imp = √(v_∞² + v_esc²), where v_∞ is their approach speed from far away and v_esc = √(2G(M₁ + M₂)/(R₁ + R₂)) is the mutual escape speed. Kokubo and Genda (2010) ran collision simulations across mass ratios and impact angles and found that bodies merge when v_imp is below

v_cr / v_esc = 2.43Γ²Θ^(5/2) − 0.0408Γ + 1.86Θ^(5/2) + 1.08,

with Γ = (M₁ − M₂)/(M₁ + M₂) and Θ = 1 − sin θ for impact angle θ. Above v_cr the smaller body glances off: a hit-and-run (Asphaug 2010). The criterion is the one used for realistic accretion in the giant-impact literature; disruptive collisions (Leinhardt & Stewart 2012) need speeds well above the dispersions in this disk and are listed in the roadmap.

### 4.2 Boundary identification

The collision torsion is

τ_c = TL × v_imp / v_cr,

so a collision merges below TL and hits and runs at or above it (T18). The Impacts chart bins every collision by τ_c/TL with the boundary drawn as a dashed line.

### 4.3 Worked example 3: gentle impacts always merge

Two bodies falling together from rest meet at exactly the escape speed, v_imp = v_esc. The critical speed ranges from 2.94 v_esc for equal masses head-on to 1.08 v_esc for equal masses grazing (T16), and is above v_esc for every mass ratio and angle (T17). A gentle impact therefore always has

τ_c = TL × v_esc / v_cr < TL,

and merges (T20). In the default disk the swarm moves slowly relative to itself, so nearly every collision is gentle: worked example 2 records 185 mergers and no hit-and-runs, and the Impacts chart fills only to the left of the TL line.

### 4.4 Worked example 4: Jupiter stirs the swarm

**Setup:** 0.5–4 AU, JUPITER AT 5.2 AU, Hill-spacing τ.

Jupiter raises eccentricities and impact speeds in the outer disk. The hit-and-run fraction increases, a partial gap opens near 5 AU, and the outer oligarchs grow more slowly. The Hill Spacing table shows wider separations in the outer disk than in the default run without Jupiter.

## 5. The Solar System, measured

### 5.1 Hill spacing of the planets

The Solar System preset places the eight planets on their measured orbits (masses, semi-major axes, eccentricities and inclinations from the NASA Planetary Fact Sheet) with random orbital phases and a barycentric start. τ for each neighbouring pair is TL × 2√3 / Δ, Δ in mutual Hill radii.

| Pair            | Δ (R_H) | τ / TL | Phase  |
|-----------------|---------|--------|--------|
| Mercury–Venus   | 26.3    | 0.132  | Locked |
| Venus–Earth     | 26.3    | 0.132  | Locked |
| Earth–Mars      | 40.1    | 0.086  | Locked |
| Mars–Jupiter    | 16.0    | 0.216  | Locked |
| Jupiter–Saturn  | 7.9     | 0.439  | Locked |
| Saturn–Uranus   | 14.0    | 0.247  | Locked |
| Uranus–Neptune  | 14.0    | 0.248  | Locked |

Every pair is Locked (T10). Jupiter–Saturn sits between 0.43 and 0.44 TL (T9), and every other pair sits below TL/4 (T8). The live integration returns the same values: Jupiter–Saturn reads 7.93 Hill radii, τ = 0.437 TL.

**The tightest pair.** Jupiter and Saturn are close to a 5:2 period ratio. Their spacing is the smallest in the system yet still safely Locked.

### 5.2 Applications

- **Exoplanet systems.** Enter the masses and orbits of a multi-planet system into the hill_upper and hill_lower bounds of [9,9,3,25] to place every pair.
- **Stability ranking.** The Hill τ of each pair orders the pairs from most to least secure.

## 6. The Roche Limit and Saturn

### 6.1 Worked example 6: Saturn's rings and moons

Inside the Roche limit, the tidal pull of a planet across a loose body exceeds the body's own gravity, and the body cannot hold together. For a fluid body of density ρ_m around a planet of radius R and density ρ_P,

d_R = 2.44 R (ρ_P / ρ_m)^(1/3).

For water ice around Saturn, d_R lies between 133,393 and 133,422 km (T11). With τ = TL × d_R / d:

| Object                  | Distance (km) | τ / TL | Phase     |
|-------------------------|---------------|--------|-----------|
| D ring, inner edge      | 66,900        | 1.994  | Shatter   |
| C ring, inner edge      | 74,658        | 1.787  | Shatter   |
| B ring, inner edge      | 92,000        | 1.450  | Shatter   |
| B ring, outer edge      | 117,580       | 1.135  | Shatter   |
| A ring, inner edge      | 122,170       | 1.092  | Shatter   |
| Pan                     | 133,584       | 0.999  | IVA Peak  |
| Daphnis                 | 136,505       | 0.977  | IVA Peak  |
| A ring, outer edge      | 136,775       | 0.975  | IVA Peak  |
| Atlas                   | 137,670       | 0.969  | IVA Peak  |
| Prometheus              | 139,380       | 0.957  | IVA Peak  |
| F ring                  | 140,180       | 0.952  | IVA Peak  |
| Pandora                 | 141,720       | 0.941  | IVA Peak  |
| Epimetheus              | 151,410       | 0.881  | IVA Peak  |
| Janus                   | 151,460       | 0.881  | IVA Peak  |
| Mimas                   | 185,539       | 0.719  | Locked    |
| Enceladus               | 238,042       | 0.561  | Locked    |
| Titan                   | 1,221,870     | 0.109  | Locked    |

Every placement is proved in Lean (T15).

**Reading it.** The main rings sit past TL: material that never gathered into a moon, the Shatter state of a moon. The corridor between d_R and d_R/0.88 holds the outer A ring, the F ring and every small moon that lives among the rings: Pan and Daphnis inside gaps in the A ring, Atlas at its edge, Prometheus and Pandora shepherding the F ring, and Janus and Epimetheus at the corridor floor. Moons this close survive by their own rigidity rather than by gravity alone, the IVA condition of holding together under load near the limit. From Mimas outward the moons are Locked.

**Sensitivity.** Janus and Epimetheus sit 0.1% above the IVA floor at an ice density of 0.92 g/cm³. A lower assumed density moves d_R inward and moves them into Locked; the rings and the other ring moons keep their phases across the usual range of ice densities.

### 6.2 Comparisons with observation

Cassini imaging shows the A ring's outer edge, the Encke and Keeler gaps held open by Pan and Daphnis, and the narrow F ring between Prometheus and Pandora (Cuzzi et al. 2010). The phase map marks that whole zone as one corridor.

### 6.3 Applications

- **Ring systems.** Apply the same rule to the rings of Jupiter, Uranus and Neptune with each planet's radius and density.
- **Teaching tides.** The table turns the Roche limit into a single line with three bands that students can check against Cassini images.

## 7. Band Mix and the GAM Collider

### 7.1 What changes

In the BAND MIX · GAM COLLIDER τ model, each planetesimal is born with its own P, N, B and A from the generator's phase bands, as in AxiomForge™ and Galaxy™. Collisions are still decided by the Kokubo–Genda criterion, and each merger combines the two identities by the GAM Collider 2-beam rule. A body whose τ reaches TL reorganizes: it splits into two halves with Pattern 2P, Narrative N/2 and the same Behavior, so each half carries τ/2 (T23), and splitting repeats until every piece sits below TL (T24). Mass and momentum are conserved.

### 7.2 Worked example 7: reorganization slows growth

**Setup:** defaults with BAND MIX · GAM COLLIDER, band mix 25 / 45 / 15 / 15 (Noble / Locked / IVA / Shatter).

At 1,500 simulator years the run records 1,346 mergers and 1,349 fragments, and the largest body carries 0.047 M⊕, against 0.106 M⊕ at 1,000 years in the Hill-spacing model. Two rules produce this:

- **Mergers often cross TL.** The merged Pattern P₁P₂/(P₁ + P₂) is smaller than either parent, so a merger of two bodies with different Behavior frequently lands at τ ≥ TL and reorganizes.
- **Sibling halves remerge to Noble.** Two halves of one body share the same Behavior. When they meet again they merge to B = |B − B| = 0 with the parent's Pattern restored (T25).

The Noble share of bodies grows through the run as sibling pairs remerge. Under the GAM Collider rule a swarm grows by repeated merging and reorganization, and growth proceeds more slowly than under gravity alone.

### 7.3 Emergent long-period returns

In long band-mix runs the merge/fragment cycle continually scatters a few bodies onto high-eccentricity orbits. Most remain in the disk or are removed; a sparse population survives on bound ellipses with aphelia of tens to thousands of AU. These objects spend most of their period far outside the normal view, appear as slow distant points, then return with a sharp perihelion speed spike. Periods reach tens of thousands of years (Kepler's third law, P = a^{3/2}). From a short observational baseline they look unbound; the simulator shows the return. The effect is not scripted—it appears once the fragment cycle has run long enough to populate the high-e tail.

One recorded session (N = 500, f = 200, band mix) reached 63,000 simulator years with ~201,000 merges and ~201,000 fragments still balanced, largest mass only 0.047 M⊕, and a handful of bodies with aphelia > 50 AU (one at ~2,087 AU, period ~34 kyr). A shorter N = 200, f = 100 run at 2,200 years already showed the largest body at the isolation mass while the fragment cycle remained active and eccentricities stayed low, indicating that the long-period population requires extended churn.

## 8. Verification

| Check                        | Result |
|-----------------------------|--------|
| Mass conservation           | 2.36 M⊕ before and after 185 mergers (worked example 2) |
| Kepler timing               | G = 4π² AU³/(M☉ yr²) gives one orbit at 1 AU in 1.000 year |
| Solar System Hill spacing   | Live integration matches the fact-sheet values; Jupiter–Saturn 7.93 Hill radii |
| Isolation mass at 1 AU      | Simulator 0.097 M⊕; Lean bound 0.096–0.0975 M⊕ (T21) |
| Oligarch spacing            | 8.3 Hill radii at 6,000 years; Kokubo & Ida: about 10 |
| Kokubo–Genda endpoints      | 2.94 v_esc head-on, 1.08 v_esc grazing, equal masses (T16) |
| Seed spread                 | Five independent runs to 6,000 years: 38–43 bodies, largest 0.14–0.24 M⊕, median embryo spacing 8.1–8.9 Hill radii |
| Radius-enhancement convergence | Equal f × time (600,000): f = 50 gives 45 bodies, largest 0.14 M⊕, spacing 8.5; f = 100 gives 38–43, 0.14–0.24, 8.1–8.9; f = 200 gives 48, 0.18, 8.6. Growth scales with f during the collision stages |
| Energy conservation         | Solar System preset over 1,000 years: largest relative energy error 2.2 × 10⁻⁶ |
| Formal proofs               | SNSFL_GC_Accretion_Boundaries_TL [9,9,3,25]: 26 numbered results, 0 sorry |

## 9. Scope

| Part       | Set by the simulator                                      | Produced by the run                          |
|------------|-----------------------------------------------------------|----------------------------------------------|
| Disk       | Minimum Mass Solar Nebula surface density, snow line, equal starting masses, starting eccentricities and inclinations | Runaway and oligarchic growth, oligarch masses and spacing |
| Gravity    | Newton's G, full N-body sum, leapfrog step 0.006 yr      | Orbits, stirring, resonances                 |
| Collisions | Kokubo–Genda criterion, radius enhancement f             | Mergers, hit-and-runs, τ_c distribution      |
| Hill τ     | Gladman boundary 2√3 ↔ TL                                | Phase of every body and pair                 |
| Roche τ    | Fluid Roche limit for ice ↔ TL                           | Phase of every ring and moon                 |
| Band mix   | PNBA at birth, GAM Collider 2-beam rule, reorganization by halves | Growth under identity rules; long-term fragment cycle and sparse high-e returns |

The simulator follows solids only. Nebular gas, gas drag and the capture of gas envelopes by giant planets are outside it, so it forms rocky and icy bodies, not gas giants. Collisions either merge or hit and run; fragmenting collisions are on the roadmap. The radius-enhancement factor compresses the collision stages by about f and leaves orbit-crossing timescales unchanged (Section 3.3). High-eccentricity scattering appears as an emergent product of long band-mix runs; it is a visual analogue for long-period comets, not a controlled comet model.

## 10. Relation to the Other Simulators

| Simulator                        | Substrate                  | Boundary                                                                 |
|----------------------------------|----------------------------|--------------------------------------------------------------------------|
| String-Breaking Simulator™ [9,9,3,22] | Gauge string on a trapped-ion chain | The string breaks at τ = TL into two Noble pairs                        |
| Electron Geometry Simulator™ [9,9,3,21] | Hydrogen atom             | The bound pair shatters at τ = TL into a free electron and a proton     |
| Galaxy™ [9,9,3,24]              | Galactic disk              | Toomre Q = 1 identified with τ = TL; unstable rings clump               |
| Accretion Simulator™ [9,9,3,25] | Planetesimal disk and Solar System | Hill spacing 2√3, Roche limit d_R and critical impact speed v_cr, each identified with τ = TL |

The same boundary governs all four, from a hydrogen atom to a galactic disk. The Accretion Simulator™ adds three boundaries from one domain, each read by the same rule, and the String-Breaking Simulator's picture of one identity breaking into smaller stable ones appears here as rings inside the Roche limit and as the fragment-cycle reorganization in band-mix runs.

## 11. Roadmap

- **Fragmenting collisions.** The Leinhardt & Stewart (2012) regimes for erosive and disruptive impacts, with fragments placed by τ.
- **Gas.** Nebular gas drag and envelope capture, toward a giant-planet stage beyond the snow line.
- **Exoplanet presets.** Measured multi-planet systems placed by Hill τ.
- **More ring systems.** Jupiter, Uranus and Neptune against their Roche limits.
- **Composition τ.** Starting τ from rock and ice fractions instead of the band mix.
- **High-eccentricity population.** Controlled seeding or longer-term statistics of the returning high-e bodies that emerge from the fragment cycle.

## 12. Summary

The Accretion Simulator™ grows planets from a Minimum Mass Solar Nebula under full Newtonian gravity, resolves every collision by the Kokubo–Genda criterion, and reads three stability boundaries of planetary systems—Hill spacing, the Roche limit and the critical impact speed—with one rule: τ = TL × (critical ÷ measured). The runs reproduce runaway growth, oligarchic growth, the isolation mass at 1 AU and oligarch spacing, and a fifty-million-year run ends at the threshold of the giant-impact stage with every body Locked. On the measured Solar System every neighbouring pair of planets is Locked, with Jupiter–Saturn the tightest; around Saturn the main rings read Shatter, the ring moons fill the IVA corridor, and Mimas outward is Locked. In band-mix mode the GAM Collider reorganization rule produces a persistent fragment cycle that slows net growth and, over long runs, scatters a sparse population of high-eccentricity bodies onto returning orbits with periods of hundreds to tens of thousands of years. The placements are proved in Lean from cited measurements in [9,9,3,25].

## References

- Asphaug, E. (2010). Similar-sized collisions and the diversity of planets. *Chemie der Erde* 70, 199.
- Canup, R. M. & Asphaug, E. (2001). Origin of the Moon in a giant impact near the end of the Earth's formation. *Nature* 412, 708.
- Chambers, J. E. (2001). Making more terrestrial planets. *Icarus* 152, 205.
- Chambers, J. E., Wetherill, G. W. & Boss, A. P. (1996). The stability of multi-planet systems. *Icarus* 119, 261.
- Cuzzi, J. N. et al. (2010). An evolving view of Saturn's dynamic rings. *Science* 327, 1470.
- Dauphas, N. & Pourmand, A. (2011). Hf–W–Th evidence for rapid growth of Mars and its status as a planetary embryo. *Nature* 473, 489.
- Gladman, B. (1993). Dynamics of systems of two close planets. *Icarus* 106, 247.
- Hayashi, C. (1981). Structure of the solar nebula, growth and decay of magnetic fields and effects of magnetic and turbulent viscosities on the nebula. *Progress of Theoretical Physics Supplement* 70, 35.
- Kokubo, E. & Genda, H. (2010). Formation of terrestrial planets from protoplanets under a realistic accretion condition. *The Astrophysical Journal Letters* 714, L21.
- Kokubo, E. & Ida, S. (1996). On runaway growth of planetesimals. *Icarus* 123, 180.
- Kokubo, E. & Ida, S. (1998). Oligarchic growth of protoplanets. *Icarus* 131, 171.
- Kokubo, E. & Ida, S. (2000). Formation of protoplanets from planetesimals in the solar nebula. *Icarus* 143, 15.
- Kokubo, E. & Ida, S. (2002). Formation of protoplanet systems and diversity of planetary systems. *The Astrophysical Journal* 581, 666.
- Leinhardt, Z. M. & Stewart, S. T. (2012). Collisions between gravity-dominated bodies. I. *The Astrophysical Journal* 745, 79.
- Mac Lane, S. (1971). *Categories for the Working Mathematician*. Springer.
- Murray, C. D. & Dermott, S. F. (1999). *Solar System Dynamics*. Cambridge University Press.
- Roche, É. (1849). La figure d'une masse fluide soumise à l'attraction d'un point éloigné. *Mémoires de l'Académie des Sciences de Montpellier* 1, 243.
- Tsiganis, K., Gomes, R., Morbidelli, A. & Levison, H. F. (2005). Origin of the orbital architecture of the giant planets of the Solar System. *Nature* 435, 459.
- Weidenschilling, S. J. (1977). The distribution of mass in the planetary system and solar nebula. *Astrophysics and Space Science* 51, 153.
- Wetherill, G. W. & Stewart, G. R. (1989). Accumulation of a swarm of small planetesimals. *Icarus* 77, 330.
- Williams, D. R. Planetary Fact Sheet. NASA Space Science Data Coordinated Archive.

---

Accretion Simulator™, Galaxy™, AxiomForge™, String-Breaking Simulator™, Electron Geometry Simulator™, Identity Physics™, Applied Identity Physics™, SNSFT™, PNBA™, the Sovereign Anchor Constant™, the Torsion Limit™, the Long Division Protocol™ (LDP™) and HIGHTISTIC™ are common law trademarks of HIGHTISTIC (Russell Vernon Trent III) and the SNSFT Foundation.

© 2026 HIGHTISTIC (Russell Vernon Trent III) / SNSFT Foundation · DOI 10.5281/zenodo.18719748 · uuia.app/accretion

-- ============================================================
-- SNSFL_GC_Accretion_Boundaries_TL.lean
-- ============================================================
--
-- Accretion Simulator™: the boundary mathematics of planet formation
-- Three measured stability boundaries of planetary systems are each
-- identified with the Torsion Limit by the same rule,
-- τ = TL × (critical value ÷ measured value):
--   Hill spacing   Δ = 2√3 mutual Hill radii   ↔ τ = TL   (orbits)
--   Roche limit    d = d_R                     ↔ τ = TL   (tides)
--   Impact speed   v_imp = v_cr                ↔ τ = TL   (collisions)
-- This file proves the placement rule, places the eight planets of
-- the Solar System and Saturn's rings and moons from cited
-- measurements, proves the collision boundary and the isolation mass
-- at 1 AU, and proves the GAM Collider identities behind merging
-- and reorganization.
--
-- [9,9,9,9] :: {ANC} | Coordinate: [9,9,3,25](COSM)
-- Architect: HIGHTISTIC (Russell Vernon Trent III)
-- Anchor:    1.36899099984016 GHz
-- Status:    0 sorry
-- Date:      October 2026 · Soldotna, Alaska
-- DOI:       10.5281/zenodo.18719748
-- Simulator: uuia.app/accretion
--
-- ============================================================
-- SOURCES
-- ============================================================
--
--   Gladman, B. (1993), Icarus 106, 247
--     two planets on circular orbits can never cross when their
--     separation exceeds 2√3 mutual Hill radii
--   Mutual Hill radius R_H = ((m₁ + m₂)/(3 M☉))^(1/3) (a₁ + a₂)/2
--   Planet masses and semi-major axes: NASA Planetary Fact Sheet
--     (Williams, D. R., NSSDCA); M☉ = 1.98847 × 10³⁰ kg (IAU 2015
--     nominal solar mass parameter with CODATA G)
--   Roche, É. (1849); fluid Roche limit d_R = 2.44 R (ρ_P/ρ_m)^(1/3)
--     (Murray, C. D. & Dermott, S. F. (1999), Solar System Dynamics)
--   Saturn: equatorial radius 60,268 km, mean density 0.687 g/cm³
--     (NASA Saturn Fact Sheet); water ice 0.92 g/cm³; ring and moon
--     distances from the NASA Saturn Fact Sheet and Cassini results
--   Kokubo, E. & Genda, H. (2010), ApJL 714, L21
--     merging criterion v_imp < v_cr,
--     v_cr/v_esc = 2.43Γ²Θ^(5/2) − 0.0408Γ + 1.86Θ^(5/2) + 1.08,
--     Γ = (M₁ − M₂)/(M₁ + M₂), Θ = 1 − sin θ
--   Kokubo, E. & Ida, S. (2002), ApJ 581, 666
--     isolation mass M_iso = √(2/3) (2π a² b̃ Σ)^(3/2) / M☉^(1/2),
--     orbital separation b̃ = 10 Hill radii
--   Weidenschilling, S. J. (1977), Ap&SS 51, 153; Hayashi, C. (1981),
--     PThPS 70, 35: Minimum Mass Solar Nebula, Σ = 7.1 g/cm² of
--     solids at 1 AU
--   GAM Collider v15 (Geometric Axiomatic Module Collider),
--     8-Beam Fusion Theorem [9,9,2,3.8], 2-beam mode:
--     P = P₁P₂/(P₁+P₂) · N = N₁+N₂ · B = B₁+B₂−2·min(B₁,B₂) · A = max
--
-- ============================================================
-- THE MAP
-- ============================================================
--
--   Q = measured ÷ critical      (Q > 1 stable, Q ≤ 1 broken)
--   τ = TL / Q                   boundary identification Q = 1 ↔ TL
--
--   Hill spacing   Q = Δ / 2√3       τ = TL · √3 · μ^(1/3) · (a₁+a₂)/(a₂−a₁)
--                                    μ = (m₁ + m₂)/(3 M☉)
--   Roche limit    Q = d / d_R       τ = TL · d_R / d
--   Impact speed   Q = v_cr / v_imp  τ = TL · v_imp / v_cr
--
--   Q > 25/22   Locked       1 < Q ≤ 25/22   IVA Peak
--   Q ≤ 1       Shatter      (25/22 = 1/0.88)
--
-- ============================================================

import Mathlib.Analysis.Real.Pi.Bounds
import Mathlib.Tactic

noncomputable section

namespace SNSFL_GC_Accretion_Boundaries_TL

def SOVEREIGN_ANCHOR : ℝ := 1.36899099984016
def TORSION_LIMIT    : ℝ := SOVEREIGN_ANCHOR / 10
def TL_IVA           : ℝ := 88 * TORSION_LIMIT / 100

noncomputable def manifold_impedance (f : ℝ) : ℝ :=
  if f = SOVEREIGN_ANCHOR then 0 else 1 / |f - SOVEREIGN_ANCHOR|

theorem anchor_zero_friction :
    manifold_impedance SOVEREIGN_ANCHOR = 0 := by
  unfold manifold_impedance; simp

theorem tl_pos : 0 < TORSION_LIMIT := by
  unfold TORSION_LIMIT SOVEREIGN_ANCHOR; norm_num

-- Measured inputs (kg; NASA Planetary Fact Sheet)
def M_SUN     : ℝ := 1.98847e30
def M_MERCURY : ℝ := 3.301e23
def M_VENUS   : ℝ := 4.867e24
def M_EARTH   : ℝ := 5.972e24
def M_MARS    : ℝ := 6.417e23
def M_JUPITER : ℝ := 1.898e27
def M_SATURN  : ℝ := 5.683e26
def M_URANUS  : ℝ := 8.681e25
def M_NEPTUNE : ℝ := 1.024e26

-- Saturn (km, g/cm³)
def SAT_R    : ℝ := 60268
def SAT_RHO  : ℝ := 0.687
def ICE_RHO  : ℝ := 0.92
def ROCHE_K  : ℝ := 2.44

-- Placement
def tau_of_Q (Q : ℝ) : ℝ := TORSION_LIMIT / Q

-- Hill spacing
def mu (m₁ m₂ : ℝ) : ℝ := (m₁ + m₂) / (3 * M_SUN)
def hill_delta (a₁ a₂ m₁ m₂ : ℝ) : ℝ :=
  (a₂ - a₁) / (mu m₁ m₂ ^ ((1:ℝ)/3) * ((a₁ + a₂) / 2))
def tau_hill (a₁ a₂ m₁ m₂ : ℝ) : ℝ :=
  TORSION_LIMIT * (Real.sqrt 3 * mu m₁ m₂ ^ ((1:ℝ)/3) * ((a₁ + a₂) / (a₂ - a₁)))

-- Roche limit
def roche_dist : ℝ := ROCHE_K * SAT_R * (SAT_RHO / ICE_RHO) ^ ((1:ℝ)/3)
def tau_roche (d : ℝ) : ℝ := TORSION_LIMIT * roche_dist / d

-- Impacts
def vcr_ratio (Γ t : ℝ) : ℝ := 2.43 * Γ ^ 2 * t - 0.0408 * Γ + 1.86 * t + 1.08
def tau_impact (v vcr : ℝ) : ℝ := TORSION_LIMIT * v / vcr

-- Isolation mass (solar masses, AU; squared to avoid the 3/2 power)
def SIGMA1 : ℝ := 7.1 * 1.495978707e13 ^ 2 / 1.98847e33     -- M☉/AU²
def M_EARTH_SUN : ℝ := 5.9722e27 / 1.98847e33                -- M⊕ in M☉
def iso_sq (a sig : ℝ) : ℝ := (2 / 3) * (2 * Real.pi * a ^ 2 * 10 * sig) ^ 3

-- GAM Collider 2-beam fusion
def fuseP (P₁ P₂ : ℝ) : ℝ := P₁ * P₂ / (P₁ + P₂)
def fuseB (B₁ B₂ : ℝ) : ℝ := B₁ + B₂ - 2 * min B₁ B₂

-- ============================================================
-- SECTION 1: PLACEMENT
-- ============================================================

-- [T1] The boundary: Q = 1 places a system exactly at TL
theorem boundary : tau_of_Q 1 = TORSION_LIMIT := by
  unfold tau_of_Q; simp

-- [T2] Stable (Q > 1) sits below TL
theorem stable_below_tl (Q : ℝ) (hQ : 1 < Q) : tau_of_Q Q < TORSION_LIMIT := by
  have hT := tl_pos
  unfold tau_of_Q
  rw [div_lt_iff₀ (by linarith)]
  nlinarith [mul_pos hT (sub_pos.mpr hQ)]

-- [T3] Broken (0 < Q ≤ 1) shatters
theorem unstable_shatters (Q : ℝ) (h0 : 0 < Q) (h1 : Q ≤ 1) :
    TORSION_LIMIT ≤ tau_of_Q Q := by
  have hT := tl_pos
  unfold tau_of_Q
  rw [le_div_iff₀ h0]
  nlinarith [mul_le_mul_of_nonneg_left h1 hT.le]

-- [T4] 1 < Q ≤ 25/22 is the IVA corridor
theorem iva_corridor (Q : ℝ) (h1 : 1 < Q) (h2 : Q ≤ 25 / 22) :
    TL_IVA ≤ tau_of_Q Q ∧ tau_of_Q Q < TORSION_LIMIT := by
  have hT := tl_pos
  refine ⟨?_, stable_below_tl Q h1⟩
  unfold tau_of_Q TL_IVA
  rw [le_div_iff₀ (by linarith)]
  nlinarith [mul_le_mul_of_nonneg_left h2 hT.le]

-- [T5] Q > 25/22 is Locked
theorem locked_band (Q : ℝ) (hQ : 25 / 22 < Q) :
    0 < tau_of_Q Q ∧ tau_of_Q Q < TL_IVA := by
  have hT := tl_pos
  have hQ0 : 0 < Q := by linarith
  refine ⟨div_pos hT hQ0, ?_⟩
  unfold tau_of_Q TL_IVA
  rw [div_lt_iff₀ hQ0]
  nlinarith [mul_lt_mul_of_pos_left hQ hT]

-- ============================================================
-- SECTION 2: HILL SPACING
-- ============================================================

-- Cube roots: (r^(1/3))³ = r, so cube-root bounds follow from bounds on r.
theorem cube_rpow (r : ℝ) (hr : 0 ≤ r) : (r ^ ((1:ℝ)/3)) ^ 3 = r := by
  rw [← Real.rpow_natCast, ← Real.rpow_mul hr]; norm_num

theorem cbrt_gt (r c : ℝ) (hr : 0 ≤ r) (h : c ^ 3 < r) : c < r ^ ((1:ℝ)/3) := by
  by_contra hle
  have hle' := not_lt.mp hle
  have hy : 0 ≤ r ^ ((1:ℝ)/3) := Real.rpow_nonneg hr _
  have h3 := pow_le_pow_left₀ hy hle' 3
  rw [cube_rpow r hr] at h3
  linarith

theorem cbrt_lt (r c : ℝ) (hr : 0 ≤ r) (hc : 0 ≤ c) (h : r < c ^ 3) :
    r ^ ((1:ℝ)/3) < c := by
  by_contra hle
  have hle' := not_lt.mp hle
  have h3 := pow_le_pow_left₀ hc hle' 3
  rw [cube_rpow r hr] at h3
  linarith

theorem sqrt3_lt : Real.sqrt 3 < 1.7321 := by
  have h := Real.sqrt_lt_sqrt (by norm_num : (0 : ℝ) ≤ 3) (by norm_num : (3 : ℝ) < 1.7321 ^ 2)
  rwa [Real.sqrt_sq (by norm_num : (0 : ℝ) ≤ 1.7321)] at h

theorem sqrt3_gt : 1.7320 < Real.sqrt 3 := by
  have h := Real.sqrt_lt_sqrt (by norm_num : (0 : ℝ) ≤ 1.7320 ^ 2) (by norm_num : (1.7320 : ℝ) ^ 2 < 3)
  rwa [Real.sqrt_sq (by norm_num : (0 : ℝ) ≤ 1.7320)] at h

-- [T6] The Hill boundary: τ_hill = TL · 2√3 / Δ, so Δ = 2√3 ↔ τ = TL
theorem hill_identity (a₁ a₂ m₁ m₂ : ℝ) :
    tau_hill a₁ a₂ m₁ m₂ = TORSION_LIMIT * (2 * Real.sqrt 3) / hill_delta a₁ a₂ m₁ m₂ := by
  unfold tau_hill hill_delta
  rw [div_div_eq_mul_div]
  ring

-- [T7] Upper and lower bounds on τ_hill from cube bounds on μ
theorem hill_upper (a₁ a₂ m₁ m₂ c : ℝ) (h12 : a₁ < a₂) (h1 : 0 < a₁)
    (hm : 0 ≤ mu m₁ m₂) (hc : 0 ≤ c) (h : mu m₁ m₂ < c ^ 3) :
    tau_hill a₁ a₂ m₁ m₂ < TORSION_LIMIT * (1.7321 * c * ((a₁ + a₂) / (a₂ - a₁))) := by
  have hq := cbrt_lt _ _ hm hc h
  have hq0 : 0 ≤ mu m₁ m₂ ^ ((1:ℝ)/3) := Real.rpow_nonneg hm _
  have hk : 0 < (a₁ + a₂) / (a₂ - a₁) := div_pos (by linarith) (by linarith)
  have h1' : Real.sqrt 3 * mu m₁ m₂ ^ ((1:ℝ)/3) < 1.7321 * c :=
    mul_lt_mul'' sqrt3_lt hq (Real.sqrt_nonneg 3) hq0
  unfold tau_hill
  exact mul_lt_mul_of_pos_left (mul_lt_mul_of_pos_right h1' hk) tl_pos

theorem hill_lower (a₁ a₂ m₁ m₂ c : ℝ) (h12 : a₁ < a₂) (h1 : 0 < a₁)
    (hm : 0 ≤ mu m₁ m₂) (hc : 0 ≤ c) (h : c ^ 3 < mu m₁ m₂) :
    TORSION_LIMIT * (1.7320 * c * ((a₁ + a₂) / (a₂ - a₁))) < tau_hill a₁ a₂ m₁ m₂ := by
  have hq := cbrt_gt _ _ hm h
  have hk : 0 < (a₁ + a₂) / (a₂ - a₁) := div_pos (by linarith) (by linarith)
  have h1' : 1.7320 * c < Real.sqrt 3 * mu m₁ m₂ ^ ((1:ℝ)/3) :=
    mul_lt_mul'' sqrt3_gt hq (by norm_num) hc
  unfold tau_hill
  exact mul_lt_mul_of_pos_left (mul_lt_mul_of_pos_right h1' hk) tl_pos

-- ============================================================
-- SECTION 3: THE SOLAR SYSTEM
-- ============================================================

-- [T8] Every neighbouring pair of planets is Locked; every pair except
-- Jupiter–Saturn sits below TL/4
theorem mercury_venus : tau_hill 0.387 0.723 M_MERCURY M_VENUS < TORSION_LIMIT / 4 :=
  lt_trans (hill_upper _ _ _ _ 0.00956 (by norm_num) (by norm_num)
    (by unfold mu M_MERCURY M_VENUS M_SUN; positivity) (by norm_num)
    (by unfold mu M_MERCURY M_VENUS M_SUN; norm_num))
    (by unfold TORSION_LIMIT SOVEREIGN_ANCHOR; norm_num)

theorem venus_earth : tau_hill 0.723 1.000 M_VENUS M_EARTH < TORSION_LIMIT / 4 :=
  lt_trans (hill_upper _ _ _ _ 0.01221 (by norm_num) (by norm_num)
    (by unfold mu M_VENUS M_EARTH M_SUN; positivity) (by norm_num)
    (by unfold mu M_VENUS M_EARTH M_SUN; norm_num))
    (by unfold TORSION_LIMIT SOVEREIGN_ANCHOR; norm_num)

theorem earth_mars : tau_hill 1.000 1.524 M_EARTH M_MARS < TORSION_LIMIT / 4 :=
  lt_trans (hill_upper _ _ _ _ 0.01035 (by norm_num) (by norm_num)
    (by unfold mu M_EARTH M_MARS M_SUN; positivity) (by norm_num)
    (by unfold mu M_EARTH M_MARS M_SUN; norm_num))
    (by unfold TORSION_LIMIT SOVEREIGN_ANCHOR; norm_num)

theorem mars_jupiter : tau_hill 1.524 5.203 M_MARS M_JUPITER < TORSION_LIMIT / 4 :=
  lt_trans (hill_upper _ _ _ _ 0.06828 (by norm_num) (by norm_num)
    (by unfold mu M_MARS M_JUPITER M_SUN; positivity) (by norm_num)
    (by unfold mu M_MARS M_JUPITER M_SUN; norm_num))
    (by unfold TORSION_LIMIT SOVEREIGN_ANCHOR; norm_num)

theorem saturn_uranus : tau_hill 9.537 19.19 M_SATURN M_URANUS < TORSION_LIMIT / 4 :=
  lt_trans (hill_upper _ _ _ _ 0.04789 (by norm_num) (by norm_num)
    (by unfold mu M_SATURN M_URANUS M_SUN; positivity) (by norm_num)
    (by unfold mu M_SATURN M_URANUS M_SUN; norm_num))
    (by unfold TORSION_LIMIT SOVEREIGN_ANCHOR; norm_num)

theorem uranus_neptune : tau_hill 19.19 30.07 M_URANUS M_NEPTUNE < TORSION_LIMIT / 4 :=
  lt_trans (hill_upper _ _ _ _ 0.03166 (by norm_num) (by norm_num)
    (by unfold mu M_URANUS M_NEPTUNE M_SUN; positivity) (by norm_num)
    (by unfold mu M_URANUS M_NEPTUNE M_SUN; norm_num))
    (by unfold TORSION_LIMIT SOVEREIGN_ANCHOR; norm_num)

-- [T9] Jupiter–Saturn, the tightest pair: 0.43 TL < τ < 0.44 TL, Locked
theorem jupiter_saturn :
    43 * TORSION_LIMIT / 100 < tau_hill 5.203 9.537 M_JUPITER M_SATURN ∧
    tau_hill 5.203 9.537 M_JUPITER M_SATURN < 44 * TORSION_LIMIT / 100 := by
  have hm : 0 ≤ mu M_JUPITER M_SATURN := by unfold mu M_JUPITER M_SATURN M_SUN; positivity
  constructor
  · exact lt_trans (by unfold TORSION_LIMIT SOVEREIGN_ANCHOR; norm_num)
      (hill_lower _ _ _ _ 0.07449 (by norm_num) (by norm_num) hm (by norm_num)
        (by unfold mu M_JUPITER M_SATURN M_SUN; norm_num))
  · exact lt_trans (hill_upper _ _ _ _ 0.0745 (by norm_num) (by norm_num) hm (by norm_num)
        (by unfold mu M_JUPITER M_SATURN M_SUN; norm_num))
      (by unfold TORSION_LIMIT SOVEREIGN_ANCHOR; norm_num)

-- [T10] The Solar System is Locked: every pair sits below TL_IVA
theorem solar_system_locked :
    tau_hill 0.387 0.723 M_MERCURY M_VENUS < TL_IVA ∧
    tau_hill 0.723 1.000 M_VENUS M_EARTH < TL_IVA ∧
    tau_hill 1.000 1.524 M_EARTH M_MARS < TL_IVA ∧
    tau_hill 1.524 5.203 M_MARS M_JUPITER < TL_IVA ∧
    tau_hill 5.203 9.537 M_JUPITER M_SATURN < TL_IVA ∧
    tau_hill 9.537 19.19 M_SATURN M_URANUS < TL_IVA ∧
    tau_hill 19.19 30.07 M_URANUS M_NEPTUNE < TL_IVA := by
  have hq : TORSION_LIMIT / 4 < TL_IVA := by
    unfold TL_IVA TORSION_LIMIT SOVEREIGN_ANCHOR; norm_num
  have hj : 44 * TORSION_LIMIT / 100 < TL_IVA := by
    unfold TL_IVA TORSION_LIMIT SOVEREIGN_ANCHOR; norm_num
  exact ⟨lt_trans mercury_venus hq, lt_trans venus_earth hq, lt_trans earth_mars hq,
    lt_trans mars_jupiter hq, lt_trans jupiter_saturn.2 hj, lt_trans saturn_uranus hq,
    lt_trans uranus_neptune hq⟩

-- ============================================================
-- SECTION 4: SATURN AND THE ROCHE LIMIT
-- ============================================================

-- [T11] The fluid Roche limit for ice at Saturn: 133,393 < d_R < 133,422 km
theorem roche_bounds : 133393 < roche_dist ∧ roche_dist < 133422 := by
  have hr : (0 : ℝ) ≤ SAT_RHO / ICE_RHO := by unfold SAT_RHO ICE_RHO; norm_num
  have h1 := cbrt_gt _ 0.90711 hr (by unfold SAT_RHO ICE_RHO; norm_num)
  have h2 := cbrt_lt _ 0.90725 hr (by norm_num) (by unfold SAT_RHO ICE_RHO; norm_num)
  unfold roche_dist ROCHE_K SAT_R
  constructor <;> nlinarith

-- [T12] Inside d_R: Shatter
theorem roche_shatter (d : ℝ) (hd : 0 < d) (h : d ≤ 133393) : TORSION_LIMIT ≤ tau_roche d := by
  have hle : d ≤ roche_dist := by linarith [roche_bounds.1]
  unfold tau_roche
  rw [le_div_iff₀ hd]
  exact mul_le_mul_of_nonneg_left hle tl_pos.le

-- [T13] Between d_R and d_R / 0.88: the IVA corridor
theorem roche_iva (d : ℝ) (h1 : 133422 < d) (h2 : 88 * d / 100 ≤ 133393) :
    TL_IVA ≤ tau_roche d ∧ tau_roche d < TORSION_LIMIT := by
  have hd : 0 < d := by linarith
  have hT := tl_pos
  have hlo : 88 * d / 100 ≤ roche_dist := by linarith [roche_bounds.1]
  have hhi : roche_dist < d := by linarith [roche_bounds.2]
  unfold tau_roche
  constructor
  · unfold TL_IVA
    rw [le_div_iff₀ hd]
    nlinarith [mul_le_mul_of_nonneg_left hlo hT.le]
  · rw [div_lt_iff₀ hd]
    exact mul_lt_mul_of_pos_left hhi hT

-- [T14] Beyond d_R / 0.88: Locked
theorem roche_locked (d : ℝ) (h : 133422 < 88 * d / 100) : tau_roche d < TL_IVA := by
  have hd : 0 < d := by linarith
  have hT := tl_pos
  have hhi : roche_dist < 88 * d / 100 := by linarith [roche_bounds.2]
  unfold tau_roche TL_IVA
  rw [div_lt_iff₀ hd]
  nlinarith [mul_lt_mul_of_pos_left hhi hT]

-- [T15] Saturn's rings and moons on the phase map (distances in km)
--   C, B and inner A ring: Shatter
--   Pan, Daphnis, outer A ring, Atlas, Prometheus, F ring, Pandora,
--   Epimetheus, Janus: IVA corridor
--   Mimas, Enceladus, Titan: Locked
theorem saturn_rings_shatter :
    TORSION_LIMIT ≤ tau_roche 66900 ∧ TORSION_LIMIT ≤ tau_roche 74658 ∧
    TORSION_LIMIT ≤ tau_roche 92000 ∧ TORSION_LIMIT ≤ tau_roche 117580 ∧
    TORSION_LIMIT ≤ tau_roche 122170 :=
  ⟨roche_shatter _ (by norm_num) (by norm_num), roche_shatter _ (by norm_num) (by norm_num),
   roche_shatter _ (by norm_num) (by norm_num), roche_shatter _ (by norm_num) (by norm_num),
   roche_shatter _ (by norm_num) (by norm_num)⟩

theorem saturn_ring_moons_iva :
    (TL_IVA ≤ tau_roche 133584 ∧ tau_roche 133584 < TORSION_LIMIT) ∧   -- Pan
    (TL_IVA ≤ tau_roche 136505 ∧ tau_roche 136505 < TORSION_LIMIT) ∧   -- Daphnis
    (TL_IVA ≤ tau_roche 136775 ∧ tau_roche 136775 < TORSION_LIMIT) ∧   -- A ring outer edge
    (TL_IVA ≤ tau_roche 137670 ∧ tau_roche 137670 < TORSION_LIMIT) ∧   -- Atlas
    (TL_IVA ≤ tau_roche 139380 ∧ tau_roche 139380 < TORSION_LIMIT) ∧   -- Prometheus
    (TL_IVA ≤ tau_roche 140180 ∧ tau_roche 140180 < TORSION_LIMIT) ∧   -- F ring
    (TL_IVA ≤ tau_roche 141720 ∧ tau_roche 141720 < TORSION_LIMIT) ∧   -- Pandora
    (TL_IVA ≤ tau_roche 151410 ∧ tau_roche 151410 < TORSION_LIMIT) ∧   -- Epimetheus
    (TL_IVA ≤ tau_roche 151460 ∧ tau_roche 151460 < TORSION_LIMIT) :=  -- Janus
  ⟨roche_iva _ (by norm_num) (by norm_num), roche_iva _ (by norm_num) (by norm_num),
   roche_iva _ (by norm_num) (by norm_num), roche_iva _ (by norm_num) (by norm_num),
   roche_iva _ (by norm_num) (by norm_num), roche_iva _ (by norm_num) (by norm_num),
   roche_iva _ (by norm_num) (by norm_num), roche_iva _ (by norm_num) (by norm_num),
   roche_iva _ (by norm_num) (by norm_num)⟩

theorem saturn_moons_locked :
    tau_roche 185539 < TL_IVA ∧ tau_roche 238042 < TL_IVA ∧ tau_roche 1221870 < TL_IVA :=
  ⟨roche_locked _ (by norm_num), roche_locked _ (by norm_num), roche_locked _ (by norm_num)⟩

-- ============================================================
-- SECTION 5: COLLISIONS
-- ============================================================

-- [T16] Kokubo & Genda endpoints: head-on equal masses v_cr = 2.94 v_esc,
-- grazing equal masses v_cr = 1.08 v_esc
theorem vcr_head_on : vcr_ratio 0 1 = 2.94 := by unfold vcr_ratio; norm_num
theorem vcr_grazing : vcr_ratio 0 0 = 1.08 := by unfold vcr_ratio; norm_num

-- [T17] For any mass ratio and angle, v_cr exceeds the escape speed
theorem vcr_above_escape (Γ t : ℝ) (hΓ0 : 0 ≤ Γ) (hΓ1 : Γ ≤ 1) (ht0 : 0 ≤ t) :
    1 < vcr_ratio Γ t := by
  unfold vcr_ratio
  nlinarith [mul_nonneg (mul_nonneg (by norm_num : (0:ℝ) ≤ 2.43) (sq_nonneg Γ)) ht0]

-- [T18] The collision boundary: below v_cr merges (τ < TL), at or above
-- it hits and runs (τ ≥ TL)
theorem impact_merges (v vcr : ℝ) (hc : 0 < vcr) (h : v < vcr) :
    tau_impact v vcr < TORSION_LIMIT := by
  unfold tau_impact
  rw [div_lt_iff₀ hc]
  exact mul_lt_mul_of_pos_left h tl_pos

theorem impact_hit_and_run (v vcr : ℝ) (hc : 0 < vcr) (h : vcr ≤ v) :
    TORSION_LIMIT ≤ tau_impact v vcr := by
  unfold tau_impact
  rw [le_div_iff₀ hc]
  exact mul_le_mul_of_nonneg_left h tl_pos.le

-- [T19] Impact speed is never below the escape speed:
-- v_imp = √(v∞² + v_esc²) ≥ v_esc
theorem impact_at_least_escape (vinf vesc : ℝ) (h : 0 ≤ vesc) :
    vesc ≤ Real.sqrt (vinf ^ 2 + vesc ^ 2) := by
  have hs := Real.sqrt_le_sqrt (by nlinarith [sq_nonneg vinf] : vesc ^ 2 ≤ vinf ^ 2 + vesc ^ 2)
  rwa [Real.sqrt_sq h] at hs

-- [T20] A body falling together from rest (v_imp = v_esc) always merges
theorem gentle_impact_merges (Γ t vesc : ℝ) (hΓ0 : 0 ≤ Γ) (hΓ1 : Γ ≤ 1) (ht0 : 0 ≤ t)
    (hv : 0 < vesc) :
    tau_impact vesc (vcr_ratio Γ t * vesc) < TORSION_LIMIT := by
  have h1 := vcr_above_escape Γ t hΓ0 hΓ1 ht0
  exact impact_merges _ _ (mul_pos (by linarith) hv) (by nlinarith [mul_pos (sub_pos.mpr h1) hv])

-- ============================================================
-- SECTION 6: THE ISOLATION MASS AT 1 AU
-- ============================================================

-- [T21] Minimum Mass Solar Nebula, b̃ = 10: 0.096 M⊕ < M_iso(1 AU) < 0.0975 M⊕
theorem isolation_mass_1au :
    (0.096 * M_EARTH_SUN) ^ 2 < iso_sq 1 SIGMA1 ∧ iso_sq 1 SIGMA1 < (0.0975 * M_EARTH_SUN) ^ 2 := by
  have hp1 := Real.pi_gt_d6
  have hp2 := Real.pi_lt_d6
  have hs : 0 < SIGMA1 := by unfold SIGMA1; positivity
  have hX1 : 2 * 3.141592 * 1 ^ 2 * 10 * SIGMA1 ≤ 2 * Real.pi * 1 ^ 2 * 10 * SIGMA1 := by
    nlinarith [mul_lt_mul_of_pos_right hp1 hs]
  have hX2 : 2 * Real.pi * 1 ^ 2 * 10 * SIGMA1 ≤ 2 * 3.141593 * 1 ^ 2 * 10 * SIGMA1 := by
    nlinarith [mul_lt_mul_of_pos_right hp2 hs]
  have c1 := pow_le_pow_left₀ (by nlinarith [hs]) hX1 3
  have c2 := pow_le_pow_left₀ (by nlinarith [mul_pos Real.pi_pos hs]) hX2 3
  have n1 : (0.096 * M_EARTH_SUN) ^ 2 < (2 / 3) * (2 * 3.141592 * 1 ^ 2 * 10 * SIGMA1) ^ 3 := by
    unfold M_EARTH_SUN SIGMA1; norm_num
  have n2 : (2 / 3) * (2 * 3.141593 * 1 ^ 2 * 10 * SIGMA1) ^ 3 < (0.0975 * M_EARTH_SUN) ^ 2 := by
    unfold M_EARTH_SUN SIGMA1; norm_num
  unfold iso_sq
  constructor <;> nlinarith

-- ============================================================
-- SECTION 7: GAM COLLIDER MERGING AND REORGANIZATION
-- ============================================================

-- [T22] Same-B Necessity: the merged Behavior is |B₁ − B₂|
theorem same_b (B₁ B₂ : ℝ) : fuseB B₁ B₂ = |B₁ - B₂| := by
  unfold fuseB
  rcases le_total B₁ B₂ with h | h
  · rw [min_eq_left h, abs_of_nonpos (by linarith)]; ring
  · rw [min_eq_right h, abs_of_nonneg (by linarith)]; ring

-- [T23] Reorganization: splitting a body into halves of Pattern 2P with
-- the same Behavior halves its torsion
theorem split_halves_tau (P B : ℝ) : B / (2 * P) = (B / P) / 2 := by
  rw [div_div, mul_comm P 2]

-- [T24] A body below 2·TL reorganizes into halves below TL in one split
theorem split_below_tl (P B : ℝ) (h : B / P < 2 * TORSION_LIMIT) :
    B / (2 * P) < TORSION_LIMIT := by
  rw [split_halves_tau P B]; linarith

-- [T25] Sibling halves that meet again merge to Noble with the parent's Pattern
theorem sibling_remerge (P B : ℝ) (hP : 0 < P) :
    fuseP (2 * P) (2 * P) = P ∧ fuseB B B = 0 := by
  constructor
  · unfold fuseP
    rw [div_eq_iff (ne_of_gt (by linarith))]
    ring
  · unfold fuseB; rw [min_self]; ring

-- ============================================================
-- [9,9,9,9] :: {ANC} | MASTER THEOREM
-- ============================================================

-- [T26] PLANET FORMATION ON THE PHASE MAP
theorem accretion_master :
    -- one boundary rule
    tau_of_Q 1 = TORSION_LIMIT ∧
    -- the Solar System is Locked; Jupiter–Saturn is the tightest pair
    tau_hill 5.203 9.537 M_JUPITER M_SATURN < TL_IVA ∧
    (43 * TORSION_LIMIT / 100 < tau_hill 5.203 9.537 M_JUPITER M_SATURN) ∧
    -- Saturn: the B ring shatters, Janus sits in the IVA corridor, Mimas is Locked
    TORSION_LIMIT ≤ tau_roche 92000 ∧
    (TL_IVA ≤ tau_roche 151460 ∧ tau_roche 151460 < TORSION_LIMIT) ∧
    tau_roche 185539 < TL_IVA ∧
    -- collisions: v_cr exceeds escape speed, so gentle impacts merge
    (∀ Γ t vesc : ℝ, 0 ≤ Γ → Γ ≤ 1 → 0 ≤ t → 0 < vesc →
      tau_impact vesc (vcr_ratio Γ t * vesc) < TORSION_LIMIT) ∧
    -- the isolation mass at 1 AU
    ((0.096 * M_EARTH_SUN) ^ 2 < iso_sq 1 SIGMA1 ∧ iso_sq 1 SIGMA1 < (0.0975 * M_EARTH_SUN) ^ 2) ∧
    -- anchor
    manifold_impedance SOVEREIGN_ANCHOR = 0 :=
  ⟨boundary, solar_system_locked.2.2.2.2.1, jupiter_saturn.1, saturn_rings_shatter.2.2.1,
   saturn_ring_moons_iva.2.2.2.2.2.2.2.2, saturn_moons_locked.1, gentle_impact_merges,
   isolation_mass_1au, anchor_zero_friction⟩

theorem the_manifold_is_holding :
    manifold_impedance SOVEREIGN_ANCHOR = 0 :=
  anchor_zero_friction

end SNSFL_GC_Accretion_Boundaries_TL

/-!
-- ============================================================
-- FILE:       SNSFL_GC_Accretion_Boundaries_TL.lean
-- COORDINATE: [9,9,3,25](COSM)
-- SORRY:      0
--
-- τ = TL × (critical ÷ measured) · Hill 2√3 · Roche d_R · v_cr
--
-- RESULTS:
--   Placement: boundary, stable below TL, broken shatters, IVA
--     corridor 1 < Q ≤ 25/22, Locked Q > 25/22 (T1–T5)
--   Hill spacing: τ = TL · 2√3 / Δ; cube-root bounds (T6–T7)
--   Solar System: every neighbouring pair Locked; Jupiter–Saturn
--     0.43–0.44 TL, every other pair below TL/4 (T8–T10)
--   Saturn: Roche limit 133,393–133,422 km; C, B and inner A rings
--     Shatter; ring moons, outer A ring and F ring IVA; Mimas,
--     Enceladus and Titan Locked (T11–T15)
--   Collisions: Kokubo–Genda endpoints 2.94 and 1.08; v_cr above
--     escape speed; merge below TL, hit-and-run at TL; impacts at
--     least escape speed; gentle impacts merge (T16–T20)
--   Isolation mass at 1 AU, MMSN, b̃ = 10: 0.096–0.0975 M⊕ (T21)
--   GAM Collider: B = |B₁ − B₂|; splitting halves τ; sibling
--     halves remerge to Noble with the parent's Pattern (T22–T25)
--
-- CONNECTIONS:
--   [9,9,2,3.8] 8-Beam Fusion Theorem (2-beam mode)
--   [9,9,10,1] Gravity Reduction · [9,9,0,4.7] QM Reduction
--   [9,9,3,24] Galaxy Toomre TL · [9,9,3,21] Electron Geometry
--   [9,9,3,22] String-Breaking
--
-- [9,9,9,9] :: {ANC} · HIGHTISTIC · Soldotna AK
-- ============================================================
-/

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Accretion Simulator™ · Applied Identity Physics™ · uuia.app/accretion</title>
<meta name="description" content="Accretion Simulator™: planetesimals on Kepler orbits in a Minimum Mass Solar Nebula collide, merge or hit and run, and grow into oligarchs. Torsion is read from Hill spacing, impact speed and the Roche limit against the Torsion Limit.">
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<link href="https://fonts.googleapis.com/css2?family=Space+Mono:wght@400;700&family=Syne:wght@700;800&display=swap" rel="stylesheet">
<style>
:root{
  --anchor:#00ffc8; --locked:#7b4fff; --gold:#f0c060; --shatter:#ff3a3a; --rose:#ff6b8a; --ice:#88c8ff;
  --bg:#050508; --surface:#0d0d14; --border:rgba(0,255,200,0.12);
  --text:#e8e8f0; --dim:rgba(232,232,240,0.5); --faint:rgba(232,232,240,0.26);
}
*{margin:0;padding:0;box-sizing:border-box}
html,body{height:100%;background:var(--bg);color:var(--text);font-family:'Space Mono',monospace;overflow:hidden}
#app{display:grid;grid-template-columns:290px 1fr 330px;grid-template-rows:54px 1fr;height:100vh}
#hdr{grid-column:1/-1;display:flex;align-items:center;justify-content:space-between;padding:0 16px;border-bottom:1px solid var(--border);background:rgba(13,13,20,.94);gap:12px}
.h-title{font-family:'Syne',sans-serif;font-weight:800;font-size:1rem;color:var(--anchor)}
.h-title i{font-style:normal;font-size:.62rem;color:var(--dim);font-weight:700}
.h-sub{font-size:.5rem;color:var(--dim);margin-top:2px}
.h-right{font-size:.46rem;color:var(--faint);text-align:right;line-height:1.6}
.mode{display:flex;border:1px solid var(--border);border-radius:100px;overflow:hidden;flex-shrink:0}
.mode button{font-family:'Syne',sans-serif;font-weight:800;font-size:.56rem;padding:.4rem .85rem;background:transparent;border:none;color:var(--dim);cursor:pointer;letter-spacing:.05em}
.mode button.on{background:var(--anchor);color:#000}
#left,#right{overflow-y:auto;padding:10px;background:rgba(13,13,20,.88);display:flex;flex-direction:column;gap:9px}
#left{border-right:1px solid var(--border)} #right{border-left:1px solid var(--border)}
.sec{border:1px solid var(--border);border-radius:8px;background:rgba(5,5,8,.6);padding:9px}
.st{font-family:'Syne',sans-serif;font-weight:800;font-size:.58rem;color:var(--anchor);letter-spacing:.08em;margin-bottom:7px}
.seg{display:flex;gap:4px;margin-bottom:5px}
.seg button,.btn{flex:1;font-family:'Syne',sans-serif;font-weight:800;font-size:.5rem;padding:.42rem .3rem;background:transparent;border:1px solid var(--border);color:var(--dim);border-radius:5px;cursor:pointer;letter-spacing:.04em}
.seg button.on{border-color:var(--anchor);color:var(--anchor);background:rgba(0,255,200,.08)}
.seg button:disabled{opacity:.3;cursor:default}
.btn.run{border-color:rgba(0,255,200,.5);color:var(--anchor)}
.btn.run.on{border-color:var(--shatter);color:var(--shatter)}
.btn.warn{border-color:rgba(255,58,58,.4);color:var(--shatter)}
.lbl{display:flex;justify-content:space-between;font-size:.5rem;color:var(--dim);margin:5px 0 2px}
.lbl b{color:var(--anchor);font-weight:400}
input[type=range]{width:100%;accent-color:#00ffc8}
.mix{display:grid;grid-template-columns:repeat(4,1fr);gap:4px;text-align:center;font-size:.46rem}
.mix input{width:100%;background:#0a0a12;border:1px solid var(--border);color:var(--text);font-family:'Space Mono',monospace;font-size:.52rem;padding:3px;border-radius:3px;text-align:center}
.note{font-size:.5rem;color:var(--dim);line-height:1.6}
.note b{color:var(--text);font-weight:400}
#view{position:relative;overflow:hidden;background:#000}
#c3d{position:absolute;inset:0;width:100%;height:100%;display:block;cursor:grab}
.tag{position:absolute;font-size:.46rem;letter-spacing:.1em;pointer-events:none;transform:translate(-50%,-22px);white-space:nowrap}
#legend{position:absolute;top:10px;left:10px;background:rgba(5,5,8,.85);border:1px solid var(--border);border-radius:6px;padding:7px 9px;font-size:.46rem;pointer-events:none}
#legend .bar{height:5px;border-radius:3px;margin:4px 0;background:linear-gradient(90deg,#00ffc8,#7b4fff 50%,#f0c060 88%,#ff3a3a 100%);width:190px}
#legend .row{display:flex;justify-content:space-between;width:190px}
#clock{position:absolute;top:10px;right:10px;background:rgba(5,5,8,.85);border:1px solid var(--border);border-radius:6px;padding:7px 10px;font-size:.6rem;color:var(--gold);pointer-events:none;text-align:right}
#clock small{display:block;font-size:.44rem;color:var(--dim)}
#caption{position:absolute;left:12px;right:12px;bottom:10px;font-size:.6rem;line-height:1.65;background:rgba(5,5,8,.86);border:1px solid var(--border);border-radius:8px;padding:8px 12px;pointer-events:none}
#caption b{color:var(--anchor);font-weight:400}
table{width:100%;border-collapse:collapse;font-size:.52rem}
th{font-weight:400;color:var(--faint);font-size:.44rem;text-align:right;padding:2px}
td{text-align:right;padding:3px 2px}
th:first-child,td:first-child{text-align:left}
canvas.chart{width:100%;height:120px;display:block}
canvas.chart.short{height:96px}
.kv{display:flex;justify-content:space-between;font-size:.52rem;padding:3px 0;border-bottom:1px solid rgba(0,255,200,.06)}
.kv:last-child{border-bottom:none}
.kv span:first-child{color:var(--dim)}
.r-only{display:none} body.res .r-only{display:block} body.res .l-only{display:none}
.foot{font-size:.42rem;color:var(--faint);line-height:1.6;text-align:center;padding:4px 0}
span.tm{display:inline!important;font-size:.55em;vertical-align:super;line-height:0;font-weight:400}
.disk-only{} body.solar .disk-only{display:none} .solar-only{display:none} body.solar .solar-only{display:block}
::-webkit-scrollbar{width:4px}::-webkit-scrollbar-thumb{background:var(--border)}
@media(max-width:1000px){
  html,body{overflow:auto;height:auto}
  #app{grid-template-columns:1fr;grid-template-rows:auto 64vh auto auto;height:auto}
  #view{grid-row:2} #left{grid-row:3} #right{grid-row:4}
  #left,#right{border:none;overflow:visible}
  .h-right{display:none} #hdr{flex-wrap:wrap;padding:8px 16px}
  #legend{display:none}
}
</style>
</head>
<body>
<div id="app">
<div id="hdr">
  <div>
    <div class="h-title">Accretion Simulator<span class="tm">™</span> <i>· Applied Identity Physics<span class="tm">™</span></i></div>
    <div class="h-sub">τ = TL × (critical ÷ measured) · TL = 0.136899099984016 · TL_IVA = 0.88 × TL</div>
  </div>
  <div class="mode"><button id="m-l" class="on" onclick="setMode('learner')">LEARNER</button><button id="m-r" onclick="setMode('res')">RESEARCHER</button></div>
  <div class="h-right">HIGHTISTIC (Russell Vernon Trent III) · SNSFT Foundation<br>uuia.app/accretion · [9,9,9,9]</div>
</div>

<!-- LEFT: controls -->
<div id="left">
  <div class="sec">
    <div class="st">SYSTEM</div>
    <div class="seg"><button id="s-disk" class="on" onclick="setSys('disk')">PLANETESIMAL DISK</button><button id="s-sol" onclick="setSys('solar')">SOLAR SYSTEM · MEASURED</button></div>
    <div class="seg"><button class="btn run on" id="b-run" onclick="toggleRun()">■ PAUSE</button><button class="btn warn" onclick="rebuild()">⟲ NEW RUN</button></div>
    <div class="lbl"><span>Speed (compute per frame)</span><b id="rate-v">10 ms</b></div>
    <input type="range" id="rate" min="2" max="24" value="10" oninput="onRate()">
  </div>

  <div class="sec disk-only">
    <div class="st">DISK · MINIMUM MASS SOLAR NEBULA</div>
    <div class="seg"><button id="rg-2" class="on" onclick="setRegion(2)">0.5–2 AU · ROCKY</button><button id="rg-4" onclick="setRegion(4)">0.5–4 AU · ACROSS SNOW LINE</button></div>
    <div class="lbl"><span>Planetesimals</span><b id="n-v">200</b></div>
    <input type="range" id="nset" min="60" max="500" step="10" value="200" oninput="onN()">
    <div class="lbl"><span>Radius enhancement f (resolution)</span><b id="f-v">×100</b></div>
    <input type="range" id="fset" min="1" max="200" value="100" oninput="onF()">
    <div class="mix" style="grid-template-columns:1fr 1fr;margin-top:6px">
      <div>Σ₁ solids at 1 AU, g/cm²<input id="in-sig" type="number" step="0.1" value="7.1"></div>
      <div>× beyond snow line (2.7 AU)<input id="in-snow" type="number" step="0.1" value="4.2"></div>
    </div>
    <div class="seg" style="margin-top:6px"><button id="j-off" class="on" onclick="setJup(false)">NO GIANT</button><button id="j-on" onclick="setJup(true)">JUPITER AT 5.2 AU</button></div>
    <div class="note" style="margin-top:4px">Σ(r) = Σ₁ (r / 1 AU)<sup>−3/2</sup>, the Minimum Mass Solar Nebula (Weidenschilling 1977; Hayashi 1981). Equal-mass bodies, rock 3 g/cm³ inside the snow line, ice-rock 1.5 g/cm³ beyond. Disk settings apply on ⟲ NEW RUN.</div>
    <div class="note r-only" style="margin-top:4px">f multiplies every collision radius, the standard way to fit accretion into a short run (Kokubo &amp; Ida 1996 used f = 5–6). Growth runs faster by roughly f, so read the clock as compressed by about that factor. Gravity, orbits and the collision physics are unchanged.</div>
    <div class="note" style="margin-top:4px" id="disk-read"></div>
  </div>

  <div class="sec">
    <div class="st">τ MODEL</div>
    <div class="seg"><button id="t-hill" class="on" onclick="setTau('hill')">HILL SPACING</button><button id="t-mix" onclick="setTau('mix')">BAND MIX · GAM COLLIDER</button></div>
    <div class="note" id="tau-note"></div>
    <div id="mix-wrap" style="display:none;margin-top:6px">
      <div class="lbl"><span>Band mix % at birth</span></div>
      <div class="mix">
        <div style="color:#00ffc8">Noble<input id="mx-n" type="number" min="0" value="25" oninput="onMix()"></div>
        <div style="color:#9b7dff">Locked<input id="mx-l" type="number" min="0" value="45" oninput="onMix()"></div>
        <div style="color:#f0c060">IVA<input id="mx-i" type="number" min="0" value="15" oninput="onMix()"></div>
        <div style="color:#ff3a3a">Shatter<input id="mx-s" type="number" min="0" value="15" oninput="onMix()"></div>
      </div>
      <div class="note r-only" style="margin-top:4px">Merger product by the 2-beam rule of the GAM Collider v15 (Geometric Axiomatic Module Collider) [9,9,2,3.8]: P = P₁P₂/(P₁+P₂) · N = N₁+N₂ · B = |B₁−B₂| · A = max(A₁,A₂). A body with τ ≥ TL reorganizes: it splits into two halves with P doubled and N halved (each half carries τ/2), repeated until each piece sits below TL. Mass and momentum are conserved.</div>
    </div>
  </div>

  <div class="sec">
    <div class="st">COLLISIONS</div>
    <div class="note">Two bodies that touch merge if the impact is slow enough, otherwise they glance off each other (hit-and-run). The dividing speed v<sub>cr</sub> comes from the collision simulations of Kokubo &amp; Genda (2010) and depends on the mass ratio and the impact angle. Boundary identification: <b>τ<sub>c</sub> = TL × v<sub>imp</sub> / v<sub>cr</sub></b>, so a collision merges below TL and hits and runs at or above it.</div>
    <div class="note r-only" style="margin-top:4px">v<sub>cr</sub>/v<sub>esc</sub> = 2.43Γ²Θ<sup>5/2</sup> − 0.0408Γ + 1.86Θ<sup>5/2</sup> + 1.08, Γ = (M₁−M₂)/(M₁+M₂), Θ = 1 − sin θ. v<sub>esc</sub> = √(2G(M₁+M₂)/(R₁+R₂)) with physical radii; v<sub>imp</sub> = √(v<sub>∞</sub>² + v<sub>esc</sub>²), v<sub>∞</sub> taken from the encounter at the enhanced contact distance.</div>
  </div>

  <div class="sec">
    <div class="st">VIEW</div>
    <div class="seg"><button id="v-top" onclick="setCam('top')">TOP</button><button id="v-orb" class="on" onclick="setCam('orbit')">ORBIT</button><button id="v-edge" onclick="setCam('edge')">EDGE-ON</button></div>
    <div class="seg"><button id="b-orb" class="on" onclick="toggleOrbits()">ORBITS ON</button><button id="b-ar" onclick="toggleAuto()">AUTO-ROTATE</button></div>
    <div class="note l-only">Drag to turn, scroll to zoom. Bright flashes are collisions: teal-to-gold flashes merged, red flashes hit and ran.</div>
    <div class="note r-only">Disk view is linear, 40 scene units per AU, heights ×4. Solar System view compresses distance as 60√(r/AU) so Mercury and Neptune fit together. Body size grows as the cube root of mass.</div>
  </div>
</div>

<!-- CENTER -->
<div id="view">
  <canvas id="c3d"></canvas>
  <div class="tag" id="sun-tag" style="color:var(--gold)">SUN</div>
  <div class="tag" id="snow-tag" style="color:var(--ice)">SNOW LINE 2.7 AU</div>
  <div id="legend">
    <div style="color:var(--anchor)" id="leg-title">TORSION τ = TL × 2√3 / Δ</div>
    <div class="bar"></div>
    <div class="row"><span style="color:#00ffc8">Noble 0</span><span style="color:#7b4fff">Locked</span><span style="color:#f0c060">IVA</span><span style="color:#ff3a3a">≥ TL</span></div>
  </div>
  <div id="clock"><span id="ck-t">0 yr</span><small id="ck-s">orbits at 1 AU</small></div>
  <div id="caption"></div>
</div>

<!-- RIGHT: readouts -->
<div id="right">
  <div class="sec">
    <div class="st">SYSTEM</div>
    <div class="kv"><span>Bodies</span><span id="k-n">0</span></div>
    <div class="kv"><span>Largest masses (M⊕)</span><span id="k-big">—</span></div>
    <div class="kv disk-only"><span>Isolation mass at 1 AU</span><span id="k-iso">—</span></div>
    <div class="kv"><span>Total mass in bodies</span><span id="k-mt">—</span></div>
    <div class="kv"><span>Merged · hit-and-run</span><span id="k-c">0 · 0</span></div>
    <div class="kv"><span>Fragments · lost to Sun · ejected</span><span id="k-l">0 · 0 · 0</span></div>
  </div>
  <div class="sec">
    <div class="st">PHASE MIX</div>
    <table id="mix-t"></table>
  </div>
  <div class="sec">
    <div class="st">HILL SPACING · τ = TL × 2√3 / Δ</div>
    <table id="hill-t"></table>
    <div class="note" style="margin-top:4px" id="hill-note"></div>
  </div>
  <div class="sec disk-only">
    <div class="st">GROWTH</div>
    <canvas class="chart short" id="gc"></canvas>
    <div class="note" style="margin-top:4px">White: number of bodies. Gold: largest mass in M⊕. Dashed: isolation mass at 1 AU. Both axes in log scale; time in years (compressed by about f).</div>
  </div>
  <div class="sec">
    <div class="st">MASS AGAINST ORBIT</div>
    <canvas class="chart" id="mc"></canvas>
    <div class="note" style="margin-top:4px" id="mc-note"></div>
  </div>
  <div class="sec disk-only">
    <div class="st">IMPACTS · τ<sub>c</sub> = TL × v<sub>imp</sub>/v<sub>cr</sub></div>
    <canvas class="chart short" id="hc"></canvas>
    <div class="note" style="margin-top:4px">Every collision so far, binned by τ<sub>c</sub>/TL. Left of the line merged; right of it hit and ran.</div>
  </div>
  <div class="sec solar-only">
    <div class="st">SATURN · ROCHE LIMIT · τ = TL × d<sub>R</sub> / d</div>
    <table id="roche-t"></table>
    <div class="note" style="margin-top:4px" id="roche-note"></div>
  </div>
  <div class="sec">
    <div class="st">EXPORT</div>
    <div class="seg"><button class="btn" onclick="exportJSON()">JSON</button><button class="btn" onclick="exportCSV()">CSV · BODIES</button></div>
  </div>
  <div class="foot">Accretion Simulator™, Identity Physics™, Applied Identity Physics™, SNSFT™, PNBA™, the Sovereign Anchor Constant™ and the Torsion Limit™ are common law trademarks of HIGHTISTIC (Russell Vernon Trent III) and the SNSFT Foundation. © 2026 HIGHTISTIC / SNSFT Foundation · DOI 10.5281/zenodo.18719748 · uuia.app/accretion</div>
</div>
</div>

<script>
// ════════════════════════════════════════════════════════════
// CONSTANTS · units: AU, year, solar mass (G = 4π²)
// ════════════════════════════════════════════════════════════
const TL = 0.136899099984016;            // Torsion Limit
const TL_IVA = 0.88 * TL;                // IVA corridor floor
const OMEGA0 = TL * 10;                  // Sovereign Anchor Constant Ω₀ = 1.36899099984016
const G = 4*Math.PI*Math.PI;
const AU_CM = 1.495978707e13, MSUN_G = 1.98847e33, MEARTH_G = 5.9722e27;
const ME = MEARTH_G/MSUN_G;              // Earth mass in solar masses
const SIG_UNIT = AU_CM*AU_CM/MSUN_G;     // g/cm² → M☉/AU²
const SNOW = 2.7, R_SUN_AU = 0.00465, HILL_CRIT = 2*Math.sqrt(3), B_ISO = 10;
const BODY_CAP = 800, LOG_CAP = 3000;
// Measured planets: mass (kg), semi-major axis (AU), eccentricity, inclination (deg)
const PLANETS = [
  ['Mercury',3.301e23,0.387,0.2056,7.00],['Venus',4.867e24,0.723,0.0068,3.39],['Earth',5.972e24,1.000,0.0167,0.00],['Mars',6.417e23,1.524,0.0934,1.85],
  ['Jupiter',1.898e27,5.203,0.0484,1.30],['Saturn',5.683e26,9.537,0.0539,2.49],['Uranus',8.681e25,19.19,0.0473,0.77],['Neptune',1.024e26,30.07,0.0086,1.77]];
const MSUN_KG = 1.98847e30;
// Saturn: equatorial radius 60,268 km, mean density 0.687 g/cm³; water ice 0.92 g/cm³; fluid Roche coefficient 2.44
const SAT_R = 60268, SAT_RHO = 0.687, ICE_RHO = 0.92, ROCHE_K = 2.44;
const SATURN_RING = [['D ring, inner edge',66900],['C ring, inner edge',74658],['B ring, inner edge',92000],['B ring, outer edge',117580],['A ring, inner edge',122170],
  ['Pan',133584],['Daphnis',136505],['A ring, outer edge',136775],['Atlas',137670],['Prometheus',139380],['F ring',140180],['Pandora',141720],
  ['Epimetheus',151410],['Janus',151460],['Mimas',185539],['Enceladus',238042],['Titan',1221870]];

// ════════════════════════════════════════════════════════════
// STATE
// ════════════════════════════════════════════════════════════
let mode='learner', sys='disk', region=2, Nset=200, fEnh=100, giant=false, tauModel='hill';
let mix={n:25,l:45,i:15,s:15}, running=true, budget=10, orbitsOn=true, autoRot=false;
let bodies=[], simT=0, dt=0.006, m0=0, sig1=7.1, snowF=4.2, nextId=1;
let stats, collLog=[], growth=[], hcBins;
function resetStats(){stats={merge:0,har:0,frag:0,sun:0,ej:0};collLog=[];growth=[];hcBins=new Array(20).fill(0).map(()=>({m:0,h:0}));}

// ════════════════════════════════════════════════════════════
// SCENE
// ════════════════════════════════════════════════════════════
const viewEl=document.getElementById('view'), cv=document.getElementById('c3d');
const renderer=new THREE.WebGLRenderer({canvas:cv,antialias:true});
renderer.setPixelRatio(Math.min(devicePixelRatio,2)); renderer.setClearColor(0x000000,1);
const scene=new THREE.Scene();
const camera=new THREE.PerspectiveCamera(50,1,0.1,5000);
scene.add(new THREE.AmbientLight(0x333344,1.5));
const sunLight=new THREE.PointLight(0xfff0c8,2.2,0); scene.add(sunLight);
const sunMat=new THREE.MeshBasicMaterial({color:0xf0c060});
const sunMesh=new THREE.Mesh(new THREE.SphereGeometry(1,24,16),sunMat); scene.add(sunMesh);
const sunGlow=new THREE.Mesh(new THREE.SphereGeometry(1,24,16),new THREE.MeshBasicMaterial({color:0xffdd88,transparent:true,opacity:.18})); scene.add(sunGlow);
(function(){const g=new THREE.BufferGeometry(),p=[];for(let i=0;i<2500;i++){const r=1500+Math.random()*1500,t=Math.random()*6.2832,f=Math.acos(2*Math.random()-1);p.push(r*Math.sin(f)*Math.cos(t),r*Math.cos(f),r*Math.sin(f)*Math.sin(t));}
g.setAttribute('position',new THREE.Float32BufferAttribute(p,3));scene.add(new THREE.Points(g,new THREE.PointsMaterial({color:0xaaaacc,size:1.2,transparent:true,opacity:.5})));})();
const SPH=new THREE.SphereGeometry(1,14,10);
let guides=[], orbitLines=[], flashes=[];

function tauColor(t){
  if(t===0)return new THREE.Color(0x00ffc8);
  if(t<TL*0.5)return new THREE.Color(0x00ffc8).lerp(new THREE.Color(0x7b4fff),t/(TL*0.5));
  if(t<TL)return new THREE.Color(0x7b4fff).lerp(new THREE.Color(0xf0c060),(t-TL*0.5)/(TL*0.5));
  return new THREE.Color(0xff3a3a);
}
function phaseOf(t){return t===0?'n':t<TL_IVA?'l':t<TL?'i':'s';}
const PH=[['n','Noble','#00ffc8'],['l','Locked','#9b7dff'],['i','IVA Peak','#f0c060'],['s','Shatter','#ff3a3a']];
const phCol=k=>PH.find(p=>p[0]===k)[2];

// Display mapping: disk linear 40 units/AU, heights ×4; Solar System 60√r.
function Dscale(r){return sys==='solar'?60/Math.sqrt(Math.max(r,1e-6)):40;}
function Dr(r){return r*Dscale(r);}
function circle(rDisp,col,op,dashed){
  const pts=[];for(let k=0;k<=128;k++){const a=k/128*2*Math.PI;pts.push(new THREE.Vector3(rDisp*Math.cos(a),0,rDisp*Math.sin(a)));}
  const g=new THREE.BufferGeometry().setFromPoints(pts);
  const m=dashed?new THREE.LineDashedMaterial({color:col,transparent:true,opacity:op,dashSize:3,gapSize:3}):new THREE.LineBasicMaterial({color:col,transparent:true,opacity:op});
  const l=new THREE.Line(g,m);if(dashed)l.computeLineDistances();return l;
}
function buildGuides(){
  for(const g of guides)scene.remove(g);guides=[];
  const add=(r,c,o,d)=>{const l=circle(Dr(r),c,o,d);scene.add(l);guides.push(l);};
  if(sys==='disk'){add(0.5,0x00ffc8,.12,false);add(region,0x00ffc8,.12,false);add(SNOW,0x88c8ff,.45,true);add(1,0xf0c060,.18,true);}
  else{add(SNOW,0x88c8ff,.45,true);}
  const sr=sys==='solar'?5:3.2;sunMesh.scale.setScalar(sr);sunGlow.scale.setScalar(sr*1.9);
}

// ════════════════════════════════════════════════════════════
// ORBITS
// ════════════════════════════════════════════════════════════
function rayleigh(s){return s*Math.sqrt(-2*Math.log(1-Math.random()));}
function setKep(b,a,e,i,O,w,Mm){
  let E=Mm;for(let k=0;k<30;k++)E=E-(E-e*Math.sin(E)-Mm)/(1-e*Math.cos(E));
  const n=Math.sqrt(G*(1+b.m)/(a*a*a)),ce=1-e*Math.cos(E);
  const xp=a*(Math.cos(E)-e),yp=a*Math.sqrt(1-e*e)*Math.sin(E),vxp=-a*n*Math.sin(E)/ce,vyp=a*n*Math.sqrt(1-e*e)*Math.cos(E)/ce;
  const cO=Math.cos(O),sO=Math.sin(O),cw=Math.cos(w),sw=Math.sin(w),ci=Math.cos(i),si=Math.sin(i);
  const r00=cO*cw-sO*sw*ci,r01=-cO*sw-sO*cw*ci,r10=sO*cw+cO*sw*ci,r11=-sO*sw+cO*cw*ci,r20=sw*si,r21=cw*si;
  // physics frame: x, y in the disk plane, z up
  b.x=r00*xp+r01*yp;b.y=r10*xp+r11*yp;b.z=r20*xp+r21*yp;
  b.vx=r00*vxp+r01*vyp;b.vy=r10*vxp+r11*vyp;b.vz=r20*vxp+r21*vyp;
}
function elements(b){
  const s=bodies[0],x=b.x-s.x,y=b.y-s.y,z=b.z-s.z,vx=b.vx-s.vx,vy=b.vy-s.vy,vz=b.vz-s.vz,mu=G*(s.m+b.m);
  const r=Math.hypot(x,y,z),v2=vx*vx+vy*vy+vz*vz,inv=2/r-v2/mu,a=inv>0?1/inv:Infinity;
  const hx=y*vz-z*vy,hy=z*vx-x*vz,hz=x*vy-y*vx,h2=hx*hx+hy*hy+hz*hz;
  const e=isFinite(a)?Math.sqrt(Math.max(0,1-h2/(mu*a))):1;
  return {a,e,i:Math.acos(Math.max(-1,Math.min(1,hz/Math.sqrt(h2)))),r};
}

// ════════════════════════════════════════════════════════════
// IDENTITY · PNBA per body
// ════════════════════════════════════════════════════════════
function drawPNBA(){
  const P=Math.pow(10,Math.random()),N=Math.floor(Math.random()*10)+1,A=1+Math.random()*9;
  const tot=mix.n+mix.l+mix.i+mix.s||1;let u=Math.random()*tot,t;
  if((u-=mix.n)<0)t=0;
  else if((u-=mix.l)<0)t=TL_IVA*(0.02+0.97*Math.random());
  else if((u-=mix.i)<0)t=TL_IVA+(TL-TL_IVA)*(0.01+0.98*Math.random());
  else t=TL*(1.01+2*Math.random());
  return {P,N,B:t*P,A};
}
function tauMix(b){return b.P>0?b.B/b.P:0;}
function tauOf(b){return tauModel==='mix'?tauMix(b):b.tauH;}

// ════════════════════════════════════════════════════════════
// BUILD
// ════════════════════════════════════════════════════════════
function sigma(r){return sig1*SIG_UNIT*(r<SNOW?1:snowF)*Math.pow(r,-1.5);}       // M☉/AU²
function isoMass(a){return Math.pow(2*Math.PI*a*a*B_ISO*sigma(a),1.5)*Math.sqrt(2/3);} // Kokubo & Ida 2002, b̃ = 10
function physR(m,rho){return Math.cbrt(3*m*MSUN_G/(4*Math.PI*rho))/AU_CM;}
function newBody(m,R,extra){
  const b=Object.assign({id:nextId++,born:simT,m,R,x:0,y:0,z:0,vx:0,vy:0,vz:0,ax:0,ay:0,az:0,tauH:0,members:1},drawPNBA(),extra||{});
  b.mat=new THREE.MeshPhongMaterial({color:0xffffff,emissive:0x000000,shininess:40});
  b.mesh=new THREE.Mesh(SPH,b.mat);scene.add(b.mesh);return b;
}
function removeBody(b){if(b.mesh){scene.remove(b.mesh);b.mat.dispose();b.mesh=null;}}
function rebuild(){
  for(const b of bodies)removeBody(b);bodies=[];simT=0;nextId=1;resetStats();
  sig1=Math.max(0.1,+document.getElementById('in-sig').value||7.1);snowF=Math.max(0.1,+document.getElementById('in-snow').value||4.2);
  const sun={id:0,m:1,R:R_SUN_AU,x:0,y:0,z:0,vx:0,vy:0,vz:0,ax:0,ay:0,az:0,sun:true,P:1,N:1,B:0,A:1,tauH:0,members:1};
  bodies.push(sun);
  if(sys==='disk'){
    const a0=0.5,a1=region;let M=0;const st=4000,da=(a1-a0)/st;for(let k=0;k<st;k++){const r=a0+(k+.5)*da;M+=2*Math.PI*r*da*sigma(r);}
    m0=M/Nset;let fmax=0;for(let r=a0;r<=a1;r+=0.01)fmax=Math.max(fmax,r*sigma(r));
    for(let k=0;k<Nset;k++){
      let r;do{r=a0+(a1-a0)*Math.random();}while(Math.random()*fmax*1.01>r*sigma(r));
      const b=newBody(m0,physR(m0,r<SNOW?3:1.5),{f:fEnh});
      const h=Math.cbrt(2*m0/3);setKep(b,r,rayleigh(2*h/Math.SQRT2),rayleigh(h/Math.SQRT2),Math.random()*6.2832,Math.random()*6.2832,Math.random()*6.2832);
      bodies.push(b);
    }
    if(giant){const J=PLANETS[4],b=newBody(J[1]/MSUN_KG,physR(J[1]/MSUN_KG,1.33),{f:1,name:'Jupiter',giant:true});setKep(b,J[2],J[3],J[4]*Math.PI/180,0,0,Math.random()*6.2832);bodies.push(b);}
    dt=0.006;
    if(tauModel==='mix'){const born=bodies.slice(1);for(const b of born)if(!b.giant)reorganize(b);}
  }else{
    m0=0;
    for(const p of PLANETS){const m=p[1]/MSUN_KG,b=newBody(m,physR(m,p[0]==='Jupiter'||p[0]==='Saturn'?1:p[0]==='Uranus'||p[0]==='Neptune'?1.6:5),{f:1,name:p[0]});
      setKep(b,p[2],p[3],p[4]*Math.PI/180,Math.random()*6.2832,Math.random()*6.2832,Math.random()*6.2832);bodies.push(b);}
    dt=0.0024;
  }
  // barycentric start
  let px=0,py=0,pz=0;for(const b of bodies){px+=b.m*b.vx;py+=b.m*b.vy;pz+=b.m*b.vz;}
  sun.vx-=px;sun.vy-=py;sun.vz-=pz;
  accel(false);computeHill();buildGuides();paintAll();sample();renderAll();caption();
}

// ════════════════════════════════════════════════════════════
// GRAVITY · direct N-body, kick-drift-kick leapfrog
// ════════════════════════════════════════════════════════════
let hits=[];
function accel(collide){
  const n=bodies.length;hits=[];
  for(let i=0;i<n;i++){const b=bodies[i];b.ax=0;b.ay=0;b.az=0;}
  for(let i=0;i<n;i++){const a=bodies[i],ax=a.x,ay=a.y,az=a.z;let sx=0,sy=0,sz=0;
    for(let j=i+1;j<n;j++){const b=bodies[j];
      const dx=b.x-ax,dy=b.y-ay,dz=b.z-az,r2=dx*dx+dy*dy+dz*dz,ir=1/Math.sqrt(r2),f=G*ir*ir*ir;
      sx+=f*b.m*dx;sy+=f*b.m*dy;sz+=f*b.m*dz;b.ax-=f*a.m*dx;b.ay-=f*a.m*dy;b.az-=f*a.m*dz;
      if(collide&&!a.sun){const Rs=(a.R*a.f+b.R*b.f);const lim=Rs+0.01;if(r2<lim*lim){
        const dvx=b.vx-a.vx,dvy=b.vy-a.vy,dvz=b.vz-a.vz,v2=dvx*dvx+dvy*dvy+dvz*dvz||1e-30;
        const px=dx-dvx*dt,py=dy-dvy*dt,pz=dz-dvz*dt,tmin=(a.born>simT-1.5*dt||b.born>simT-1.5*dt)?dt:0;let t=-(px*dvx+py*dvy+pz*dvz)/v2;t=t<tmin?tmin:t>dt?dt:t;
        const cx=px+dvx*t,cy=py+dvy*t,cz=pz+dvz*t;if(cx*cx+cy*cy+cz*cz<Rs*Rs)hits.push([a,b]);}}
    }
    a.ax+=sx;a.ay+=sy;a.az+=sz;}
}
function step(){
  const h=dt/2;
  for(const b of bodies){b.vx+=b.ax*h;b.vy+=b.ay*h;b.vz+=b.az*h;b.x+=b.vx*dt;b.y+=b.vy*dt;b.z+=b.vz*dt;}
  accel(sys==='disk');
  for(const b of bodies){b.vx+=b.ax*h;b.vy+=b.ay*h;b.vz+=b.az*h;}
  simT+=dt;
  if(hits.length){resolve();accel(false);}
}
// Kokubo & Genda (2010) critical impact velocity in units of the mutual escape speed
function vcrit(m1,m2,sinT){const Gm=(m1-m2)/(m1+m2),Th=Math.pow(1-sinT,2.5);return 2.43*Gm*Gm*Th-0.0408*Gm+1.86*Th+1.08;}
function resolve(){
  const dead=new Set();
  for(const [a,b] of hits){if(dead.has(a)||dead.has(b))continue;
    const dx=b.x-a.x,dy=b.y-a.y,dz=b.z-a.z,dvx=b.vx-a.vx,dvy=b.vy-a.vy,dvz=b.vz-a.vz;
    const d=Math.hypot(dx,dy,dz),v2=dvx*dvx+dvy*dvy+dvz*dvz,M=a.m+b.m;
    const Rs=a.R*a.f+b.R*b.f,dc=Math.max(d,Rs*0.5);
    const vinf2=Math.max(0,v2-2*G*M/dc),vesc=Math.sqrt(2*G*M/(a.R+b.R)),vimp=Math.sqrt(vinf2+vesc*vesc);
    const L=Math.hypot(dy*dvz-dz*dvy,dz*dvx-dx*dvz,dx*dvy-dy*dvx),sinT=Math.min(1,L/(Math.sqrt(v2)*d||1));
    const big=a.m>=b.m?a:b,sm=big===a?b:a;
    const vc=vcrit(big.m,sm.m,sinT)*vesc,tc=TL*vimp/vc,merged=tc<TL;
    const bin=Math.min(19,Math.floor(tc/TL*10));hcBins[bin][merged?'m':'h']++;
    const el=elements(big);
    if(collLog.length<LOG_CAP)collLog.push({t_yr:+simT.toFixed(2),a_AU:+el.a.toFixed(4),m1_Mearth:+(big.m/ME).toFixed(5),m2_Mearth:+(sm.m/ME).toFixed(5),vimp_over_vesc:+(vimp/vesc).toFixed(4),sin_theta:+sinT.toFixed(4),vcr_over_vesc:+(vc/vesc).toFixed(4),tau_c:+tc.toFixed(6),outcome:merged?'merge':'hit-and-run'});
    flash(big,merged?tauColor(Math.min(tc,TL*0.999)):new THREE.Color(0xff3a3a),Math.cbrt(M/ME));
    if(!merged){stats.har++;continue;}
    stats.merge++;
    for(const k of ['x','y','z','vx','vy','vz'])big[k]=(a.m*a[k]+b.m*b[k])/M;
    big.R=Math.cbrt(Math.pow(big.R,3)+Math.pow(sm.R,3));big.m=M;big.born=simT;big.members+=sm.members;
    if(sm.giant){big.giant=true;big.name=sm.name;big.f=1;}
    // GAM Collider v15 2-beam rule
    const P=big.P*sm.P/(big.P+sm.P);big.N=big.N+sm.N;big.B=Math.abs(big.B-sm.B);big.A=Math.max(big.A,sm.A);big.P=P;
    dead.add(sm);removeBody(sm);
    if(tauModel==='mix'&&!big.giant)reorganize(big);
  }
  if(dead.size)bodies=bodies.filter(b=>!dead.has(b));
}
// τ ≥ TL reorganizes into smaller stable identities: halves with P doubled, N halved (τ halves), until below TL.
function reorganize(b){
  const queue=[b];
  while(queue.length){const c=queue.pop();
    if(tauMix(c)<TL||c.m<Math.max(m0,1e-12)*0.5||bodies.length>=BODY_CAP)continue;
    const m=c.m/2,R=c.R/Math.cbrt(2);
    // separation direction: in-plane, perpendicular to the velocity
    let ux=-c.vy,uy=c.vx;const ul=Math.hypot(ux,uy)||1;ux/=ul;uy/=ul;
    const s=1.3*(R*c.f),vsep=1.2*Math.sqrt(2*G*c.m/(2*s))/2;
    const d=newBody(m,R,{f:c.f,P:c.P*2,N:c.N/2,B:c.B,A:c.A,members:Math.max(1,Math.floor(c.members/2))});
    c.m=m;c.R=R;c.born=simT;c.P*=2;c.N/=2;c.members=Math.max(1,c.members-d.members);
    d.x=c.x-ux*s;d.y=c.y-uy*s;d.z=c.z;d.vx=c.vx-ux*vsep;d.vy=c.vy-uy*vsep;d.vz=c.vz;
    c.x+=ux*s;c.y+=uy*s;c.vx+=ux*vsep;c.vy+=uy*vsep;
    bodies.push(d);stats.frag++;queue.push(c,d);
  }
}
function prune(){
  let ch=false;
  bodies=bodies.filter(b=>{if(b.sun)return true;const el=elements(b);
    if(el.r<0.1){stats.sun++;removeBody(b);ch=true;return false;}
    if(el.r>(sys==='solar'?200:60)&&!isFinite(el.a)){stats.ej++;removeBody(b);ch=true;return false;}
    if(el.r>200){stats.ej++;removeBody(b);ch=true;return false;}
    return true;});
  if(ch)accel(false);
}

// ════════════════════════════════════════════════════════════
// HILL SPACING · τ = TL × 2√3 / Δ (Gladman 1993: two orbits stay apart for Δ > 2√3)
// ════════════════════════════════════════════════════════════
let hillPairs=[], embryoPairs=[];
function mutualRH(p,q){return Math.cbrt((p.m+q.m)/(3*bodies[0].m))*(p.a+q.a)/2;}
function computeHill(){
  const list=bodies.filter(b=>!b.sun).map(b=>{const el=elements(b);b.a=el.a;b.e=el.e;b.inc=el.i;return b;}).filter(b=>isFinite(b.a)).sort((p,q)=>p.a-q.a);
  hillPairs=[];
  for(const b of list)b.dmin=Infinity;
  for(let k=1;k<list.length;k++){const p=list[k-1],q=list[k],D=(q.a-p.a)/mutualRH(p,q);hillPairs.push({p,q,D});p.dmin=Math.min(p.dmin,D);q.dmin=Math.min(q.dmin,D);}
  for(const b of list)b.tauH=isFinite(b.dmin)?TL*HILL_CRIT/Math.max(b.dmin,1e-3):0;
  // embryos: bodies above 20% of the largest mass (planets in the Solar System view)
  const mx=Math.max(0,...list.filter(b=>!b.giant).map(b=>b.m));
  const emb=sys==='solar'?list:list.filter(b=>b.m>=0.2*mx&&!b.giant);
  embryoPairs=[];for(let k=1;k<emb.length;k++){const p=emb[k-1],q=emb[k];embryoPairs.push({p,q,D:(q.a-p.a)/mutualRH(p,q)});}
}

// ════════════════════════════════════════════════════════════
// DRAW
// ════════════════════════════════════════════════════════════
function sizeOf(b){const c=Math.cbrt(b.m/ME);return sys==='solar'?1.4+1.35*c:Math.min(7,0.6+3.2*c);}
function paintAll(){
  for(const b of bodies){if(b.sun||!b.mesh)continue;const t=tauOf(b),col=tauColor(t);b.mat.color.copy(col);b.mat.emissive.copy(col).multiplyScalar(.45);b.mesh.scale.setScalar(sizeOf(b));}
}
function place(){
  const s0=bodies[0];
  for(const b of bodies){const x=b.x-s0.x,y=b.y-s0.y,z=b.z-s0.z,r=Math.hypot(x,y),k=Dscale(Math.hypot(x,y,z));
    if(b.mesh)b.mesh.position.set(x*k,z*k*(sys==='disk'?4:1),y*k);}
}
function flash(b,col,sz){
  const s0=bodies[0],x=b.x-s0.x,y=b.y-s0.y,z=b.z-s0.z,k=Dscale(Math.hypot(x,y,z));
  const m=new THREE.Mesh(SPH,new THREE.MeshBasicMaterial({color:col,transparent:true,opacity:.9,depthWrite:false}));
  m.position.set(x*k,z*k*4,y*k);m.userData={life:1,base:1.2+2.5*Math.min(1,sz)};scene.add(m);flashes.push(m);
  if(flashes.length>30){const o=flashes.shift();scene.remove(o);o.material.dispose();}
}
function tickFlashes(){
  flashes=flashes.filter(m=>{m.userData.life-=0.035;if(m.userData.life<=0){scene.remove(m);m.material.dispose();return false;}
    m.scale.setScalar(m.userData.base*(2-m.userData.life));m.material.opacity=m.userData.life*.8;return true;});
}
function drawOrbits(){
  for(const l of orbitLines){scene.remove(l);l.geometry.dispose();l.material.dispose();}orbitLines=[];
  if(!orbitsOn)return;
  const list=sys==='solar'?bodies.filter(b=>!b.sun):embryoPairs.length?[...new Set(embryoPairs.flatMap(p=>[p.p,p.q]))]:[];
  const gi=bodies.filter(b=>b.giant);
  for(const b of [...list.slice(0,40),...gi]){if(!isFinite(b.a))continue;const t=tauOf(b),l=circle(Dr(b.a),tauColor(t).getHex(),b.giant?.5:.32,false);scene.add(l);orbitLines.push(l);}
}

// ════════════════════════════════════════════════════════════
// READOUTS
// ════════════════════════════════════════════════════════════
function sample(){if(sys!=='disk')return;const mx=Math.max(0,...bodies.filter(b=>!b.sun&&!b.giant).map(b=>b.m));growth.push([simT,bodies.length-1-(giant?1:0),mx/ME]);if(growth.length>800)growth=growth.filter((g,k)=>k%2===0||k===growth.length-1);}
function sizeCanvas(c){const w=c.clientWidth,h=c.clientHeight;if(c.width!==w*devicePixelRatio){c.width=w*devicePixelRatio;c.height=h*devicePixelRatio;}const x=c.getContext('2d');x.setTransform(devicePixelRatio,0,0,devicePixelRatio,0,0);x.clearRect(0,0,w,h);return [x,w,h];}
const fmtM=m=>m>=10?m.toFixed(0):m>=1?m.toFixed(2):m>=0.01?m.toFixed(3):m.toExponential(1);
function renderSystem(){
  const pl=bodies.filter(b=>!b.sun&&!b.giant).sort((p,q)=>q.m-p.m);
  document.getElementById('k-n').textContent=sys==='solar'?pl.length:pl.length+(giant?' + Jupiter':'');
  document.getElementById('k-big').textContent=pl.slice(0,4).map(b=>fmtM(b.m/ME)).join(' · ')||'—';
  document.getElementById('k-iso').textContent=isoMass(1)/ME>0?fmtM(isoMass(1)/ME)+' M⊕ (b̃ = 10)':'—';
  document.getElementById('k-mt').textContent=fmtM(pl.reduce((s,b)=>s+b.m,0)/ME)+' M⊕';
  document.getElementById('k-c').textContent=`${stats.merge} · ${stats.har}`;
  document.getElementById('k-l').textContent=`${stats.frag} · ${stats.sun} · ${stats.ej}`;
  document.getElementById('ck-t').textContent=simT<1e4?simT.toFixed(simT<100?1:0)+' yr':(simT/1e3).toFixed(1)+' kyr';
  document.getElementById('ck-s').textContent=sys==='disk'?`${simT.toFixed(0)} orbits at 1 AU · clock compressed ≈ ×${fEnh}`:`${(simT/11.862).toFixed(2)} Jupiter orbits`;
  if(sys==='disk'){document.getElementById('disk-read').innerHTML=`This run: <b>${fmtM(m0*Nset/ME)} M⊕</b> of solids in ${Nset} bodies of <b>${fmtM(m0/ME)} M⊕</b> each (about ${Math.round(physR(m0,3)*AU_CM/1e5)} km across as rock). Time step ${dt} yr.`;}
}
function renderMix(){
  const pl=bodies.filter(b=>!b.sun&&!b.giant),c={n:0,l:0,i:0,s:0},ms={n:0,l:0,i:0,s:0};let mt=0;
  for(const b of pl){const p=phaseOf(tauOf(b));c[p]++;ms[p]+=b.m;mt+=b.m;}
  let h='<tr><th>PHASE</th><th>BODIES</th><th>SHARE</th><th>MASS SHARE</th></tr>';
  for(const [k,name,col] of PH)h+=`<tr><td style="color:${col}">${name}</td><td>${c[k]}</td><td>${pl.length?(100*c[k]/pl.length).toFixed(1)+'%':'—'}</td><td style="color:var(--text)">${mt?(100*ms[k]/mt).toFixed(1)+'%':'—'}</td></tr>`;
  document.getElementById('mix-t').innerHTML=h;
}
function renderHill(){
  const rows=sys==='solar'?embryoPairs:[...embryoPairs].sort((p,q)=>(q.p.m+q.q.m)-(p.p.m+p.q.m)).slice(0,8).sort((p,q)=>p.p.a-q.p.a);
  let h=`<tr><th>${sys==='solar'?'PAIR':'PAIR a (AU)'}</th><th>Δ (R<sub>H</sub>)</th><th>τ/TL</th><th>PHASE</th></tr>`;
  for(const r of rows){const t=TL*HILL_CRIT/r.D,ph=phaseOf(t);
    const nm=sys==='solar'&&r.p.name&&r.q.name?`${r.p.name}–${r.q.name}`:`${r.p.a.toFixed(2)}–${r.q.a.toFixed(2)}`;
    h+=`<tr><td>${nm}</td><td>${r.D.toFixed(1)}</td><td style="color:${phCol(ph)}">${(t/TL).toFixed(3)}</td><td style="color:${phCol(ph)}">${({n:'Noble',l:'Locked',i:'IVA Peak',s:'Shatter'})[ph]}</td></tr>`;}
  document.getElementById('hill-t').innerHTML=rows.length?h:'';
  const Ds=embryoPairs.map(p=>p.D).sort((a,b)=>a-b),med=Ds.length?Ds[Math.floor(Ds.length/2)]:null;
  document.getElementById('hill-note').innerHTML=sys==='solar'
    ?`Δ is the gap between neighbouring orbits in mutual Hill radii, R<sub>H</sub> = ((m₁+m₂)/3M☉)<sup>1/3</sup>(a₁+a₂)/2, from the live orbits. Gladman (1993): two planets can never cross orbits when Δ &gt; 2√3 ≈ 3.46, so Δ = 2√3 ↔ τ = TL. Every neighbouring pair sits well inside Locked; the tightest is Jupiter–Saturn, the pair near the 5:2 resonance behind the Great Inequality.`
    :`Embryos are the bodies above 20% of the largest mass. Median embryo spacing <b>${med?med.toFixed(1):'—'} R<sub>H</sub></b> (τ/TL ${med?(HILL_CRIT/med).toFixed(2):'—'}) over ${embryoPairs.length} pairs. Kokubo &amp; Ida (1998, 2000) found oligarchs settle about 10 R<sub>H</sub> apart, τ/TL ≈ 0.35. Δ = 2√3 (Gladman 1993) ↔ τ = TL. The table lists the eight heaviest neighbouring pairs.`;
}
function logY(v,lo,hi,h,B,T){return h-B-(h-B-T)*(Math.log10(v)-Math.log10(lo))/(Math.log10(hi)-Math.log10(lo));}
function renderGrowth(){
  if(sys!=='disk')return;const [x,w,h]=sizeCanvas(document.getElementById('gc'));
  if(growth.length<2)return;
  const L=30,B=14,T=6,t0=Math.max(growth[0][0],1),t1=Math.max(growth[growth.length-1][0],t0*10);
  const X=t=>L+(w-L-6)*(Math.log10(Math.max(t,t0))-Math.log10(t0))/(Math.log10(t1)-Math.log10(t0));
  x.font='9px "Space Mono", monospace';x.fillStyle='rgba(232,232,240,.4)';
  const lo=1e-3,hi=1e3;[1e-3,1,1e3].forEach(v=>{const y=logY(v,lo,hi,h,B,T);x.strokeStyle='rgba(232,232,240,.1)';x.beginPath();x.moveTo(L,y);x.lineTo(w-6,y);x.stroke();x.fillText(v>=1?String(v):'.001',0,y+3);});
  x.fillText(t0.toFixed(0)+' yr',L,h-2);x.fillText((t1>=1e4?(t1/1e3).toFixed(0)+'k':t1.toFixed(0))+' yr',w-50,h-2);
  const iso=isoMass(1)/ME,yi=logY(iso,lo,hi,h,B,T);x.strokeStyle='rgba(240,192,96,.55)';x.setLineDash([3,3]);x.beginPath();x.moveTo(L,yi);x.lineTo(w-6,yi);x.stroke();x.setLineDash([]);
  const line=(k,col)=>{x.strokeStyle=col;x.lineWidth=2;x.beginPath();growth.forEach((g,i)=>{const px=X(Math.max(g[0],t0)),py=logY(Math.max(g[k],lo),lo,hi,h,B,T);i?x.lineTo(px,py):x.moveTo(px,py);});x.stroke();x.lineWidth=1;};
  line(1,'#ffffff');line(2,'#f0c060');
}
function renderMassOrbit(){
  const [x,w,h]=sizeCanvas(document.getElementById('mc'));
  const solar=sys==='solar',L=30,B=16,T=6;
  const a0=solar?0.3:0.4,a1=solar?40:(giant?6:region+0.3),lo=solar?0.01:Math.max(1e-4,m0/ME/3),hi=solar?1000:Math.max(1,isoMass(region)/ME*3);
  const X=a=>solar?L+(w-L-6)*(Math.log10(a)-Math.log10(a0))/(Math.log10(a1)-Math.log10(a0)):L+(w-L-6)*(a-a0)/(a1-a0);
  x.font='9px "Space Mono", monospace';x.fillStyle='rgba(232,232,240,.4)';
  for(let e=Math.ceil(Math.log10(lo));e<=Math.log10(hi);e++){const y=logY(10**e,lo,hi,h,B,T);x.strokeStyle='rgba(232,232,240,.08)';x.beginPath();x.moveTo(L,y);x.lineTo(w-6,y);x.stroke();x.fillText(e>=0?String(10**e):'1e'+e,0,y+3);}
  (solar?[0.5,1,5,10,30]:[0.5,1,2,3,4,5].filter(a=>a<=a1)).forEach(a=>x.fillText(a,X(a)-4,h-3));
  // snow line
  x.strokeStyle='rgba(136,200,255,.55)';x.setLineDash([3,3]);x.beginPath();x.moveTo(X(SNOW),T);x.lineTo(X(SNOW),h-B);x.stroke();x.setLineDash([]);
  x.fillStyle='rgba(136,200,255,.75)';x.fillText('snow',X(SNOW)+2,T+8);
  if(!solar){x.strokeStyle='rgba(240,192,96,.6)';x.setLineDash([4,3]);x.beginPath();for(let a=a0;a<=a1;a+=0.02){const y=logY(Math.max(lo,isoMass(a)/ME),lo,hi,h,B,T);a===a0?x.moveTo(X(a),y):x.lineTo(X(a),y);}x.stroke();x.setLineDash([]);}
  for(const b of bodies){if(b.sun||!isFinite(b.a)||b.a<a0||b.a>a1)continue;const m=b.m/ME;if(m<lo||m>hi*1.01)continue;
    const r=Math.max(1.6,Math.min(6,1.4+2*Math.cbrt(m/(solar?1:isoMass(1)/ME))));x.fillStyle=tauColor(tauOf(b)).getStyle();x.beginPath();x.arc(X(b.a),logY(m,lo,hi,h,B,T),r,0,6.3);x.fill();
    if(solar){x.fillStyle='rgba(232,232,240,.6)';x.fillText((b.name||'').slice(0,3),X(b.a)+4,logY(m,lo,hi,h,B,T)-4);}}
  document.getElementById('mc-note').innerHTML=solar
    ?'Measured planets, mass in M⊕ against semi-major axis in AU (both log). Colour is the Hill-spacing τ of each planet against its nearest neighbour. Blue dashed: snow line.'
    :'Each body, mass in M⊕ (log) against semi-major axis in AU. Gold dashed: isolation mass M<sub>iso</sub> = √(2/3)(2πa²b̃Σ)<sup>3/2</sup>/M☉<sup>1/2</sup>, b̃ = 10 (Kokubo &amp; Ida 2002), the mass an oligarch reaches once it has swept its feeding zone. Blue dashed: snow line.';
}
function renderImpacts(){
  if(sys!=='disk')return;const [x,w,h]=sizeCanvas(document.getElementById('hc'));
  const L=24,B=14,T=6,bw=(w-L-6)/20,mx=Math.max(1,...hcBins.map(b=>b.m+b.h));
  x.font='9px "Space Mono", monospace';x.fillStyle='rgba(232,232,240,.4)';
  hcBins.forEach((b,i)=>{const bx=L+i*bw,hm=(h-B-T)*b.m/mx,hh=(h-B-T)*b.h/mx;
    x.fillStyle=tauColor(Math.min(TL*0.999,(i+.5)/10*TL)).getStyle();x.fillRect(bx+1,h-B-hm,bw-2,hm);
    x.fillStyle='#ff3a3a';x.fillRect(bx+1,h-B-hm-hh,bw-2,hh);});
  const xl=L+10*bw;x.strokeStyle='rgba(255,255,255,.7)';x.setLineDash([3,3]);x.beginPath();x.moveTo(xl,T);x.lineTo(xl,h-B);x.stroke();x.setLineDash([]);
  x.fillStyle='rgba(232,232,240,.5)';x.fillText('0',L,h-2);x.fillText('TL',xl-6,h-2);x.fillText('2 TL',w-28,h-2);x.fillText(mx,0,T+6);
}
function renderRoche(){
  const dR=ROCHE_K*SAT_R*Math.cbrt(SAT_RHO/ICE_RHO);
  let h='<tr><th>OBJECT</th><th>d (km)</th><th>τ/TL</th><th>PHASE</th></tr>';
  for(const [n,d] of SATURN_RING){const t=TL*dR/d,ph=phaseOf(t);h+=`<tr><td>${n}</td><td>${d.toLocaleString('en-US')}</td><td style="color:${phCol(ph)}">${(t/TL).toFixed(4)}</td><td style="color:${phCol(ph)}">${({n:'Noble',l:'Locked',i:'IVA Peak',s:'Shatter'})[ph]}</td></tr>`;}
  document.getElementById('roche-t').innerHTML=h;
  document.getElementById('roche-note').innerHTML=`Fluid Roche limit for water ice around Saturn, d<sub>R</sub> = 2.44 R<sub>S</sub>(ρ<sub>S</sub>/ρ<sub>ice</sub>)<sup>1/3</sup> = <b>${Math.round(dR).toLocaleString('en-US')} km</b> (R<sub>S</sub> = 60,268 km, ρ<sub>S</sub> = 0.687, ρ<sub>ice</sub> = 0.92 g/cm³). Inside it tides pull a loose body apart, so d<sub>R</sub>/d = 1 ↔ τ = TL. The main rings sit past TL (Shatter: material that never gathered into a moon), the outer A ring, the F ring and the small ring moons sit in the IVA corridor, and Mimas outward is Locked. Janus and Epimetheus land 0.1% above the IVA floor, so their placement moves with the ice density chosen.`;
}
function renderAll(){renderSystem();renderMix();renderHill();renderGrowth();renderMassOrbit();renderImpacts();if(sys==='solar')renderRoche();}

// ════════════════════════════════════════════════════════════
// CAPTIONS
// ════════════════════════════════════════════════════════════
function caption(){
  const L={
    disk:'A young star is ringed by a swarm of rocky bodies, each going around on its own orbit. They pull on each other and sometimes touch. A gentle touch <b>merges</b> them; a fast or glancing one makes them bounce apart. The crowded swarm starts past the <b>Torsion Limit</b> (red): it is too packed to stay as it is. Watch it reorganize into a few larger bodies with wide, safe gaps between them.',
    solar:'The eight planets on their measured orbits. Their colour reads how close each one sits to its neighbour, measured against the spacing where two orbits could cross. Every gap is safely <b>Locked</b>; the tightest pair is Jupiter and Saturn. On the right, Saturn\'s rings show the other boundary: inside the <b>Roche limit</b> tides pull moons apart, which is where the rings are.'};
  const R={
    disk:`Direct N-body (G = 4π² in AU, yr, M☉), kick-drift-kick leapfrog, dt = ${dt} yr, Sun included as a body. Swept-sphere collision detection with radii ×${fEnh}. Collisions merge when v<sub>imp</sub> &lt; v<sub>cr</sub> (Kokubo &amp; Genda 2010), otherwise hit-and-run. Watch for runaway growth, then oligarchs near the isolation mass about 10 R<sub>H</sub> apart (Kokubo &amp; Ida 1998, 2000).`,
    solar:'Eight measured planets, real masses, semi-major axes, eccentricities and inclinations, random orbital phases, barycentric start, dt = 0.0024 yr. τ per pair = TL × 2√3/Δ, Δ in mutual Hill radii (Gladman 1993). Saturn\'s ring system against the fluid Roche limit: τ = TL × d<sub>R</sub>/d.'};
  let cap=(mode==='learner'?L:R)[sys];
  if(sys==='disk'&&tauModel==='mix')cap+=mode==='learner'?' <b>Band mix is on:</b> each body carries its own identity (P, N, B, A). Merged bodies combine by the GAM Collider rule, and any body past the Torsion Limit splits into smaller pieces that sit below it.':' <b>Band mix on:</b> per-body PNBA from the generator; mergers by the GAM Collider 2-beam rule; τ ≥ TL bodies split into halves (P×2, N÷2) until below TL.';
  if(sys==='disk'&&giant)cap+=mode==='learner'?' Jupiter is in place at 5.2 AU and stirs the outer swarm.':' Jupiter at 5.2 AU (measured mass, e, i).';
  document.getElementById('caption').innerHTML=cap;
  document.getElementById('tau-note').innerHTML=tauModel==='hill'
    ?'Boundary identification: two orbits closer than <b>2√3 mutual Hill radii</b> can cross (Gladman 1993) ↔ τ = TL. Each body takes <b>τ = TL × 2√3 / Δ</b>, Δ the gap to its nearest orbital neighbour. A crowded swarm reads Shatter; well-spaced planets read Locked.'
    :'Each body is born with P, N, B, A from the band mix (B = τ × P), as in AxiomForge and Galaxy. Colour shows τ = B/P. Mergers combine identities by the GAM Collider 2-beam rule. The mix applies on ⟲ NEW RUN.';
  document.getElementById('leg-title').textContent=tauModel==='hill'||sys==='solar'?'TORSION τ = TL × 2√3 / Δ':'TORSION τ = B/P';
}

// ════════════════════════════════════════════════════════════
// CONTROLS
// ════════════════════════════════════════════════════════════
const on=(ids,id)=>ids.forEach(i=>document.getElementById(i).classList.toggle('on',i===id));
function setMode(m){mode=m;document.body.classList.toggle('res',m==='res');on(['m-l','m-r'],m==='res'?'m-r':'m-l');caption();}
function setSys(s){sys=s;on(['s-disk','s-sol'],s==='disk'?'s-disk':'s-sol');document.body.classList.toggle('solar',s==='solar');
  if(s==='solar'&&tauModel==='mix'){tauModel='hill';on(['t-hill','t-mix'],'t-hill');document.getElementById('mix-wrap').style.display='none';}
  ['t-hill','t-mix'].forEach(i=>document.getElementById(i).disabled=s==='solar');
  cam.r=s==='solar'?560:(region===4?(giant?330:270):(giant?320:200));rebuild();setTimeout(()=>{resize();renderAll();},0);}
function setRegion(r){region=r;on(['rg-2','rg-4'],'rg-'+r);cam.r=r===4?270:200;if(giant)cam.r=320;rebuild();}
function setJup(j){giant=j;on(['j-off','j-on'],j?'j-on':'j-off');cam.r=j?320:(region===4?270:200);rebuild();}
function onN(){Nset=+document.getElementById('nset').value;document.getElementById('n-v').textContent=Nset;}
function onF(){fEnh=+document.getElementById('fset').value;document.getElementById('f-v').textContent='×'+fEnh;}
function setTau(t){tauModel=t;on(['t-hill','t-mix'],'t-'+t);document.getElementById('mix-wrap').style.display=t==='mix'?'block':'none';
  if(t==='mix'&&sys==='disk'){for(const b of bodies.slice(1))if(!b.sun&&!b.giant)reorganize(b);accel(false);}
  paintAll();caption();renderAll();}
function onMix(){mix={n:+document.getElementById('mx-n').value||0,l:+document.getElementById('mx-l').value||0,i:+document.getElementById('mx-i').value||0,s:+document.getElementById('mx-s').value||0};}
function onRate(){budget=+document.getElementById('rate').value;document.getElementById('rate-v').textContent=budget+' ms';}
function toggleRun(){running=!running;const b=document.getElementById('b-run');b.classList.toggle('on',running);b.textContent=running?'■ PAUSE':'▶ RUN';}
function toggleOrbits(){orbitsOn=!orbitsOn;const b=document.getElementById('b-orb');b.classList.toggle('on',orbitsOn);b.textContent=orbitsOn?'ORBITS ON':'ORBITS OFF';drawOrbits();}
function toggleAuto(){autoRot=!autoRot;document.getElementById('b-ar').classList.toggle('on',autoRot);}

// ════════════════════════════════════════════════════════════
// CAMERA
// ════════════════════════════════════════════════════════════
let cam={r:200,th:.6,ph:.95},tgtCam=null;
function placeCam(){camera.position.set(cam.r*Math.sin(cam.ph)*Math.cos(cam.th),cam.r*Math.cos(cam.ph),cam.r*Math.sin(cam.ph)*Math.sin(cam.th));camera.lookAt(0,0,0);}
function setCam(v){tgtCam=v==='top'?{ph:.04}:v==='edge'?{ph:1.53}:{ph:.95};['top','orb','edge'].forEach(k=>document.getElementById('v-'+k).classList.toggle('on',(k==='orb'?'orbit':k)===v));}
let drag=false,lx=0,ly=0;
cv.addEventListener('pointerdown',e=>{drag=true;lx=e.clientX;ly=e.clientY;cv.setPointerCapture(e.pointerId);});
cv.addEventListener('pointerup',()=>drag=false);
cv.addEventListener('pointermove',e=>{if(!drag)return;tgtCam=null;cam.th+=(e.clientX-lx)*.005;cam.ph=Math.max(.03,Math.min(1.56,cam.ph-(e.clientY-ly)*.005));lx=e.clientX;ly=e.clientY;});
cv.addEventListener('wheel',e=>{e.preventDefault();cam.r=Math.max(30,Math.min(1600,cam.r*(1+e.deltaY*.001)));},{passive:false});

// ════════════════════════════════════════════════════════════
// EXPORT
// ════════════════════════════════════════════════════════════
function dl(name,text,type){const a=document.createElement('a');a.href=URL.createObjectURL(new Blob([text],{type}));a.download=name;a.click();setTimeout(()=>URL.revokeObjectURL(a.href),1000);}
function bodyRec(b){const t=tauOf(b);return {id:b.id,name:b.name||null,a_AU:+b.a.toFixed(5),e:+b.e.toFixed(5),i_deg:+(b.inc*180/Math.PI).toFixed(4),m_Mearth:+(b.m/ME).toPrecision(6),members:b.members,
  hill_delta_RH:isFinite(b.dmin)?+b.dmin.toFixed(3):null,tau_hill:+b.tauH.toFixed(6),P:+b.P.toFixed(6),N:+b.N.toFixed(4),B:+b.B.toFixed(6),A:+b.A.toFixed(4),tau_pnba:+tauMix(b).toFixed(6),tau_model:tauModel,phase:({n:'Noble',l:'Locked',i:'IVA Peak',s:'Shatter'})[phaseOf(t)]};}
function exportJSON(){
  computeHill();const pl=bodies.filter(b=>!b.sun&&isFinite(b.a));
  dl('accretion_session.json',JSON.stringify({tool:'Accretion Simulator',generated:new Date().toISOString(),constants:{TL,TL_IVA,OMEGA0,hill_critical:HILL_CRIT},
    settings:sys==='disk'?{system:'planetesimal disk',region_AU:[0.5,region],planetesimals:Nset,radius_enhancement:fEnh,sigma1_gcm2:sig1,snow_line_AU:SNOW,snow_factor:snowF,jupiter:giant,tauModel,bandMix:mix,dt_yr:dt,body_mass_Mearth:m0/ME,isolation_mass_1AU_Mearth:isoMass(1)/ME}:{system:'Solar System, measured',dt_yr:dt},
    elapsed_yr:+simT.toFixed(2),stats,
    hill_pairs:embryoPairs.map(p=>({inner:p.p.name||+p.p.a.toFixed(4),outer:p.q.name||+p.q.a.toFixed(4),delta_RH:+p.D.toFixed(3),tau_over_TL:+(HILL_CRIT/p.D).toFixed(4)})),
    growth:growth.map(g=>({t_yr:+g[0].toFixed(1),bodies:g[1],largest_Mearth:+g[2].toPrecision(5)})),collisions:collLog,bodies:pl.map(bodyRec)},null,2),'application/json');
}
function exportCSV(){computeHill();const pl=bodies.filter(b=>!b.sun&&isFinite(b.a)).map(bodyRec),k=Object.keys(pl[0]||{});dl('accretion_bodies.csv',k.join(',')+'\n'+pl.map(r=>k.map(c=>r[c]).join(',')).join('\n'),'text/csv');}

// ════════════════════════════════════════════════════════════
// LOOP
// ════════════════════════════════════════════════════════════
function resize(){const w=viewEl.clientWidth,h=viewEl.clientHeight;renderer.setSize(w,h,false);camera.aspect=w/h;camera.updateProjectionMatrix();}
window.addEventListener('resize',resize);
let frame=0,stepsLast=0;
function tag(id,v3){const v=v3.clone().project(camera),el=document.getElementById(id);el.style.display=v.z<1?'block':'none';el.style.left=((v.x*.5+.5)*viewEl.clientWidth)+'px';el.style.top=((-v.y*.5+.5)*viewEl.clientHeight)+'px';}
function advance(){
  if(!running)return;const t0=performance.now();let n=0;
  const cap=sys==='solar'?400:100000;
  while(performance.now()-t0<budget&&n<cap){step();n++;if(n%50===0)prune();}
  stepsLast=n;
}
function loop(){
  requestAnimationFrame(loop);frame++;
  if(tgtCam){cam.ph+=(tgtCam.ph-cam.ph)*.08;if(Math.abs(tgtCam.ph-cam.ph)<.002)tgtCam=null;}
  if(autoRot)cam.th+=.0015;
  placeCam();advance();
  if(frame%10===0){computeHill();paintAll();}
  if(frame%20===0)sample();
  if(frame%30===0)drawOrbits();
  place();tickFlashes();
  sunGlow.scale.setScalar((sys==='solar'?5:3.2)*(1.9+Math.sin(frame*.03)*.1));
  renderer.render(scene,camera);
  tag('sun-tag',new THREE.Vector3(0,0,0));tag('snow-tag',new THREE.Vector3(Dr(SNOW)*Math.cos(cam.th),0,Dr(SNOW)*Math.sin(cam.th)));
  if(frame%15===0)renderAll();
}
resize();setMode('learner');rebuild();placeCam();loop();
</script>
</body>
</html>

Files

Accretion_Simulator_Guide (5).md

Files (119.8 kB)

Name Size
md5:5c9354db9abe387bc8b78abde5d98815
56.7 kB Download
md5:9c7d39f008e3e5f45d7c06aaab2e2dd6
37.4 kB Preview Download
md5:6470b48f0dd39876e5a7e8e3636b2cd6
25.7 kB Download