Pen Settings

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. If you link to another Pen, it will include the CSS from that Pen. If the preprocessor matches, it will attempt to combine them before processing.

+ add another resource

You're using npm packages, so we've auto-selected Babel for you here, which we require to process imports and make it all work. If you need to use a different JavaScript preprocessor, remove the packages in the npm tab.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Use npm Packages

We can make npm packages available for you to use in your JavaScript. We use webpack to prepare them and make them available to import. We'll also process your JavaScript with Babel.

⚠️ This feature can only be used by logged in users.

Code Indentation

     

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

HTML Settings

Here you can Sed posuere consectetur est at lobortis. Donec ullamcorper nulla non metus auctor fringilla. Maecenas sed diam eget risus varius blandit sit amet non magna. Donec id elit non mi porta gravida at eget metus. Praesent commodo cursus magna, vel scelerisque nisl consectetur et.

            
              
#container

#warning1.message

  %h1
    This experiment requires the
    %a{ href:'https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html', target:'_blank' } Web Audio API
  %h2
    Please try in one of
    %a{ href:'http://caniuse.com/#feat=audio-api', target:'_blank' } these browsers

#warning2.message

  %h1
    Safari users. You may hear audio but see no visuals. This is due to
    %a{ href:'https://goo.gl/6WLx1', target:'_blank' } this bug
    in Safari 6

#intro.message

  %h1 Simple music visualiser
  %h2 Loading audio&hellip;
            
          
!
            
              @import compass

