Start here
Installation
NatureGL Magic ships as a folder with a runnable demo, the library source, and a prebuilt ES module with TypeScript declarations. Pick whichever of the three integration paths suits your build.
#Requirements
| three.js | >= 0.180 as a peer dependency. Developed and tested on r186 |
| Renderer | THREE.WebGLRenderer with WebGL2 and EXT_color_buffer_float. Current desktop and mobile browsers have both. No WebGPU needed |
| Camera | THREE.PerspectiveCamera, used by render() and composite() |
| Node | 18 or newer, only for the demo and the build scripts |
MagicSystem throws MagicSystem: WebGL2 + EXT_color_buffer_float required if the extension is missing. The demo checks the same thing up front and shows a fallback message.
#Run the demo first
#Unpack and install
cd naturegl-magic
npm install#Start the dev server
npm run devVite serves port 5187 and opens http://localhost:5187/demo/, a moonlit courtyard with all seven effects. The demo page lists every control. The same server also serves /examples/basic/ and a landing page at /.
#Build or test (optional)
npm run build # build:lib (bundle + .d.ts -> build/), then build:demo (static site -> dist/)
npm test # headless GPU test: every preset -> test-results/*.png + fps
npm run test:examples # opens both examples, fails on errors or warnings#What's in the folder
├── build/prebuilt library: index.js, index.js.map, *.d.ts├── src/library source (no DOM UI, no demo scenery)│ ├── MagicSystem.jsfacade: create, update, render, composite, presets, effects│ ├── core/FluidSolver (atlas grid, MacCormack), GPU helpers, shared uniforms│ ├── render/ScreenPipeline (raymarch, TAA, composite, bloom, grade), Sparks, GlowProbe│ ├── effects/one class per effect + the generic EmitterEffect│ ├── shaders/GLSL as exported template strings (*.glsl.js)│ └── config/QualityLevels, defaults, presets/ (one file per preset)├── demo/full demo: moonlit courtyard and UI├── examples/basic/minimal Vite integration├── examples/cdn/plain JS + import map against build/├── docs/API.mdfull API reference└── scripts/smoke.mjs (headless GPU test), examples.mjs, shoot.mjs
#Add it to your project
Copy build/ into your project, for example as lib/naturegl-magic/, and import from it. three stays an external import, so your bundler or an import map resolves it.
import { MagicSystem } from './lib/naturegl-magic/index.js';The bundle has a source map and .d.ts files next to it, so editors get types and go-to-definition.
src/ is plain ES modules with JSDoc. The shaders are JavaScript strings, so no loader or plugin is needed.
import { MagicSystem } from './vendor/naturegl-magic/index.js';Choose this if you want to read or patch the shaders in place.
Keep the package next to your app and alias it to the source. The demo is wired up the same way.
import { resolve } from 'node:path';
export default {
resolve: {
alias: { 'naturegl-magic': resolve(__dirname, '../naturegl-magic/src/index.js') },
},
};import { MagicSystem } from 'naturegl-magic';#Without a bundler
An import map resolves three from a CDN. The library comes from your copy of build/.
<script type="importmap">
{ "imports": {
"three": "https://cdn.jsdelivr.net/npm/three@0.186.0/build/three.module.js",
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.186.0/examples/jsm/"
} }
</script>
<script type="module">
import * as THREE from 'three';
import { MagicSystem } from './lib/naturegl-magic/index.js'; // a copy of build/
</script>examples/cdn/index.html is a complete page (the three/addons/ entry is there for its OrbitControls). Serve the package root with any static server, such as npx http-server ., and open /examples/cdn/.
#The examples
| Example | Shows |
|---|---|
examples/basic/ | The Vite alias path: a portal preset, a custom orange addEmitter() flame, click-to-cast impulse(), a live portal.move() every frame and a floor patched with patchReflectiveFloor() |
examples/cdn/ | No bundler: preset: null, then loadPreset('spellOrbs') plus an extra vortexRing. The system is on window.magic so you can try the API from the console |
npm run test:examples opens both on the real GPU, clicks once, saves test-results/examples-basic.png and examples-cdn.png, and exits non-zero on any page error, console error or warning. The CDN example imports build/, so run npm run build:lib after changing src/.