Guides
Portals and spell orbs
Two glow-heavy effects. A portal is two torus emitters inside a swirl field that spins dye and pulls it into the eye. Spell orbs are emitters on tilted orbits that leave coloured trails and light the scene.
#Portals
portal preset with the camera slowly orbiting. The swirl field fades out about 0.4 m either side of the portal plane (swirl.thickness), so the dye winds into a flat vortex.const portal = magic.addEffect('portal', {
position: [0, 2.25, 0],
axis: [0, 0, 1], // the portal's normal
colors: ['#a66bff', '#35d4ff'], // outer ring, inner ring
});
portal.retarget({ target: camera.position }); // turn it to face the cameraA portal adds four things to each frame:
- An outer torus emitter of
radius1.12 m and tubethickness0.2 m incolors[0]. Its glow pulses by ±pulse(25 %) atpulseRate2.2 rad/s. - An inner torus emitter of
innerRadius0.62 m incolors[1]. Its radius wobbles byinnerWobble0.08 m. - A swirl field around the axis. Inside
swirl.radiusit drives the fluid toward a velocity that spins atspeed, pulls toward the axis atpulland lifts along it atlift. - Rim sparks that spawn on a circle of
sparks.ringRadius1.15 m and are attracted to the centre atsparks.attract1.8 m/s, so they spiral into the eye.
Neither emitter pushes the fluid (velocity zero, blend 0). All the motion comes from the swirl.
#Options
| Option | Default | |
|---|---|---|
position, axis | [0, 2.25, 0], [0, 0, 1] | Centre and normal. retarget() sets axis |
radius, thickness | 1.12, 0.2 | Outer ring and its tube radius (m) |
innerRadius, innerThickness, innerWobble | 0.62, 0.12, 0.08 | Inner ring |
colors | [[0.62, 0.28, 1], [0.2, 0.85, 1]] | Outer and inner dye, linear RGB |
glow, innerGlow | 3.2, 2.4 | Glow per second |
density, innerDensity | 0.55, 0.35 | Dye density per second |
pulse, pulseRate | 0.25, 2.2 | Outer glow pulse depth (0 = steady) and rate (rad/s) |
swirl | { radius: 1.75, speed: 3.2, pull: 1.35, thickness: 0.4, lift: 0 } | speed: 0 removes the swirl field |
sparks | { rate: 1.2, radius: 0.12, ringRadius: 1.15, attract: 1.8, life: 0.35, jitter: 0.8, colorA, colorB } | rate: 0 removes the sparks |
The colors getter returns the colours in effect this frame, with any setColor() override applied. The demo uses it to tint the rune ring.
#Recipes
// a calm, wide gate: slower spin, less pull, no pulse
portal.set({ radius: 1.4, pulse: 0, swirl: { speed: 1.6, pull: 0.6 } });
// a floor portal: lie it flat and let it lift smoke upward through the eye
portal.move([0, 0.4, 0]).retarget([0, 1, 0]).set({ swirl: { lift: 1.2 } });
// open it over five seconds (the clip on the Overview page)
magic.clear();
let opened = 0;
function openPortal(dt) { // call every frame before magic.update(dt)
const k = Math.min(1, (opened += dt) / 5);
portal.setIntensity(k * k * (3 - 2 * k));
}#Spell orbs
spellOrbs: three orbs at 1.25 rad/s on orbits tilted 0, 0.9 and −0.9 rad. The fluid inside each orb is driven at 60 % of the orb's speed (trail: 0.6), which drags the glow out into ribbons.const orbs = magic.addEffect('spellOrb', {
position: [0, 2.0, 0], // orbit centre
count: 3,
colors: ['#a66bff', '#35d4ff', '#ffc44a'],
});
orbs.orbs[0].position; // live world position of each orbEach orb is an emitter that moves along its orbit. It also gets:
- a point light (
light.intensity28, scaled by the glow control and the effect's intensity), so the orbs light the floor and props as they pass. Setlight: { intensity: 0 }to add no lights. - a bright core sphere of
visual.size0.075 m, drawn at three times the orb colour. Setvisual: { size: 0 }for none.
The orbs' lights and meshes are ordinary three.js objects in your scene, named MagicOrbLight and MagicOrb. setLightsEnabled(false) hides the lights along with the glow light.

setLightsEnabled(false) against the default. It hides the orbs' point lights and the emission-driven glow light; the rest of the scene's lighting is unchanged.#Options
| Option | Default | |
|---|---|---|
position | [0, 2, 0] | Orbit centre |
count | 3 | Number of orbs. Change it live with set({ count }) |
orbitRadius, speed | 1.05, 1.25 | Metres; rad/s |
tilts, bob | [0, 0.9, -0.9], 0.18 | Per-orb orbit tilt (cycled); vertical bob (m) |
colors | violet, cyan, gold | Cycled over the orbs |
radius, glow, density | 0.15, 4.2, 1.2 | Emitter size, glow and dye per second |
temperature, blend, trail | 0.08, 0.25, 0.6 | Heat; drive strength; fraction of the orb's velocity given to the fluid |
light | { intensity: 28 } | One PointLight per orb; 0 = none |
visual | { size: 0.075 } | Core sphere per orb; 0 = none |
sparks | { rate: 0.35, radius: 1.4, needGlow: 0.25, life: 0.6, jitter: 1.2, colorA, colorB } | Sparks spawn only where the dye glow exceeds needGlow |