@import url( https://fonts.googleapis.com/css?family=Lato:400,700 )

html, body
  
  font-family: 'Lato', sans-serif
  background: #13242f
  overflow: hidden
  
#container
  
  &:before
    
    @include background-image( radial-gradient( center, ellipse cover, rgba(0,0,0,0) 20%, rgba(0,0,0,1) 95% ) )
    position: absolute
    content: ''
    z-index: 0
    opacity: 0.9
    height: 100%
    width: 100%
    left: 0
    top: 0
  
  &:after
    
    background: url( 'https://s.cdpn.io/1715/noise-1.png' )
    position: absolute
    content: ''
    z-index: 1
    opacity: 0.8
    height: 100%
    width: 100%
    left: 0
    top: 0
    
audio
  
  position: absolute
  z-index: 2
  right: 0
  top: 0
  
.message
  
  $height: 60px
  $width: 360px
  
  box-shadow: 0 2px 4px rgba(0,0,0,0.2)
  text-transform: uppercase
  border-radius: 3px
  text-align: center
  line-height: 1.2
  background: rgba(0,0,0,0.8)
  position: absolute
  margin-left: $width * -0.5
  margin-top: $height * -0.5
  font-size: 13px
  padding: 20px
  display: none
  z-index: 3
  height: $height
  width: $width
  color: #fff
  left: 50%
  top: 50%
  
  h1, h2
    
    font-weight: 300
    margin: 10px 0
    
    a
      
      text-decoration: none
      font-weight: 700
      color: #1B676B
      
#intro
  
  display: block
            
          
!
            
              ###

  Music is by The XX
  @see http://thexx.info

  This is best viewed in Chrome since there is a bug in Safari
  when using getByteFrequencyData with MediaElementAudioSource

  @see https://goo.gl/6WLx1

###

# Config

NUM_PARTICLES = 150
NUM_BANDS = 128
SMOOTHING = 0.5
MP3_PATH = 'https://api.soundcloud.com/tracks/42328219/stream?client_id=b1495e39071bd7081a74093816f77ddb'

SCALE = MIN: 5.0,  MAX: 80.0
SPEED = MIN: 0.2,   MAX: 1.0
ALPHA = MIN: 0.8,   MAX: 0.9
SPIN  = MIN: 0.001, MAX: 0.005
SIZE  = MIN: 0.5,   MAX: 1.25

COLORS = [
  '#69D2E7'
  '#1B676B'
  '#BEF202'
  '#EBE54D'
  '#00CDAC'
  '#1693A5'
  '#F9D423'
  '#FF4E50'
  '#E7204E'
  '#0CCABA'
  '#FF006F'
]

# Audio Analyser

class AudioAnalyser
  
  @AudioContext: self.AudioContext or self.webkitAudioContext
  @enabled: @AudioContext?
  
  constructor: ( @audio = new Audio(), @numBands = 256, @smoothing = 0.3 ) ->
  
    # construct audio object
    if typeof @audio is 'string'
      src = @audio
      @audio = new Audio()
      @audio.crossOrigin = "anonymous"
      @audio.controls = yes
      @audio.src = src
  
    # setup audio context and nodes
    @context = new AudioAnalyser.AudioContext()
    
    # createScriptProcessor so we can hook onto updates
    @jsNode = @context.createScriptProcessor 2048, 1, 1
    
    # smoothed analyser with n bins for frequency-domain analysis
    @analyser = @context.createAnalyser()
    @analyser.smoothingTimeConstant = @smoothing
    @analyser.fftSize = @numBands * 2
    
    # persistant bands array
    @bands = new Uint8Array @analyser.frequencyBinCount

    # circumvent http://crbug.com/112368
    @audio.addEventListener 'canplay', =>
    
      # media source
      @source = @context.createMediaElementSource @audio

      # wire up nodes

      @source.connect @analyser
      @analyser.connect @jsNode

      @jsNode.connect @context.destination
      @source.connect @context.destination

      # update each time the JavaScriptNode is called
      @jsNode.onaudioprocess = =>

        # retreive the data from the first channel
        @analyser.getByteFrequencyData @bands
        
        # fire callback
        @onUpdate? @bands if not @audio.paused
        
  start: ->
  
    @audio.play()
    
  stop: ->
  
    @audio.pause()
    
# Particle

class Particle
  
  constructor: ( @x = 0, @y = 0 ) ->

    @reset()
    
  reset: ->
  
    @level = 1 + floor random 4
    @scale = random SCALE.MIN, SCALE.MAX
    @alpha = random ALPHA.MIN, ALPHA.MAX
    @speed = random SPEED.MIN, SPEED.MAX
    @color = random COLORS
    @size = random SIZE.MIN, SIZE.MAX
    @spin = random SPIN.MAX, SPIN.MAX
    @band = floor random NUM_BANDS
    
    if random() < 0.5 then @spin = -@spin
    
    @smoothedScale = 0.0
    @smoothedAlpha = 0.0
    @decayScale = 0.0
    @decayAlpha = 0.0
    @rotation = random TWO_PI
    @energy = 0.0
    
  move: ->
  
    @rotation += @spin
    @y -= @speed * @level
    
  draw: ( ctx ) ->
    
    power = exp @energy
    scale = @scale * power
    alpha = @alpha * @energy * 1.5
    
    @decayScale = max @decayScale, scale
    @decayAlpha = max @decayAlpha, alpha
    
    @smoothedScale += ( @decayScale - @smoothedScale ) * 0.3
    @smoothedAlpha += ( @decayAlpha - @smoothedAlpha ) * 0.3
    
    @decayScale *= 0.985
    @decayAlpha *= 0.975
  
    ctx.save()
    ctx.beginPath()
    ctx.translate @x + cos( @rotation * @speed ) * 250, @y
    ctx.rotate @rotation
    ctx.scale @smoothedScale * @level, @smoothedScale * @level
    ctx.moveTo @size * 0.5, 0
    ctx.lineTo @size * -0.5, 0
    ctx.lineWidth = 1
    ctx.lineCap = 'round'
    ctx.globalAlpha = @smoothedAlpha / @level
    ctx.strokeStyle = @color
    ctx.stroke()
    ctx.restore()
    
# Sketch
    
Sketch.create

  particles: []
  
  setup: ->
    
    # generate some particles
    for i in [0..NUM_PARTICLES-1] by 1
      
      x = random @width
      y = random @height * 2
      
      particle = new Particle x, y
      particle.energy = random particle.band / 256
      
      @particles.push particle
      
    if AudioAnalyser.enabled
      
      try

        # setup the audio analyser
        analyser = new AudioAnalyser MP3_PATH, NUM_BANDS, SMOOTHING

        # update particles based on fft transformed audio frequencies
        analyser.onUpdate = ( bands ) => particle.energy = bands[ particle.band ] / 256 for particle in @particles
        
        # start as soon as the audio is buffered
        analyser.start();
      
        # show audio controls
        document.body.appendChild analyser.audio
        
        intro = document.getElementById 'intro'
        intro.style.display = 'none'
        
        # bug in Safari 6 when using getByteFrequencyData with MediaElementAudioSource
        # @see https://goo.gl/6WLx1
        if /Safari/.test( navigator.userAgent ) and not /Chrome/.test( navigator.userAgent )
        
          warning = document.getElementById 'warning2'
          warning.style.display = 'block'

      catch error
      
    else
      
      # Web Audio API not detected
      warning = document.getElementById 'warning1'
      warning.style.display = 'block'
    
  draw: ->
  
    @globalCompositeOperation = 'lighter'
  
    for particle in @particles
      
      # recycle particles
      if particle.y < -particle.size * particle.level * particle.scale * 2
        
        particle.reset();
        particle.x = random @width
        particle.y = @height + particle.size * particle.scale * particle.level
      
      particle.move()
      particle.draw @
            
          
!
999px
🕑 One or more of the npm packages you are using needs to be built. You're the first person to ever need it! We're building it right now and your preview will start updating again when it's ready.

Console