             info =
                 key: key
                 velocity: message[2]
-                timestamp: midiTime
+                timestamp: clock()
 
             # Split keyboard into particles and LFOs
             if key >= 60

        when 0xb0  # Voice 0, Control Change
            switch message[1]
                when 7   # "Data entry" slider, brightness
                    brightness = message[2] * 3.0 / 127

                when 1   # "Modulation" slider, particle speed
                    particleLifetime = 0.1 + message[2] * 2.0 / 127

    for p in particles

        # Angle: Global spin, thne positional mapping to key
        theta = midiToAngle p.note.key

        # Radius: Particles spawn in center, fly outward
        radius = 3.0 * (1 - p.life)

        # Positioned in polar coordinates
        x = radius * Math.cos theta
        y = radius * Math.sin theta

        # One rainbow per octave
        hue = (p.note.key - 60 + 0.1) / 12.0
        p.color = OPC.hsv hue, 0.3, 0.8

        # Intensity mapped to velocity, nonlinear
        p.intensity = Math.pow(p.note.velocity / 100, 3.0) * 0.25 * brightness

        # Falloff gets sharper as the note gets higher
        p.falloff = 20 + (p.note.key - 60) * 20

        # Add influence of LFOs
        for key, note of lfoNotes
            age = now - note.timestamp
            hz = midiToHz key
            lfoAngle = midiToAngle key

            # Amplitude starts with left hand velocity
            wobbleAmp = Math.pow(note.velocity / 100, 3.0)

            # Scale based on particle fuzziness
            wobbleAmp *= 100.0 / p.falloff

            # Fade over time
            wobbleAmp /= 1 + age

            # Wobble
            wobbleAmp *= Math.sin(p.life * Math.pow(3, (p.note.key - 35) / 12.0))

            # Wobble angle driven by LFO note and particle life
            x += wobbleAmp * Math.cos lfoAngle
            y += wobbleAmp * Math.sin lfoAngle

        # Use the XZ plane
        p.point = [x, 0, y]

        p.life -= timeStep / particleLifetime

