preload()
preload() runs before setup() and is the perfect place to load assets and pre-compute expensive operations like maze generation. Tone.js instruments must be created before Tone.start() is called, which happens when the user interacts with the page.
function preload() {
ambientSynth = new Tone.PolySynth(Tone.Synth, {
oscillator: {
type: "sawtooth"
},
envelope: {
attack: 2,
decay: 1,
sustain: 1,
release: 2
},
volume: -15
}).toDestination();
monsterGrowl = new Tone.Player({
url: "https://p5js.org/assets/files/sound/monster.mp3",
volume: -10,
playbackRate: 0.8
}).toDestination();
mazeData = generateMaze(MAZE_SIZE, MAZE_SIZE);
playerPosGrid = mazeData.playerStart;
monsterPosGrid = mazeData.monsterStart;
exitPosGrid = mazeData.exitPos;
}
Line-by-line explanation (6 lines)
🔧 Subcomponents:
ambientSynth = new Tone.PolySynth(Tone.Synth, { oscillator: { type: "sawtooth" }, envelope: { attack: 2, decay: 1, sustain: 1, release: 2 }, volume: -15 }).toDestination();
Creates a synthesizer that plays unsettling chords with a slow, eerie envelope—the 2-second attack makes notes fade in spookily
monsterGrowl = new Tone.Player({ url: "https://p5js.org/assets/files/sound/monster.mp3", volume: -10, playbackRate: 0.8 }).toDestination();
Loads a sound file and slows it down (0.8x speed) to make it sound more menacing and low-pitched
mazeData = generateMaze(MAZE_SIZE, MAZE_SIZE);
Generates the entire maze structure, player start position, monster start position, and exit location before setup() runs
ambientSynth = new Tone.PolySynth(Tone.Synth, {...}).toDestination();- Creates a polyphonic synthesizer (can play multiple notes at once) with a sawtooth oscillator and a slow envelope (2 seconds to attack, fade, sustain, and release). The -15 volume keeps it quiet so it doesn't overwhelm other sounds.
monsterGrowl = new Tone.Player({...}).toDestination();- Loads an audio file from a URL and plays it through Tone's audio graph. The playbackRate of 0.8 stretches the sound slower, making it deeper and more threatening.
mazeData = generateMaze(MAZE_SIZE, MAZE_SIZE);- Calls the maze generation function before p5's setup() to pre-compute the level. This must happen early so setup() can use the maze data to create 3D geometry.
playerPosGrid = mazeData.playerStart;- Stores the player's starting grid position (row and column) so setup() can place the camera there.
monsterPosGrid = mazeData.monsterStart;- Stores the monster's starting grid position so setup() can create the monster mesh in the right spot.
exitPosGrid = mazeData.exitPos;- Stores the exit's grid position so the game can check if the player reaches it and wins.