JSFXR is a small JavaScript port of the sfxr tool that was originally written for a game jam. Its purpose is narrow: it generates short retro game sounds from a fixed set of parameters, and it can be embedded in a web page in a few lines of code. That narrowness is the point. There is no arrangement, no effects chain, no automation. There are a handful of sliders that shape a waveform, and the result is either a usable retro sound or it is not.
This article walks through the JSFXR parameter set and what each control does, then builds three specific sounds with it: a coin, a jump, and a laser. The design logic behind those sounds is covered in How to Make 8-Bit Sound Effects and How to Create a Coin Sound Effect, and this article is about the specific controls that JSFXR exposes to get there.
What JSFXR Is and What It Is Not
JSFXR is a sound generator, not an audio editor. It does not record, import, layer, or process audio from other sources. Every sound it produces is synthesized from its own parameters at the moment the user clicks Play or Export.
It is also designed specifically for retro-style sounds. The parameter set is small and the resulting waveforms are simple, which makes it well suited to a coin, jump, laser, hit, power-up or explosion in a retro style. It is a poor fit for realistic impacts, ambient audio, or anything that needs multiple layers.
The original sfxr was created by Tomas Pettersson for the Ludum Dare game jam. JSFXR is a JavaScript port of that tool, and it has been used in a large number of browser-based games and game tutorials since. The parameter set has remained stable across versions.
The Parameter Set
JSFXR exposes roughly a dozen parameters. They fall into four groups: the waveform, the pitch envelope, the amplitude envelope, and the optional vibrato and arpeggio controls.
- Wave type. The basic oscillator. JSFXR offers square, sawtooth, sine and noise. Square is the default for most retro sounds; noise is used for impacts and explosions.
- Attack time. How long the sound takes to reach full volume. Retro effects usually use a very short attack, often 0.
- Sustain time. How long the sound holds at its peak level before the decay begins.
- Sustain punch. An extra boost at the start of the sustain phase, which adds a percussive quality.
- Decay time. How long the sound fades out after the sustain phase.
- Start frequency. The pitch the sound begins at.
- Min frequency. The pitch the sound slides toward. If this matches the start frequency, there is no pitch slide.
- Slide. The speed at which the pitch moves from start frequency to min frequency.
- Delta slide. A change in the slide speed over the duration of the sound, which can create accelerating or decelerating pitch movement.
- Vibrato depth and speed. A small oscillation in pitch, which can add a wobble or instability.
- Change amount and change speed. A slow variation in pitch over the duration of the sound, used for longer effects like power-ups.
- Repeat speed. The rate at which the sound restarts, used for arpeggios and repeating notes.
- Square duty. The width of the square wave. Lower values sound thinner and more nasal.
- Phaser offset and sweep. A modulation that adds a metallic or sweeping quality to the sound.
Not every parameter is used in every sound. A coin, for example, uses only a handful of them. The rest stay at zero or at their default values.
Building a Coin with JSFXR
The coin is the simplest of the three examples. It is a short tonal sound with a slight upward pitch movement at the end. The parameter values below are a starting point; the exact numbers matter less than the relationships between them.
- Wave type. Square.
- Attack time. 0. The sound starts immediately.
- Sustain time. Around 0.05. Short enough to keep the coin brief.
- Decay time. Around 0.1. The sound should be gone within about 150 milliseconds.
- Start frequency. Around 0.55. This is JSFXR's normalized frequency scale; the exact pitch depends on the implementation.
- Min frequency. Slightly higher than the start frequency. This creates the upward slide that reads as reward.
- Slide. A small positive value. The slide should be fast enough to complete within the sound's duration.
- Square duty. Around 0.35. A narrower duty cycle than 0.5 gives the coin a thinner, more arcade quality.
The result is a single short blip with an upward glide, which is the essential shape of a coin. The two-note structure that the coin sound design article describes can also be produced in JSFXR by using the repeat speed parameter, but the single-glide version is what most people recognize as a classic 8-bit coin.
Building a Jump with JSFXR
The jump sound uses a longer pitch slide than the coin, and the direction of movement is the defining characteristic. The sound should rise quickly in pitch and cut off while still climbing.
- Wave type. Square.
- Attack time. 0.
- Sustain time. Around 0.1. Slightly longer than the coin, so the upward slide has room to register.
- Decay time. Around 0.08. The sound should end quickly once the sustain finishes.
- Start frequency. Around 0.35.
- Min frequency. Around 0.85. A wide range is what makes the jump feel like an upward launch.
- Slide. A moderate positive value. The pitch should move noticeably over the duration of the sound, not instantly.
- Square duty. Around 0.5. The fuller duty cycle gives the jump a bit more presence than the coin.
The jump sound is essentially a coin with a much larger pitch range and a slightly longer duration. This is a common pattern in JSFXR: the parameters overlap, and the difference between two sounds is usually one or two values.
Building a Laser with JSFXR
The laser is the opposite of the jump. It uses a fast downward pitch slide and a very short duration. The synthesizer techniques behind a laser sound are covered in more detail in How to Make Laser and Sci-Fi Sound Effects with Synthesizers, and the same principles apply here.
- Wave type. Square or sawtooth. Sawtooth is slightly harsher and more "energy weapon"; square is slightly thinner and more "arcade".
- Attack time. 0.
- Sustain time. Around 0.03. Very short. A laser should feel like a single burst, not a tone.
- Decay time. Around 0.05.
- Start frequency. Around 0.9. High starting pitch is essential for the laser character.
- Min frequency. Around 0.3. The pitch should drop sharply.
- Slide. A high negative value. The downward sweep is fast and complete within the sound's short duration.
- Square duty. Around 0.25. A narrow duty cycle gives the laser a thinner, more electronic quality.
The laser is the fastest of the three sounds, and the easiest to get wrong by making it too long. If the sustain or decay values are increased beyond these ranges, the laser starts to sound like a falling whistle rather than an energy discharge.
How the Three Sounds Relate
Looking at the three parameter sets side by side reveals the pattern that makes JSFXR efficient for retro sound design. The sounds are not built from scratch; they are variations on the same small set of parameters.
- Coin. Short, small upward slide, narrow duty cycle.
- Jump. Short, wide upward slide, fuller duty cycle.
- Laser. Very short, fast downward slide, high start frequency, narrow duty cycle.
The direction of the pitch slide is the primary identifier. Upward for reward and movement, downward for attack. The speed of the slide is the second identifier. Fast downward is a laser; slow upward is a jump.
Once the coin, jump and laser are working, the rest of the common retro sound set is built from the same parameters with different values. A hit sound is a laser with a longer decay and a noise layer. A power-up is a coin with a longer sustain and a repeating pitch change. An explosion is a noise waveform with a fast attack and a long decay.
Using JSFXR in a Browser Game
JSFXR can be embedded directly in a web page. The library exposes a function to generate a sound from a parameter object, and a function to play or export it. The generated audio is produced through the Web Audio API, so it plays immediately in the browser without requiring a separate audio file.
For a browser game, this means the retro sound set can be generated at load time and held in memory, rather than downloaded as WAV files. A full retro sound set from JSFXR is only a few hundred bytes of parameters, compared to hundreds of kilobytes of WAV data.
The sounds can also be exported as WAV files if the game needs to ship them as assets, either for a browser game that prefers pre-rendered audio or for a traditional engine that cannot run JavaScript. The JSFXR interface usually provides an export button for this purpose.
One limitation worth knowing is that JSFXR sounds are single-voice and single-layer. A laser made in JSFXR cannot have a separate noise layer underneath the oscillator, because the tool only produces one waveform at a time. For layered sounds, either combine multiple JSFXR outputs in a separate tool, or use a different generator.
Comparison with a Full Synthesizer
JSFXR and a full synthesizer are solving different problems. A synthesizer gives you arbitrary waveforms, filter envelopes, modulation routing and effects. JSFXR gives you a fixed parameter set and a fast path from "I need a coin sound" to having one.
For a game that needs five or six retro sounds and no more, JSFXR is faster than any other approach. For a game that needs layered weapon effects, filtered impacts or procedural variation, a synthesizer or a generator like the ones covered in the free sound effect generator comparison is a better fit.
The two approaches can also be combined. A JSFXR sound can be exported as a WAV and then processed in Audacity for cleanup or layering. The workflow for that is covered in How to Use Audacity to Make Game Sound Effects.
A Starting Parameter Set to Copy
For anyone who wants a working starting point rather than tuning from scratch, these three parameter sets produce recognizable coin, jump and laser sounds in JSFXR. The values are on JSFXR's normalized scale, where most parameters range from 0 to 1.
Coin:
wave_type: square
attack: 0
sustain: 0.05
decay: 0.10
start_freq: 0.55
min_freq: 0.60
slide: 0.02
square_duty: 0.35
Jump:
wave_type: square
attack: 0
sustain: 0.10
decay: 0.08
start_freq: 0.35
min_freq: 0.85
slide: 0.15
square_duty: 0.50
Laser:
wave_type: saw
attack: 0
sustain: 0.03
decay: 0.05
start_freq: 0.90
min_freq: 0.30
slide: -0.30
square_duty: 0.25
These are not final values, and small adjustments to each parameter produce noticeably different results. The coin, for example, becomes noticeably brighter if the start frequency is raised, and noticeably duller if the square duty cycle is widened.
Compare with a Browser Generator
Open the SfxMaker generator and create the same coin, jump or laser, then compare the result against the JSFXR version to see how the parameter sets differ.
Open SfxMaker Generator →Common Mistakes
- Making the sounds too long. Retro effects are short by design. If a coin, jump or laser lasts longer than about 200 milliseconds, it stops feeling like a retro sound.
- Using the wrong slide direction. Upward slides read as reward or upward motion. Downward slides read as attack. Reversing them makes the sound feel wrong without an obvious reason why.
- Ignoring the square duty cycle. A duty cycle of 0.5 sounds neutral. A narrower duty cycle (around 0.25 to 0.35) is what gives retro sounds their characteristic thin, nasal quality.
- Trying to layer inside JSFXR. The tool produces single-voice sounds. Layering requires an external editor.
- Using the same settings for every sound. The parameter set is small, and it is easy to accidentally produce the same sound twice. Check the slide direction and the frequency range before assuming the settings are different.
What to Check Before Using the Sounds
Listen to the JSFXR sounds in the context of the game, not just in the generator's preview. A coin that sounds correct in isolation can be too bright against music, and a laser that sounds impactful in the preview can become fatiguing when fired dozens of times in a minute.
Also check the levels. JSFXR sounds are not normalized, and two sounds generated with the same amplitude settings can have noticeably different perceived volumes. Adjust the levels in the game engine rather than regenerating the sounds.
The JSFXR parameter set is small enough to learn in an afternoon, and the three example sounds here are a reasonable starting point for a full retro sound set. Once the coin, jump and laser are tuned, the remaining sounds in a typical retro game are variations on the same parameters rather than entirely new designs.