three.js clock

Following the three.js charts post, here’s the clock using three.js:

class ThreeJsClock
  initCSR: ->
    width = 800
    height = 600
    viewAngle = 45
    aspect = width / height
    near = 1
    far = 1000
    
    @camera = new THREE.PerspectiveCamera viewAngle, aspect, near, far
    @camera.position.z = 500
    
    @scene = new THREE.Scene
    @scene.add @camera

    @renderer = new THREE.WebGLRenderer
      antialias: true
      premultipliedAlpha: false
      alpha: true
    @renderer.setSize width, height
    
    canvas = $(@renderer.domElement)
      .attr('id', 'canvas')
      
    $('<div>')
      .append(canvas)
      .appendTo(document.body)
    
  draw: =>
    @render()
    setTimeout(() =>
        requestAnimationFrame @draw
      , 1000 / @fps)

  setHands: =>
    time = new Date()
    
    @handsSep.second.rotation.z = -time.getSeconds() / 60 * 2 * Math.PI
    @handsSep.minute.rotation.z = -time.getMinutes() / 60 * 2 * Math.PI
    @handsSep.hour.rotation.z = -time.getHours() / 12 * 2 * Math.PI
    
  render: =>
    if Math.abs(@group.rotation.y) > Math.PI / 2
      @rot *= -1
    @group.rotation.y += @rot
    
    @setHands()
    @renderer.render @scene, @camera
    
  makeScene: ->
    @group = new THREE.Object3D
    @scene.add @group
        
    @clock = new THREE.Object3D
    @group.add @clock
    
    backGeom = new THREE.CylinderGeometry(
      radiusTop = 200, 
      radiusBottom = 200, 
      height = 10, 
      radiusSegments = 70,
      heightSegments = 70, 
      openEnded = false,
      )
    
    backMat = new THREE.MeshLambertMaterial
      color: 0x80b2ff
      
    backMesh = new THREE.Mesh backGeom, backMat
    backMesh.rotation.x = Math.PI / 2
    @clock.add backMesh
    
    @ticks = new THREE.Object3D
    @clock.add @ticks
    
    tickGeom = new THREE.SphereGeometry(
      radius = 10, 
      widthSegments = 70, 
      heightSegments = 70)
    
    tickMat = new THREE.MeshLambertMaterial
      color: 0xcfcf53
      
    for x in [0..12]
      tickMesh = new THREE.Mesh tickGeom, tickMat
      tickMesh.position.y = 180
      
      dummy = new THREE.Object3D
      dummy.add tickMesh
      dummy.rotation.z = x * Math.PI / 6
      
      @ticks.add dummy

    @hands = new THREE.Object3D
    @clock.add @hands

    handCentGeom = new THREE.SphereGeometry(
      radius = 25, 
      widthSegments = 70, 
      heightSegments = 70)
    
    handCentMat = new THREE.MeshLambertMaterial
      color: 0xffc0c0
    
    handCentMesh = new THREE.Mesh handCentGeom, handCentMat
    @hands.add handCentMesh
      
    makeHand = (hands, len, rad, z) ->
      handGeom = new THREE.CylinderGeometry(
        radiusTop = 1, 
        radiusBottom = rad, 
        height = len, 
        radiusSegments = 70,
        heightSegments = 70, 
        openEnded = false,
        )
      handMat = new THREE.MeshLambertMaterial
        color: 0xffc0c0
        
      handMesh = new THREE.Mesh handGeom, handMat
      handMesh.position.y = len / 2
      handMesh.position.z = z

      dummy = new THREE.Object3D
      dummy.add handMesh
      
      hands.add dummy
      dummy
      
    @handsSep = 
      second: makeHand @hands, 170, 3, 20
      minute: makeHand @hands, 150, 4, 15
      hour: makeHand @hands, 130, 5, 10
            
    @rot = 0.01
    
    directionalLight = new THREE.SpotLight 0xffffff
    directionalLight.position.set 0, 0, 3000
    @scene.add directionalLight
    
  run: ->
    @initCSR()
    @makeScene()
    
    @fps = 15
    @draw()
    
module.exports = ThreeJsClock

Here’s a screenshot:

screenshot