Chapter 4 · Section 8
The Direct Pull and the Particle–Particle Split
The BPT law
BPT does not state this; it is a game method that serves two things the book does state. The first is the pull and the horizon. BPT Part 2.4 (Event Horizons and Null Wells) takes Newtonian gravity as given and reads the horizon at the "event horizon scale r_s = 2GM/c²" as the boundary where a well's Pulse activity falls to null; Part 3.11 sets the G it uses. The second is the sites. BPT Part 3.14 (Proto Wells: Where Wells Will Form) says "a Proto Well is not a well. Formed in the data before the physical layer, it is the deepest place of the Data Matter, the seed of a halo (Part 3.13), and at the Physical Nova it becomes a site: where the gas will gather, where the first stars will light, and where a well will be born." A site therefore has no horizon and no point mass of its own: in the code it is the heart of the matter round it, and it pulls only through the grid, as that matter does (ruling 2026-10-29, matter.js:242–245). The direct pull below is how the game resolves Newton's law near a real well, where the mesh is too coarse.
The established physics
- Newton's law with Plummer softening, a = GM·r̂/(r² + ε²), the softening "every N-body code uses" (matter.js:322); the P³M split of a short-range direct force and a long-range mesh force (Hockney & Eastwood 1988, cited at matter.js:335).
- The Schwarzschild radius r_s = 2GM/c² (BPT Part 2.4).
The game's math
accel(b, wells, isWell) matter.js:331:
- A site (
b.site) feels the bodies' field alone, interpolated (matter.js:336–338). Sites pull nothing directly (if (w.site) continue). - A body feels the bodies' mesh field, plus each non-site well within three blocks directly, faded by
near = max(0, 1 − d/(2B))to nothing at two blocks (matter.js:352). - A well feels the wells' mesh field (matter, Data Matter, sites) plus every other non-site well directly at full strength, unless more than 256 wells pull (
nPull > 256): then it is treated as a body (whole grid with wells included, plus direct pulls within two blocks, faded). Ruling 2026-10-29, after 15,000 sites at level 202 made 2 × 10⁸ pairs a sub-step and a step took 53 s.
The direct term (matter.js:351–354):
d² = dr² + dc² + ε², a = near · G · max(1, M) / d², along (dr, dc)/d
ε = reach(w) = max(1, r_s, (10·G·max(1, M))^(1/3)) matter.js:324
r_s = horizon(w) = 2·G·max(1, M) / c² (0 for a site) matter.js:318
The (10GM)^(1/3) term: inside it one flip's pull would bend a path by more than a tenth of the distance, which a one-flip step cannot follow (matter.js:319–323). The softening is computed once per binning (w._soft).
Binning (also read from the wells' side in Chapter 3, Part 3.12). binWells() matter.js:272 sorts non-site wells into mesh blocks. If more than 8 pull and the mesh has more than 7 blocks a side, every well writes itself into the 7 × 7 blocks round it once, so a body's near list is one lookup (profiled 2026-10-28: 14 % of a physical step was rebuilding those lists). wellsNear() matter.js:291 returns every puller when there are 8 or fewer, or when the reach wraps the torus. binBodies() and bodiesNear() matter.js:304–316 do the same for bodies.
Worked case, desktop at level 6 or deeper with G_F ≈ 4.3 × 10⁻⁷ and c = 128: a well of 10⁴ cells has r_s = 2 × 4.3 × 10⁻⁷ × 10⁴ / 16,384 ≈ 5 × 10⁻⁷ cells, (10GM)^(1/3) = (0.043)^(1/3) ≈ 0.35, so ε = 1 cell: the softening is the one-cell floor, not the horizon.
In the game
The direct pull is what the player sees near the wells: clumps swinging round a well and on past it, or falling in (Part 4.12), and wells drifting through the matter toward each other until they merge (the merger of wells and its finds are in Chapter 3). In 3D every well is drawn where its pull has carried it, moved each slice by moveWells() (app.js:1312); a well inside a drawn galaxy is drawn small, a third of its mark, "a horizon is tiny next to its galaxy" (setWells() scene3d.js:1471–1475). The HUD's Wells line counts the sites still waiting for their wells: "… · N sites waiting" (app.js:2141–2142). No control changes the pull.
The scale model
The direct pull covers what the mesh cannot resolve, within two blocks. Beyond the 256-well switch, well–well pulls past two blocks come from the mesh, at its resolution. Both are numerical resolution, not physics, and change nothing at the level of the law: the same G and the same masses.
Fixed numbers
| Number | Where | What it is | Kind |
|---|---|---|---|
| 3 | accel() matter.js:349; binWells() matter.js:283 |
Blocks searched for a body's direct wells (7 × 7) | METHOD (covers the 2-block fade) |
| 2 | accel() matter.js:352 |
Direct pull fades to zero at 2B | METHOD (P³M split) |
| 256 | accel() matter.js:339 |
Wells pulling directly before wells go on the grid | METHOD (P³M switch for cost) |
| 8 | binWells() matter.js:281; wellsNear() matter.js:293 |
Few enough wells to skip bins | METHOD |
| 7 | binWells() matter.js:281 |
Mesh must exceed 7 blocks for the cache | METHOD |
| 10 | reach() matter.js:324 |
Softening (10GM)^(1/3): a tenth of the distance bent a flip | METHOD (resolution) |
| 1 | reach() matter.js:324 |
Softening floor, cells | METHOD |
| 1 | accel() matter.js:353; horizon() matter.js:318 |
Floor on a well's mass | METHOD |
| 2 | horizon() matter.js:318 |
r_s = 2GM/c² | PHYSICS (Schwarzschild 1916; BPT Part 2.4) |