Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/kepabilbao67-bot/musicplayer2/llms.txt

Use this file to discover all available pages before exploring further.

NEON DJ is built entirely inside a single index.html file of approximately 75 KB. There are no build tools, no npm packages, no bundler, and no external JavaScript dependencies loaded at startup — you can open the file directly in any modern browser and the full DJ mixer is immediately available. This document explains how the file is structured internally and how its three logical sections work together.

File Structure Overview

The file is divided into three distinct sections that map directly to HTML’s natural layers:
index.html
├── <style>        CSS design tokens, layout, component styles
├── <body>         HTML markup (header, .console grid, deck panels, mixer)
└── <script>
    ├── Utilities         midiToFreq, clamp, formatTime
    ├── Audio context     AC(), masterNode()
    ├── Synth functions   synthKick, synthSnare, synthBass, etc.
    ├── Track generator   generateTrack(def)
    ├── FX functions      fxRiser, fxAirhorn, flangerThrow, etc.
    ├── encodeWAV         PCM → WAV blob encoder
    ├── Deck class        all per-deck state + Web Audio nodes
    └── Init code         deck setup, event listeners, keyboard handler
The <style> block comes first and contains all visual design tokens, layout rules, and component styles. The <body> defines the static HTML skeleton — header, the three-column .console grid, both deck panels, the central mixer, and the FX bar at the bottom. The <script> block at the end of <body> contains every piece of application logic.

CSS Design Tokens

All colours and surface values are declared as CSS custom properties on :root, making the entire visual theme easy to adjust from a single location:
:root {
  --bg:      #0a0c12;   /* page background            */
  --panel:   #141824;   /* card/panel surface          */
  --panel-2: #1b2130;   /* slightly lighter panel      */
  --line:    #2a3142;   /* borders and dividers        */
  --text:    #e8eef7;   /* primary text                */
  --muted:   #79839a;   /* secondary / label text      */
  --a:       #ff3d7f;   /* Deck A accent — magenta     */
  --b:       #21d4fd;   /* Deck B accent — cyan        */
  --accent:  #b06bff;   /* global purple accent        */
  --good:    #2fe6a0;   /* positive / active states    */
}
These tokens are consumed throughout the stylesheet and also read at runtime from JavaScript (for waveform canvas drawing) via getComputedStyle.

Layout: Three-Column CSS Grid

The main .console element uses a three-column CSS Grid to place Deck A, the central mixer, and Deck B side by side:
.console {
  display: grid;
  grid-template-columns: 1fr 240px 1fr;
  gap: 14px;
  max-width: 1180px;
  margin: 0 auto;
}

@media (max-width: 880px) {
  .console { grid-template-columns: 1fr; }
}
At viewports of 880 px or narrower, the grid collapses to a single column so the decks and mixer stack vertically for mobile use.

Key Global Objects

The JavaScript section is built around a small set of global objects and instances:

audioCtx

The singleton AudioContext (or webkitAudioContext) created lazily on the first user gesture via the AC() helper function. Never instantiated at script parse time.

masterGain

A GainNode that receives both deck outputs. Its gain value is set by the master volume slider (default 0.85).

masterLimiter

A DynamicsCompressorNode connected after masterGain. Prevents clipping when multiple elements play simultaneously (threshold −3 dB, ratio 20:1).

masterFlangerWet / masterEchoWet

GainNodes that control the wet level of the master flanger and echo send effects. Both start at gain 0 and are ramped up momentarily by flangerThrow() and echoThrow().

deckA / deckB

Instances of the Deck class. Each encapsulates its own Web Audio graph, UI element references, playback state, EQ nodes, filter, delay send, and reverb send.

FX object

A plain object mapping effect names (riser, airhorn, impact, zap, flanger, brake, echo) to their trigger functions. Used by the FX pad buttons and keyboard shortcuts.

The Deck Class

The Deck class is the core abstraction. Each instance is constructed with a reference to its root DOM element, a colour string ("a" or "b"), and a getter for the other deck (used for SYNC). The constructor:
  1. Stores playback state (buffer, offset, rate, isPlaying, loopActive, hot cue positions).
  2. Queries and caches all relevant DOM elements by data-role attribute.
  3. Calls buildGraph() to create and connect all Web Audio nodes for that deck.
  4. Calls bind() to attach all event listeners (transport buttons, knobs, vinyl jog, waveform click).

The FX Object

Effect trigger functions are collected into a single FX map:
const FX = {
  riser:   fxRiser,
  airhorn: fxAirhorn,
  impact:  fxImpact,
  zap:     fxZap,
  flanger: flangerThrow,
  echo:    echoThrow,
  brake:   brakeAll
};
FX pad buttons read btn.dataset.fx and look up the function: FX[btn.dataset.fx](). The keyboard handler maps number keys 17 to the same functions.

Initialization Flow

1

Page Load

The browser parses and executes the <script> block. No audio is created yet — AudioContext is not instantiated.
2

Track Generation

init() is called immediately. It iterates over all genre definitions in TRACKS and calls generateTrack(def) for each, rendering every track offline using OfflineAudioContext. A progress bar is shown during this phase.
3

Deck Construction

After all buffers are ready, deckA and deckB are instantiated. Both call AC() for the first time, which creates the shared AudioContext and the master node chain.
4

Default Tracks Loaded

House is loaded into Deck A and Techno into Deck B. Previously saved settings are restored from localStorage.
5

Animation Loop

loopAnim() is called, starting a requestAnimationFrame loop that redraws waveforms, rotates the vinyl, updates VU meters, draws the spectrum analyser, and flashes the beat LED.
The single-file architecture makes NEON DJ trivially easy to share — send one file, open in a browser, done. The trade-off is maintainability at scale: all CSS, markup, and logic live in one 1,500-line document with no module boundaries, no type checking, and no hot-module reload. For a personal tool or creative demo this is an excellent choice; for a production app maintained by a team, splitting into modules would be preferable.

Build docs developers (and LLMs) love