webaudio
sandbox
What this shows
Three flat-shaded spheres carry positional sound sources over a grid; click to start the audio, then walk with WASD and drag to look while each sphere glows with its sound's loudness.
Side by side with the three.js r186 original: webaudio_sandbox.html
Differences from three.js
- Both sides start with the scene already rendered and build the audio graph on the first click on their own canvas, instead of waiting for the upstream START button; cleanup stops every source and closes that side's AudioContext.
- The upstream music tracks 358232 and 376737 are CC BY-NC-SA and are not copied, so both sides substitute generated audio: a sawtooth pulsing twice a second on the first sphere and a fast square beat on the second, built from OscillatorNode and GainNode.
- The CC0 Project_Utopia ambience is also replaced by a generated slow triangle swell, because the asset was not copied into this repository; it plays as a node source instead of a looping media element.
- The generated sources start at once and never end, where the two upstream songs play through once.
- EASEL has no Phong material, so the spheres use flat-shaded LambertMaterial without specular.
- EASEL's AudioAnalyzer takes an AudioContext and options, so the port creates one per sphere with fftSize 32 and attaches it to that sound's output, where three.js passes the sound to AudioAnalyser.
- EASEL FogExp2 evaluates fog per vertex from a lookup table, so the fog fades across each face instead of per pixel.
Loading scene…Key API excerpt
Key API excerpt
import * as EASEL from "@xsyetopz/easel";
canvas.addEventListener("click", () => {
const context = new AudioContext();
EASEL.setAudioContext(context);
const listener = new EASEL.AudioListener();
camera.add(listener);
const sound = new EASEL.PositionalAudio(listener);
const oscillator = context.createOscillator();
oscillator.start(0);
sound.setNodeSource(oscillator);
sound.refDistance = 20;
sound.volume = 0.5;
mesh.add(sound);
analyser = new EASEL.AudioAnalyzer(context, { fftSize: 32 }).attach(sound.output);
});
material.emissive.b = analyser.averageFrequency / 256;
controls.update(timer.update(timestamp).delta);
renderer.prepare(scene, camera);
renderer.render(scene, camera);