the code

(ns index)

(defn prep-canvas []
  (let [can (js/document.createElement "canvas")
        ctx (.getContext can "2d")
        width js/window.innerWidth
        height js/window.innerHeight]
    (set! can.style "position: absolute; top: 0px; left: 0px;")
    (set! can.width width)
    (set! can.height height)
    (js/document.body.appendChild can)
    {:canvas can
     :context ctx
     :width width
     :height height}))

(defn rand [n]
  (js/Math.floor (* (js/Math.random) n)))

(defn render-snowflake [{:keys [context]} {:keys [x y size]}]
  (set! context.fillStyle "#fff")
  (set! context.font (str size "px serif"))
  (.fillText context "*" x y))

(defn snowflake-step [{:keys [height]} {:keys [x y dy] :as snowflake}]
  (set! snowflake.y (if (> y height) (- 20) (+ y dy)))
  (set! snowflake.x (+ x (- (js/Math.random) 0.5))))

(defn gen-snowflakes [n {:keys [width height]}]
  (->>
   (range n)
   (map
    (fn [_]
      (let [size (+ (rand 10) 2)
            x (rand width)
            y (rand height)]
        {:size size
         :x x
         :y y
         :dy (inc (js/Math.random 10))})))
   (doall)))

(defn animation-loop [step-fn]   
   (step-fn)
   (js/window.requestAnimationFrame (partial animation-loop step-fn)))

(defn draw-text [{:keys [context width height]} text]
  (set! context.fillStyle "#fff")
  (set! context.font "100px serif")
  (context.fillText text (* width 0.3) (* height 2/6) (* width 7/8)))

(defn draw-terrain [{:keys [context width height]} fill growing?]
  (set! context.fillStyle fill)
  (context.beginPath)
  (context.moveTo -500 (if growing? height height))
  (loop [x 0
         y (if growing?
             (- height 100)
             (- height 400))]
    (if (< x width)
      (let [x (+ x (+ 10 (rand 20)))
            y (if growing?
                (- y (rand 10))
                (+ y (rand 10)))]
        (context.lineTo x y)
        (recur x y))
      (context.lineTo (+ x 100) height)))
  (context.fill))

(let [background (prep-canvas)
      text-layer (prep-canvas)
      {:keys [context width height] :as snow} (prep-canvas)
      terrain (prep-canvas)
      snowflakes (gen-snowflakes 800 snow)]
  (background.context.fillRect 0 0 width height)
  (draw-text text-layer "Happy Holidays!")
  (draw-terrain terrain "#fff" true)
  (draw-terrain terrain "#ddd" false)
  (animation-loop
   (fn []
     (set! context.fillStyle "#000")
     (context.clearRect 0 0 width height)
     (doseq [sf snowflakes]
       (render-snowflake snow sf)
       (snowflake-step snow sf)))))