PulseCore

Chapter 6 · Section 8

Drawing a Galaxy: Its Points, Its Layout, Its Light

The BPT law

BPT Part 3.14 (The Game's Reading) states how a galaxy is drawn: "Its stars are its own population, by type; the young blue ones lie on the arms, where they form, and the old ones in a smooth disk and bulge. So a spiral is an exponential disk with as many trailing logarithmic arms as its disk can raise, round a warm bulge; a lenticular as a smooth disk with a larger bulge; an elliptical as a round warm swarm; an irregular or a starburst as clumps." The Spiral Arms section gives the reason the young stars light the arms: "Gas passing through an arm is squeezed, shocks and forms stars there (Roberts, 1969), and the bright blue stars die within a few tens of millions of years, before they drift far, so the arms are lit by the young stars they make." And the stars are drawn as the same kinds anywhere: "Stars are drawn by type: blue-white giants bright and few in young clusters, red giants and supergiants large and orange, red dwarfs small and dim ..."

How many points a galaxy gets on a given device is not in BPT; it is a game method.

The established physics

  • Logarithmic trailing arms of a density wave, along which the young stars lie (Lin & Shu 1964).
  • An exponential disk: the radius of a point drawn as ρ = −R_d·ln u, u uniform, has the exponential surface density Σ ∝ e^(−ρ/R_d) (exact).
  • A logarithmic spiral of pitch i: φ = cot(i)·ln(ρ/ρ₀) (exact geometry).
  • Nothing in the layout of the bulge, the elliptical swarm or the irregular's clumps is taken from a source; those shapes are display choices.

The game's math

The device's points. sendOutMatter() app.js:1198 sets the scene's point count P = max(matterBudget(), 15,000), and matterBudget() is 8000 on a phone and 8000 to 16,000 on a desktop by its memory and cores (app.js:1176–1182; the matter chapter). The scene lowers P by a fifth when frames average over 45 ms across 3 s, while P > 8000 (scene3d.js:2003). The fallback is 30,000 if none was set.

The galaxies' share (setGalaxies(list) scene3d.js:483–496):

B_g = round(0.6 · P)
For spirals and starbursts, largest first by stars:
    full = 120 · max(1, arms)
    gets full while the arm galaxies' running total stays within 0.6 · B_g, else 40
least = clamp(⌊(B_g − arm points used) / (other galaxies)⌋, 12, 40)
count_i = max(arm or least floor, round(B_g · max(1, stars_i) / Σ stars))

The buffer is sized to ⌈1.3·n⌉ points so small changes do not reallocate it.

Example: a desktop at P = 16,000: B_g = 9600; the arm galaxies may take 5760 points at full, so the 24 largest two-armed spirals get 240 points each (about 2 × 120 on and between the arms), and every spiral after them 40. On a phone, P = max(8000, 15,000) = 15,000 and B_g = 9000.

Each point's star (scene3d.js:527–537). A kind is picked from pop (Part 6.4) in proportion to its light n·L. It is "young" if m ≥ 2 Suns, not a giant, not a white dwarf or neutron star. Its color and size come from starLook() (the stars chapter), then: size = (0.01 + 0.2·min(0.08, size))·clamp(R/8, 0.12, 1)·starSizeK, and its color is mixed 45 : 55 with its type's tint (spiral arm young [0.62, 0.78, 1], spiral other [1, 0.86, 0.62], elliptical [1, 0.76, 0.48], lenticular [0.98, 0.88, 0.66], irregular [0.66, 0.8, 1]), the star gain held under 1.6, times 0.85, and the size × 1.35.

Each point's place (scene3d.js:516, 528, 539–546), R the drawn radius and R_d its drawn scale length (Part 6.5), R_d at least 0.03 cells (0.28·R if missing), the pitch 18° if missing:

elliptical or spheroidal: ρ = min(R, 0.3·R·(−ln u)^1.5), φ uniform, flattened q = 0.75
irregular: 4 clumps at 0.55·R·√u, each point Gaussian about one, σ = 0.12·R
bulge (old stars, with chance 0.35 in a lenticular, 0.15 otherwise): ρ = min(0.4·R, −0.25·R_d·ln u)
disk: ρ = clamp(−R_d·ln u, 0.05·R, R)
   on an arm (spirals and starbursts, chance 0.85 if young, 0.2 if old):
   φ = −sense · cot(pitch) · ln(ρ / ρ₀) + 2πj/m + w·g,   ρ₀ = 0.5·R_d,  w = 0.35π/m,  g Gaussian
   otherwise φ uniform

Arm points (young stars on an arm) are drawn 1.3 times larger; all others at 0.85 brightness.

One set of stars (scene3d.js:553–555, 690–695, 727–730). The galaxies are binned in 16-cell bins; inGalaxy(r, c) is true inside any galaxy's drawn radius R. A body there has its star points drawn by the galaxy layer instead, and keeps only its gas and its white dwarfs and neutron stars. The cluster glows skip patches inside a galaxy (Part 6.10).

On the surface (scene3d.js:621–626). A column cell and a row cell have different lengths on the torus, so each galaxy's column offsets are scaled by the ratio of the two lengths at its center, at most cols/(4·max(1, R)), a quarter turn of the ring.

In the game

This is the galaxy as the player sees it in the 3D view. A spiral is a blue-white pair (or more) of trailing arms on a warm gold-white disk round a small bright bulge; a lenticular is a pale gold disk with a larger bulge and no arms; an elliptical a round, slightly flattened yellow-orange swarm; a dwarf irregular four patchy blue clumps. Each point is a real kind of star of that galaxy, colored as that kind is colored everywhere in the game and then tinted toward its type, so types read apart at a glance: the comment at scene3d.js:534–536 (2026-10-29) records the ruling, "we cant see the different galaxy types clearly", that led to the tints. Inside a galaxy's drawn radius the body field's own star points give way to the galaxy's, so one set of stars is shown; the bodies' gas haze and their white dwarfs and neutron stars stay.

Galaxies are laid round the torus's curved surface so they stay round, not stretched, near the inner throat (scene3d.js:618–626). A galaxy's points follow its well as the well moves, so a galaxy drifts and merges with its well. The largest spirals carry the most points, which is why their arms show from afar; a small galaxy is a smaller sprinkle. On a slow device the scene draws fewer points after a few seconds of slow frames, so the same universe can look sparser on a phone. At the return to the Source the galaxy and stream points are hidden halfway through the fade and gone in the hollow torus that remains (scene3d.js:2032–2036).

The scale model

A drawn galaxy is one real galaxy (each drawn galaxy one galaxy, app.js:1405). Its points do not stand for a fixed number of stars: a galaxy of stars drawn stars, standing for stars × starMult real ones, gets count_i points, so one point stands for stars_i × starMult / count_i real stars. The points are a sample of its light, not of its number: a kind gets points by n·L, so a few blue giants get many. The layout is the law's (exponential disk, logarithmic arms at the measured pitch and number) at the enlarged drawn size; the bulge, the elliptical's swarm and the irregular's clumps are display.

Where the game and the theory differ

  • BPT draws "an irregular or a starburst as clumps". The code draws a starburst as a spiral, with arms (scene3d.js:517: spiral = /spiral|starburst/), unlike the book and the comment at scene3d.js:481–482.
  • The points each galaxy gets are a share of what the device can draw, not of the galaxy: the galaxies get 60% of the device's points, the largest spirals 120 points an arm until they hold 60% of that, later spirals 40, the others between 12 and 40 each. Because each count is the larger of its floor and its share, the total can exceed the galaxies' share when there are many galaxies, and the floors make the stars per point smaller for small galaxies and spirals than for large non-spirals. BPT states none of this.
  • The comment at scene3d.js:486–490 still describes 240 points for any spiral and "The galaxies' share of the device's points is 35 %"; the code gives 120 an arm and 60%. The comment at scene3d.js:479 still gives the pitch as 18°; the measured pitch is passed and 18° is only the fallback.
  • The scene lowers the device's points by a fifth on slow frames (to no less than 8000), so what is drawn depends on the device's speed during the run.

Fixed numbers

Number Where What it is Kind
15000 app.js:1198 least scene point budget, any device CAP
30000 scene3d.js:485, 571 point budget if none was set CAP
0.8 scene3d.js:2003 the budget lowered by a fifth on slow frames CAP
45 scene3d.js:2003 mean frame time that lowers the budget, ms CAP
3000 scene3d.js:2003 frame time summed before a check, ms METHOD
8000 scene3d.js:2003 the budget is never lowered from 8000 or less CAP
0.6 scene3d.js:485 galaxies get 60% of the points CAP
120 scene3d.js:494 points an arm for a full spiral CAP
2 scene3d.js:494, 516 arms if missing METHOD (two-armed default)
0.6 scene3d.js:494 full spirals take at most 60% of the galaxies' points CAP
40 scene3d.js:494 points for a spiral past that share CAP
12 scene3d.js:495 least points for any other galaxy CAP
40 scene3d.js:495 most "least" points for any other galaxy CAP
1 scene3d.js:485, 496 max(1, stars) METHOD
1.3 scene3d.js:501 buffer headroom METHOD (avoids reallocating)
0.03 scene3d.js:516 least drawn scale length, cells CAP
0.28 scene3d.js:516 R_d = 0.28·R if missing METHOD (a placeholder; R/R_d = 4 is always passed)
18 scene3d.js:516 pitch in degrees if missing METHOD (placeholder; the pitch is always passed)
0.5 scene3d.js:516 arms start at ρ₀ = 0.5·R_d DISPLAY
0.35π scene3d.js:516 arm width, radians, over m DISPLAY
4 scene3d.js:528 an irregular's clumps DISPLAY
0.55, 0.12 scene3d.js:528, 540 clump placement and spread, × R DISPLAY
0.3, 1.5 scene3d.js:539 an elliptical's radial profile DISPLAY
0.75 scene3d.js:539 an elliptical's flattening DISPLAY
0.35, 0.15 scene3d.js:541 bulge share of old stars, lenticular and other DISPLAY
0.4, 0.25 scene3d.js:541 bulge's outer limit (× R) and scale (× R_d) DISPLAY
0.05 scene3d.js:543 least disk radius, × R DISPLAY
0.85, 0.2 scene3d.js:544 chance of an arm, young and old stars DISPLAY
2 scene3d.js:531 Suns: "young" on the arms BPT (Part 3.14, as in Part 6.3)
0.01, 0.2, 0.08 scene3d.js:533 point size from the star's look DISPLAY
8, 0.12, 1 scene3d.js:533 point size scaled by R/8, between 0.12 and 1 DISPLAY
1.6 scene3d.js:537 greatest star gain in a galaxy DISPLAY
0.45, 0.55, 0.85 scene3d.js:538 star color against type tint, and dimming DISPLAY
tints scene3d.js:537 the five type colors DISPLAY
1.35 scene3d.js:538 galaxy points' size factor DISPLAY
1.3, 0.85 scene3d.js:547 arm points larger; others dimmer DISPLAY
[1, 0.95, 0.88], 0.016 scene3d.js:532 color and size when no kind is known DISPLAY
16 scene3d.js:553, 692 galaxy bins, cells METHOD (lookup speed)
256 scene3d.js:553, 692 field side if not yet known METHOD
4 scene3d.js:626 column stretch at most a quarter turn of the ring CAP

Measured

The comment at scene3d.js:486–490 (2026-10-28) records: "measured in the browser, 75 spirals at 40 points each showed no arms even close up", the reason spirals get their arm points first. The comment at scene3d.js:618–622 (2026-10-28) records that, "measured in the browser with the other layers hidden: the largest spirals were smears and streaks", the reason for the surface stretch.