NatureGL Magicv1.0.0

Reference

API reference

Everything exported from src/index.js and build/index.js. The types are in build/*.d.ts.

js
import {
  MagicSystem, PRESETS, getPresetParams, DEFAULT_PARAMS, QUALITY_LEVELS,
  EFFECT_TYPES, MagicEffect, PortalEffect, GenieLampEffect, InkEffect, SpellOrbEffect,
  VortexRingEffect, DragonBreathEffect, ForceFieldEffect, EmitterEffect, TravellingRing,
  FluidSolver, LIMITS, patchReflectiveFloor,
} from 'naturegl-magic';

Units are metres and seconds. Vectors are THREE.Vector3 or [x, y, z]. Colours are linear [r, g, b] arrays (above 1 = HDR glow), or THREE.Color, '#rrggbb' or 0xrrggbb (sRGB, converted to linear). Options are stored as JSON arrays.

#MagicSystem

#MagicSystem.create(options): Promise<MagicSystem>static async

Builds the system: allocates the fluid fields for the quality tier, adds the sparks and the glow light to options.scene, loads the preset, then warms up with renderer.compileAsync(scene, camera) when the renderer has it. new MagicSystem(options) does the same without the warm-up.

OptionTypeDefault
rendererTHREE.WebGLRenderer—Required. WebGL2 with EXT_color_buffer_float, or the constructor throws
sceneTHREE.Scene—Required. Sparks, the glow light and effect meshes are added here
cameraTHREE.PerspectiveCamera—Required. Used by render() and composite()
quality'low', 'medium', 'high', 'ultra''high'See Quality levels
domain{ min?, width? }{ min: [-2, 0, -2], width: 4 }Simulation box. Height = 1.5 × width. The bottom is a solid floor; the sides and top are open
presetstring, object or null'portal'Loaded on creation. null = default params, no effects
sparksbooleantrueGPU sparks
glowLightbooleantrueThe emission-driven PointLight
glowShadowsbooleantrueThe glow light casts shadows (enable renderer.shadowMap yourself)

#Frame

#magic.update(dt): voidmethod

Advances the effects, one fluid step, the sparks, the glow readback and the lights. dt is clamped to 1/120 … 1/30 s, then scaled by params.controls.speed. Offscreen only: it draws nothing on screen.

#magic.render(target = null): voidmethod

Renders scene with camera into an internal colour + depth target, then composites the volume over it. Call it instead of renderer.render(scene, camera). The output is tone-mapped (ACES) and sRGB-encoded, to target or the canvas.

#magic.composite(inputColor, inputDepth, target = null): voidmethod

The lower-level entry point. inputColor is a linear HDR colour texture and inputDepth its DepthTexture, both from magic.camera. Colour alpha is the reflectivity mask: 1 − alpha reflects the volume on surfaces at the domain floor. See Rendering into your scene.

#magic.resize(): voidmethod

Matches the internal targets to the renderer's drawing buffer. Call it after renderer.setSize() or setPixelRatio().

The screen pipeline: scene → volume raymarch at the tier's scale (MRT: colour + transmittance, opacity-weighted depth) → temporal accumulation → depth-aware bilateral upsample and composite (+ heat haze) → 6-level bloom → exposure, hue-preserving ACES, saturation, contrast, vignette → sRGB.

#Presets and params

#magic.loadPreset(nameOrObject, { effects = true, clear = true }?): MagicEffect[]method

Replaces params with DEFAULT_PARAMS merged with the preset. With effects, removes every effect and adds the preset's. With clear, clears the fluid. Returns the handles it added. Sets presetName to the name, or 'custom' for an object.

#magic.setParams(partial): MagicSystemmethod

Deep-merges into params. An effects key is ignored; effects are untouched. Arrays are replaced, not merged. Returns the system.

#magic.getParams(): objectmethod

A deep copy of params plus effects: [{ type, options, intensity? }], JSON-serialisable. Pass it back to loadPreset().

#magic.setQualityLevel(level): voidmethod

Rebuilds the solver at another tier, which clears the fields. Throws on an unknown level.

#magic.setLightsEnabled(on): voidmethod

Shows or hides the glow light and the effects' lights (the spell orbs').

#magic.clear(): voidmethod

Clears velocity, dye and state, the sparks, the in-flight rings and impulses, and the volume's temporal history.

#magic.dispose(): voidmethod

Removes every effect, frees all GPU resources and removes the sparks and the glow light from the scene.

#Effects

#magic.addEffect(type, options?): MagicEffectmethod

type is a key of EFFECT_TYPES: 'portal', 'genieLamp', 'ink', 'spellOrb', 'vortexRing', 'dragonBreath', 'forceField' or 'emitter'. options deep-merge onto the class's defaults; intensity is also accepted. Throws on an unknown type. See Effects and handles.

#magic.addEmitter(options?): EmitterEffectmethod

A generic continuous emitter. See Custom spells.

#magic.impulse(position, direction = [0, 1, 0], color = [0.62, 0.3, 1], opts?): voidmethod

A one-shot burst. opts and their defaults: radius 0.45, speed 0.6, density 26, glow 8, temperature 0.2, fuel 0, expansion 0.35 (radial blast), duration 0.16, sparks true. At most 4 are in flight; a new one drops the oldest.

#magic.getEffect(type): MagicEffect | nullmethod

The first effect of that type.

#magic.removeEffect(handle): voidmethod

Also magic.removeAllEffects().

#Properties

Property
paramsThe current MagicParams. Mutate it directly or use setParams
effectsThe live effect handles
presetNameThe last preset loaded
glowGlowProbe: position, color, power, smoke, light (PointLight), intensity (light gain)
glowLightThe same as glow.light
sparksSparks: enabled, points (the THREE.Points in your scene)
solverFluidSolver: NX NY NZ H min max, fields { velocity, state, dye, light }, toGrid(v)
stats{ grid, voxels, steps, quality, label, glowPower, glowColor, smoke, effects } for HUDs
quality, qualitySettingsThe tier name and its settings
domain{ min: Vector3, width }
timeSimulation time (s), after the speed control
uniformsThe shared uniform block (advanced)

#Effect handles

Every effect extends MagicEffect. The per-effect options are on the guide pages: portal and spellOrb, genieLamp and vortexRing, dragonBreath, ink and forceField, emitter.

#effect.move(position): thismethod

Sets the position. InkEffect moves its whole tank (its position is the tank centre). ForceFieldEffect pauses its wander path for wander.holdTime.

#effect.retarget(direction | { target }): thismethod

Aims direction or axis. GenieLampEffect and EmitterEffect turn velocity and keep its speed. Effects without a direction ignore it.

#effect.setColor(color | null): thismethod

Overrides every dye colour of the effect; null restores its palette.

#effect.setIntensity(k): thismethod

Scales glow, density and spark rate. Clamped at 0.

#effect.set(partialOptions): thismethod

Deep-merges options live, with colours normalised.

#effect.remove(): voidmethod

Removes it from the system and frees its meshes and lights.

#effect.toJSON(): { type, options, intensity? }method

The preset form. intensity is omitted when it's 1.

Member
type, options, enabled, intensityenabled = false pauses it and hides its meshes
positionA copy of the current position
colorOverrideThe setColor() value, or null
systemThe owning MagicSystem

#Effect-specific members

ClassMembers
PortalEffectcolors (getter: the colours in effect)
GenieLampEffectpuff(), rings
InkEffectdrop(position?, color?)
SpellOrbEffectorbs[i].position, orbs[i].color, meshes, lights
VortexRingEffectfire(overrides?), rings (TravellingRing[])
DragonBreathEffectcolor, strength (getters)
ForceFieldEffectvelocity, pickTarget, mesh

#Writing an effect

Subclass MagicEffect, give it static defaults, push sources in update(t, dt, frame) and register it in EFFECT_TYPES. The optional hooks are onReset(), onDisabled() and dispose(). See Custom spells.

#Other exports

Export
PRESETS{ portal, genieLamp, ink, spellOrbs, vortexRings, dragonBreath, forceField }
getPresetParams(nameOrPartial)A deep-cloned DEFAULT_PARAMS merged with the preset, including its effects array
DEFAULT_PARAMSSee Parameters
QUALITY_LEVELS{ n, steps, scale, jacobi, lsteps, fsteps, maccormack, label } per tier. See Quality levels
EFFECT_TYPESType name → effect class. Add your own
LIMITS{ emitters: 8, impulses: 4, rings: 4, swirls: 2, spawners: 4 } (frozen)
TravellingRingThe state of one ring in flight: center, axis, age, alive, step(dt, intensity)
patchReflectiveFloor(material, { strength = 1, roughnessScale = 1.25 }?)Makes the material write the reflection mask. Returns the strength uniform { value }. See reflections

#FluidSolver

MagicSystem owns one. Use it directly only for a custom renderer.

#new FluidSolver(renderer, pass, uniforms, qualitySettings, domain)class

The dye-carrying solver on an N × 1.5N × N grid stored as a 2D atlas. step() advances it by the shared dt uniform, reset() clears it, fields returns the current velocity, state, dye and light textures, toGrid(v) converts world to grid coordinates, defines holds the GLSL layout defines for your own samplers, and dispose() frees it.