BlackHole
A man-made black hole you pump up and let down with the mouse wheel.
What it does
BlackHole sits beside a GravityMass, which is the physics, and a MeshPrimitive sphere. It adds a mass dial, a horizon that follows the mass, and the look.
Every frame the System sets the GravityMass radius, the distance at which a rock is swallowed, to mass × horizonScale, and scales the sphere to match. What you see is what eats rocks. The radius grows linearly with mass, like a real horizon: at the defaults a hole of 600 has a radius of 1.32, and the dial runs from 0.33 at 150 to 3.3 at 1500.
A wheel notch over the hole moves its mass by massStep, heavier when you roll away from you. Gameplay takes the new radius at once. Only the sphere eases, over resizeSeconds, so a pumped hole swells instead of popping.
The look ships as an engine plugin: an accretion disk, white-hot at the inner edge and red at the rim, a halo with a photon ring, a glow while the pointer is over the hole or holding it, and a flare when it swallows a rock. The disk is tilted so it reads in a top view and a side view.
Setup
The engine work ships with the component, in adapter/register.ts. A project made with bjs create installs it for you: src/main.ts calls every adapter/register.ts that bjs download puts in the project, before the scene loads. If you boot the game from your own code, call it once, right after building the adapter:
Without it the hole is a bare black sphere and the System warns once. The plugin is Babylon only. The horizon and the dial work the same without it.
Use it in a scene
A scene is just data — a list of entities, each with its components. At startup the SceneLoader turns this JSON into a live world; edit the file and reload to rebuild it.
Build it from scratch with the bjs CLI:
- 1Scaffold a project
World, renderer, and dev server — ready to run.
- 2Install dependencies
- 3Add BlackHole
Copies its source into src/ so the scene resolves.
First time? Run bjs login once.
- 4Paste the scene into src/scenes/arcade-room.ts and run
SceneLoader builds the world from the JSON; reload to rebuild.
PointerDrag is optional: it brings the wheel and the glow. SpaceGolf puts all four on a Pool blueprint and hands holes out from it.
Props
minMass(number, default150) — lightest the player may make it.maxMass(number, default1500) — heaviest. Never belowminMass.massStep(number, default75) — mass added or removed per notch.horizonScale(number, default0.0022) — horizon radius per unit of mass.resizeSeconds(number, default0.25) — time the sphere takes to ease to a new size. 0 snaps.diskInner(number, default1.7) — inner edge of the disk, in horizon radii.diskOuter(number, default4.4) — outer edge of the disk, in horizon radii.diskTilt(number, default0.42) — tilt of the disk out of the horizontal, in radians.hotColor(color, default[1, 0.86, 0.6]) — the disk's inner edge, and the photon ring.coolColor(color, default[0.95, 0.32, 0.08]) — the disk's outer edge.highlightColor(color, default[0.45, 0.85, 1]) — the hover and grab glow.diskSpin(number, default1.6) — disk speed at a mass of 600. It grows with the square root of the mass.
Events
Emits:
blackhole.mass.changed{ entityId, mass, min, max }when a hole enters play, on every dial move, and when a mass written straight onto the GravityMass changes, as SpaceGolf's director does for each level.
Listens:
pointerdrag.wheel{ entityId, delta }turns the dial bydeltanotches.blackhole.mass.adjust{ entityId, steps }turns it bysteps, for buttons and touch screens.pointerdrag.hover.changed,pointerdrag.startedandpointerdrag.endeddrive the glow.gravity.body.contactsets off the flare whenswallowedis true andmassIdis this hole.
Dependencies
MeshPrimitive: the sphere the System scales and the plugin dresses.GravityMass: the mass and the swallow radius. A rock that touches the horizon is swallowed rather than crashed.
Notes
- A
radiusset on the GravityMass in the scene is overwritten every frame. Size a hole with its mass andhorizonScale. - The System sets
absorbsandlenseson the GravityMass when the hole joins, so a scene can leave both out: the hole still swallows rocks and still bends aGravityLenssky. - Only
setMeshScaleis written, so it never races whoever drags the hole. - A parked hole is hidden, not undressed. Handed out again, it snaps to its new size and announces its mass again.
- The disk and halo bloom only with a
GlowLayerin the scene. The plugin keeps checking until one exists.











































