diff --git a/Setup.hs b/Setup.hs
--- a/Setup.hs
+++ b/Setup.hs
@@ -1,5 +1,5 @@
 {-
-  Copyright 2019 The CodeWorld Authors. All rights reserved.
+  Copyright 2020 The CodeWorld Authors. All rights reserved.
 
   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
diff --git a/codeworld-api.cabal b/codeworld-api.cabal
--- a/codeworld-api.cabal
+++ b/codeworld-api.cabal
@@ -1,11 +1,11 @@
 Name:                codeworld-api
-Version:             0.6.0
+Version:             0.7.0
 Synopsis:            Graphics library for CodeWorld
 License:             Apache
 License-file:        LICENSE
 Author:              The CodeWorld Authors
 Maintainer:          Chris Smith <cdsmith@gmail.com>
-Copyright:           (c) 2019, The CodeWorld Authors
+Copyright:           (c) 2020, The CodeWorld Authors
 Bug-reports:         https://github.com/google/codeworld/issues
 Build-type:          Simple
 Cabal-version:       >=1.10
@@ -56,13 +56,13 @@
                        deepseq              >= 1.4   && < 1.5,
                        dependent-sum        >= 0.4   && < 0.6.2,
                        ghc-prim             >= 0.3.1 && < 0.6,
-                       hashable             >= 1.2.4 && < 1.3,
+                       hashable             >= 1.2.4 && < 1.4,
                        monad-loops          >= 0.3   && < 0.5,
                        mtl                  >= 2.2.1 && < 2.3,
                        random               >= 1.1   && < 1.2,
                        ref-tf               >= 0.4   && < 0.5,
                        reflex               >= 0.6.3 && < 0.7,
-                       template-haskell     >= 2.8   && < 2.15,
+                       template-haskell     >= 2.8   && < 2.16,
                        text                 >= 1.2.2 && < 1.3,
                        time                 >= 1.8   && < 2.0,
                        witherable           >= 0.3   && < 0.4
@@ -73,11 +73,11 @@
                        ghcjs-prim,
                        codeworld-game-api,
                        codeworld-prediction,
-                       ghcjs-dom             >= 0.8 && < 0.9,
+                       ghcjs-dom             >= 0.9 && < 0.9.4,
                        transformers
   else
     Build-depends:     blank-canvas          >= 0.6 && < 0.8,
-                       time                  >= 1.6.0 && < 1.9
+                       time                  >= 1.8 && < 2.0
 
   Ghc-options:         -O2 -Wall
   if flag(strictbuild)
@@ -117,13 +117,13 @@
                        deepseq              >= 1.4   && < 1.5,
                        dependent-sum        >= 0.4   && < 0.6.2,
                        ghc-prim             >= 0.3.1 && < 0.6,
-                       hashable             >= 1.2.4 && < 1.3,
+                       hashable             >= 1.2.4 && < 1.4,
                        monad-loops          >= 0.3   && < 0.5,
                        mtl                  >= 2.2.1 && < 2.3,
                        random               >= 1.1   && < 1.2,
                        ref-tf               >= 0.4   && < 0.5,
                        reflex               >= 0.6.3 && < 0.7,
-                       template-haskell     >= 2.8   && < 2.15,
+                       template-haskell     >= 2.8   && < 2.16,
                        text                 >= 1.2.2 && < 1.3,
                        time                 >= 1.8   && < 2.0,
                        witherable           >= 0.3   && < 0.4
@@ -134,11 +134,11 @@
                        ghcjs-prim,
                        codeworld-game-api,
                        codeworld-prediction,
-                       ghcjs-dom             >= 0.8 && < 0.9,
+                       ghcjs-dom             >= 0.9 && < 0.9.4,
                        transformers
   else
     Build-depends:     blank-canvas          >= 0.6 && < 0.8,
-                       time                  >= 1.6.0 && < 1.9
+                       time                  >= 1.8 && < 2.0
 
   Ghc-options:         -O2
   Cpp-options:         -DCODEWORLD_UNIT_TEST
diff --git a/jsbits/sim_fp.js b/jsbits/sim_fp.js
--- a/jsbits/sim_fp.js
+++ b/jsbits/sim_fp.js
@@ -1,5 +1,5 @@
 /*
- * Copyright 2019 The CodeWorld Authors. All rights reserved.
+ * Copyright 2020 The CodeWorld Authors. All rights reserved.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/CodeWorld.hs b/src/CodeWorld.hs
--- a/src/CodeWorld.hs
+++ b/src/CodeWorld.hs
@@ -1,7 +1,7 @@
 {-# LANGUAGE PatternSynonyms #-}
 
 {-
-  Copyright 2019 The CodeWorld Authors. All rights reserved.
+  Copyright 2020 The CodeWorld Authors. All rights reserved.
 
   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
@@ -23,12 +23,6 @@
     debugActivityOf,
     groupActivityOf,
     unsafeGroupActivityOf,
-    simulationOf,
-    debugSimulationOf,
-    interactionOf,
-    debugInteractionOf,
-    collaborationOf,
-    unsafeCollaborationOf,
 
     -- * Pictures
     Picture,
@@ -36,9 +30,7 @@
     Font (..),
     blank,
     polyline,
-    path,
     thickPolyline,
-    thickPath,
     polygon,
     thickPolygon,
     solidPolygon,
@@ -56,9 +48,7 @@
     arc,
     sector,
     thickArc,
-    text,
     lettering,
-    styledText,
     styledLettering,
     colored,
     coloured,
@@ -98,15 +88,8 @@
     red,
     green,
     blue,
-    cyan,
-    magenta,
     yellow,
-    aquamarine,
     orange,
-    azure,
-    violet,
-    chartreuse,
-    rose,
     brown,
     pink,
     purple,
diff --git a/src/CodeWorld/App.hs b/src/CodeWorld/App.hs
--- a/src/CodeWorld/App.hs
+++ b/src/CodeWorld/App.hs
@@ -3,7 +3,7 @@
 {-# OPTIONS_GHC -Wno-deprecations -Wno-name-shadowing #-}
 
 {-
-  Copyright 2019 The CodeWorld Authors. All rights reserved.
+  Copyright 2020 The CodeWorld Authors. All rights reserved.
 
   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
@@ -21,7 +21,6 @@
 module CodeWorld.App
   {-# WARNING "This is an experimental API.  It can change at any time." #-}
   ( Rule,
-    timeRule,
     eventRule,
     pictureRule,
     multiEventRule,
@@ -38,14 +37,10 @@
 import System.Random (StdGen)
 
 data Rule :: * -> * where
-  TimeRule :: (Double -> state -> state) -> Rule state
   EventRule :: (Int -> Event -> state -> state) -> Rule state
   PictureRule :: (Int -> state -> Picture) -> Rule state
   Rules :: [Rule state] -> Rule state
 
-timeRule :: (Double -> state -> state) -> Rule state
-timeRule = TimeRule
-
 eventRule :: (Event -> state -> state) -> Rule state
 eventRule = EventRule . const
 
@@ -59,9 +54,6 @@
 multiPictureRule = PictureRule
 
 subrule :: (a -> b) -> (b -> a -> a) -> Rule b -> Rule a
-subrule getter setter (TimeRule step_b) = TimeRule step_a
-  where
-    step_a dt a = setter (step_b dt (getter a)) a
 subrule getter setter (EventRule event_b) = EventRule event_a
   where
     event_a k ev a = setter (event_b k ev (getter a)) a
@@ -74,14 +66,10 @@
 rules = Rules
 
 applicationOf :: world -> [Rule world] -> IO ()
-applicationOf w rules = interactionOf w step event picture
+applicationOf w rules = activityOf w event picture
   where
-    step dt = foldl' (.) id [f dt | f <- concatMap stepHandlers rules]
     event ev = foldl' (.) id [f ev | f <- concatMap eventHandlers rules]
     picture w = pictures [pic w | pic <- concatMap pictureHandlers rules]
-    stepHandlers (TimeRule f) = [f]
-    stepHandlers (Rules rs) = concatMap stepHandlers rs
-    stepHandlers _ = []
     eventHandlers (EventRule f) = [f 0]
     eventHandlers (Rules rs) = concatMap eventHandlers rs
     eventHandlers _ = []
@@ -91,14 +79,10 @@
 
 unsafeMultiApplicationOf :: Int -> (StdGen -> state) -> [Rule state] -> IO ()
 unsafeMultiApplicationOf n initial rules =
-  unsafeCollaborationOf n initial step event picture
+  unsafeGroupActivityOf n initial event picture
   where
-    step dt = foldl' (.) id [f dt | f <- concatMap stepHandlers rules]
     event k ev = foldl' (.) id [f k ev | f <- concatMap eventHandlers rules]
     picture k w = pictures [pic k w | pic <- concatMap pictureHandlers rules]
-    stepHandlers (TimeRule f) = [f]
-    stepHandlers (Rules rs) = concatMap stepHandlers rs
-    stepHandlers _ = []
     eventHandlers (EventRule f) = [f]
     eventHandlers (Rules rs) = concatMap eventHandlers rs
     eventHandlers _ = []
diff --git a/src/CodeWorld/App2.hs b/src/CodeWorld/App2.hs
--- a/src/CodeWorld/App2.hs
+++ b/src/CodeWorld/App2.hs
@@ -3,7 +3,7 @@
 {-# OPTIONS_GHC -Wno-deprecations #-}
 
 {-
-  Copyright 2019 The CodeWorld Authors. All rights reserved.
+  Copyright 2020 The CodeWorld Authors. All rights reserved.
 
   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
@@ -22,7 +22,6 @@
   {-# WARNING "This is an experimental API.  It can change at any time." #-}
   ( Application,
     defaultApplication,
-    withTimeStep,
     withEventHandler,
     withPicture,
     withMultiEventHandler,
@@ -37,46 +36,38 @@
 data Application :: * -> * where
   App ::
     state ->
-    (Double -> state -> state) ->
     (Int -> Event -> state -> state) ->
     (Int -> state -> Picture) ->
     Application state
 
 defaultApplication :: state -> Application state
 defaultApplication s =
-  App s (const id) (const (const id)) (const (const blank))
-
-withTimeStep ::
-  (Double -> state -> state) ->
-  Application state ->
-  Application state
-withTimeStep f (App initial step event picture) =
-  App initial (\dt -> f dt . step dt) event picture
+  App s (const (const id)) (const (const blank))
 
 withEventHandler ::
   (Event -> state -> state) ->
   Application state ->
   Application state
-withEventHandler f (App initial step event picture) =
-  App initial step (\k ev -> f ev . event k ev) picture
+withEventHandler f (App initial event picture) =
+  App initial (\k ev -> f ev . event k ev) picture
 
 withPicture :: (state -> Picture) -> Application state -> Application state
-withPicture f (App initial step event picture) =
-  App initial step event (\k s -> f s & picture k s)
+withPicture f (App initial event picture) =
+  App initial event (\k s -> f s & picture k s)
 
 withMultiEventHandler ::
   (Int -> Event -> state -> state) ->
   Application state ->
   Application state
-withMultiEventHandler f (App initial step event picture) =
-  App initial step (\k ev -> f k ev . event k ev) picture
+withMultiEventHandler f (App initial event picture) =
+  App initial (\k ev -> f k ev . event k ev) picture
 
 withMultiPicture ::
   (Int -> state -> Picture) ->
   Application state ->
   Application state
-withMultiPicture f (App initial step event picture) =
-  App initial step event (\k s -> f k s & picture k s)
+withMultiPicture f (App initial event picture) =
+  App initial event (\k s -> f k s & picture k s)
 
 subapplication ::
   (a -> b) ->
@@ -84,13 +75,12 @@
   Application b ->
   (b -> a) ->
   Application a
-subapplication getter setter (App initial step event picture) f =
+subapplication getter setter (App initial event picture) f =
   App
     (f initial)
-    (\dt s -> setter (step dt (getter s)) s)
     (\k ev s -> setter (event k ev (getter s)) s)
     (\k -> picture k . getter)
 
 applicationOf :: Application world -> IO ()
-applicationOf (App initial step event picture) =
-  interactionOf initial step (event 0) (picture 0)
+applicationOf (App initial event picture) =
+  activityOf initial (event 0) (picture 0)
diff --git a/src/CodeWorld/CanvasM.hs b/src/CodeWorld/CanvasM.hs
--- a/src/CodeWorld/CanvasM.hs
+++ b/src/CodeWorld/CanvasM.hs
@@ -6,7 +6,7 @@
 {-# LANGUAGE TypeFamilies #-}
 
 {-
-  Copyright 2019 The CodeWorld Authors. All rights reserved.
+  Copyright 2020 The CodeWorld Authors. All rights reserved.
   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at
@@ -46,53 +46,53 @@
 #endif
 
 class (Monad m, MonadIO m) => MonadCanvas m where
-    type Image m
+  type Image m
 
-    save :: m ()
-    restore :: m ()
-    transform ::
-           Double -> Double -> Double -> Double -> Double -> Double -> m ()
-    translate :: Double -> Double -> m ()
-    scale :: Double -> Double -> m ()
-    newImage :: Int -> Int -> m (Image m)
-    builtinImage :: Text -> m (Maybe (Image m))
-    withImage :: Image m -> m a -> m a
-    drawImage :: Image m -> Int -> Int -> Int -> Int -> m ()
-    drawImgURL :: Text -> Text -> Double -> Double -> m ()
-    globalCompositeOperation :: Text -> m ()
-    globalAlpha :: Double -> m ()
-    lineWidth :: Double -> m ()
-    strokeColor :: Int -> Int -> Int -> Double -> m ()
-    fillColor :: Int -> Int -> Int -> Double -> m ()
-    font :: Text -> m ()
-    textCenter :: m ()
-    textMiddle :: m ()
-    beginPath :: m ()
-    closePath :: m ()
-    moveTo :: (Double, Double) -> m ()
-    lineTo :: (Double, Double) -> m ()
-    quadraticCurveTo :: (Double, Double) -> (Double, Double) -> m ()
-    bezierCurveTo ::
-           (Double, Double) -> (Double, Double) -> (Double, Double) -> m ()
-    arc :: Double -> Double -> Double -> Double -> Double -> Bool -> m ()
-    rect :: Double -> Double -> Double -> Double -> m ()
-    clip :: m ()
-    fill :: m ()
-    stroke :: m ()
-    fillRect :: Double -> Double -> Double -> Double -> m ()
-    fillText :: Text -> (Double, Double) -> m ()
-    measureText :: Text -> m Double
-    isPointInPath :: (Double, Double) -> m Bool
-    isPointInStroke :: (Double, Double) -> m Bool
-    getScreenWidth :: m Double
-    getScreenHeight :: m Double
+  save :: m ()
+  restore :: m ()
+  transform ::
+    Double -> Double -> Double -> Double -> Double -> Double -> m ()
+  translate :: Double -> Double -> m ()
+  scale :: Double -> Double -> m ()
+  newImage :: Int -> Int -> m (Image m)
+  builtinImage :: Text -> m (Maybe (Image m))
+  withImage :: Image m -> m a -> m a
+  drawImage :: Image m -> Int -> Int -> Int -> Int -> m ()
+  drawImgURL :: Text -> Text -> Double -> Double -> m ()
+  globalCompositeOperation :: Text -> m ()
+  globalAlpha :: Double -> m ()
+  lineWidth :: Double -> m ()
+  strokeColor :: Int -> Int -> Int -> Double -> m ()
+  fillColor :: Int -> Int -> Int -> Double -> m ()
+  font :: Text -> m ()
+  textCenter :: m ()
+  textMiddle :: m ()
+  beginPath :: m ()
+  closePath :: m ()
+  moveTo :: (Double, Double) -> m ()
+  lineTo :: (Double, Double) -> m ()
+  quadraticCurveTo :: (Double, Double) -> (Double, Double) -> m ()
+  bezierCurveTo ::
+    (Double, Double) -> (Double, Double) -> (Double, Double) -> m ()
+  arc :: Double -> Double -> Double -> Double -> Double -> Bool -> m ()
+  rect :: Double -> Double -> Double -> Double -> m ()
+  clip :: m ()
+  fill :: m ()
+  stroke :: m ()
+  fillRect :: Double -> Double -> Double -> Double -> m ()
+  fillText :: Text -> (Double, Double) -> m ()
+  measureText :: Text -> m Double
+  isPointInPath :: (Double, Double) -> m Bool
+  isPointInStroke :: (Double, Double) -> m Bool
+  getScreenWidth :: m Double
+  getScreenHeight :: m Double
 
 saveRestore :: MonadCanvas m => m a -> m a
 saveRestore m = do
-    save
-    r <- m
-    restore
-    return r
+  save
+  r <- m
+  restore
+  return r
 
 #if defined(ghcjs_HOST_OS)
 
@@ -113,6 +113,9 @@
         x <- unCanvasM m dim ctx
         unCanvasM (f x) dim ctx
 
+foreign import javascript "$6.drawImage($1, $2, $3, $4, $5);"
+    js_drawImage :: Element -> Double -> Double -> Double -> Double -> Canvas.Context -> IO ()
+
 foreign import javascript "$2.globalCompositeOperation = $1;"
     js_globalCompositeOperation :: JSString -> Canvas.Context -> IO ()
 
@@ -167,13 +170,7 @@
         CanvasM (const (Canvas.drawImage (Canvas.Image c) x y w h))
     drawImgURL name url w h = CanvasM $ \ _ ctx -> do
         img <- createOrGetImage name url
-        Canvas.drawImage
-            (Canvas.Image (unElement img))
-            (round (-w/2))
-            (round (-h/2))
-            (round w)
-            (round h)
-            ctx
+        js_drawImage img (-w/2) (-h/2) w h ctx
     globalCompositeOperation op =
         CanvasM (const (js_globalCompositeOperation (textToJSString op)))
     globalAlpha a = CanvasM (const (js_globalAlpha a))
diff --git a/src/CodeWorld/CollaborationUI.hs b/src/CodeWorld/CollaborationUI.hs
--- a/src/CodeWorld/CollaborationUI.hs
+++ b/src/CodeWorld/CollaborationUI.hs
@@ -9,7 +9,7 @@
 {-# OPTIONS_GHC -Wno-unticked-promoted-constructors -Wno-name-shadowing #-}
 
 {-
-  Copyright 2019 The CodeWorld Authors. All rights reserved.
+  Copyright 2020 The CodeWorld Authors. All rights reserved.
 
   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
diff --git a/src/CodeWorld/Color.hs b/src/CodeWorld/Color.hs
--- a/src/CodeWorld/Color.hs
+++ b/src/CodeWorld/Color.hs
@@ -4,7 +4,7 @@
 {-# OPTIONS_GHC -Wno-name-shadowing #-}
 
 {-
-  Copyright 2019 The CodeWorld Authors. All rights reserved.
+  Copyright 2020 The CodeWorld Authors. All rights reserved.
 
   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
@@ -176,97 +176,40 @@
 alpha :: Color -> Double
 alpha (RGBA _ _ _ a) = fence a
 
--- Old-style colors
-
-white, black, red, green, blue, cyan, magenta, yellow :: Color
-
-orange, rose, chartreuse, aquamarine, violet, azure :: Color
-
-gray, grey, brown, purple, pink :: Color
+-- Named colors
 
+white :: Color
 white = HSL 0.00 0.00 1.00
 
+black :: Color
 black = HSL 0.00 0.00 0.00
 
+gray :: Color
 gray = HSL 0.00 0.00 0.50
 
+grey :: Color
 grey = HSL 0.00 0.00 0.50
 
+red :: Color
 red = HSL 0.00 0.75 0.50
 
+orange :: Color
 orange = HSL 0.61 0.75 0.50
 
+yellow :: Color
 yellow = HSL 0.98 0.75 0.50
 
+green :: Color
 green = HSL 2.09 0.75 0.50
 
+blue :: Color
 blue = HSL 3.84 0.75 0.50
 
+purple :: Color
 purple = HSL 4.80 0.75 0.50
 
+pink :: Color
 pink = HSL 5.76 0.75 0.75
 
+brown :: Color
 brown = HSL 0.52 0.60 0.40
-
-cyan = HSL (3 / 3 * pi) 0.75 0.5
-
-magenta = HSL (5 / 3 * pi) 0.75 0.5
-
-chartreuse = HSL (3 / 6 * pi) 0.75 0.5
-
-aquamarine = HSL (5 / 6 * pi) 0.75 0.5
-
-azure = HSL (7 / 6 * pi) 0.75 0.5
-
-violet = HSL (9 / 6 * pi) 0.75 0.5
-
-rose = HSL (11 / 6 * pi) 0.75 0.5
-
-{-# WARNING
-  magenta
-  [ "Please use HSL(5 * pi / 3, 0.75, 0.5) instead of magenta.",
-    "The variable magenta may be removed July 2020."
-  ]
-  #-}
-
-{-# WARNING
-  cyan
-  [ "Please use HSL(pi, 0.75, 0.5) instead of cyan.",
-    "The variable cyan may be removed July 2020."
-  ]
-  #-}
-
-{-# WARNING
-  chartreuse
-  [ "Please use HSL(pi / 2, 0.75, 0.5) instead of chartreuse.",
-    "The variable chartreuse may be removed July 2020."
-  ]
-  #-}
-
-{-# WARNING
-  aquamarine
-  [ "Please use HSL(5 * pi / 6, 0.75, 0.5) instead of aquamarine.",
-    "The variable aquamarine may be removed July 2020."
-  ]
-  #-}
-
-{-# WARNING
-  azure
-  [ "Please use HSL(7 * pi / 6, 0.75, 0.5) instead of azure.",
-    "The variable azure may be removed July 2020."
-  ]
-  #-}
-
-{-# WARNING
-  rose
-  [ "Please use HSL(11 * pi / 6, 0.75, 0.5) instead of rose.",
-    "The variable rose may be removed July 2020."
-  ]
-  #-}
-
-{-# WARNING
-  violet
-  [ "Please use purple instead of violet.",
-    "The variable violet may be removed July 2020."
-  ]
-  #-}
diff --git a/src/CodeWorld/DrawState.hs b/src/CodeWorld/DrawState.hs
--- a/src/CodeWorld/DrawState.hs
+++ b/src/CodeWorld/DrawState.hs
@@ -1,7 +1,7 @@
 {-# LANGUAGE BangPatterns #-}
 
 {-
-  Copyright 2019 The CodeWorld Authors. All rights reserved.
+  Copyright 2020 The CodeWorld Authors. All rights reserved.
 
   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
@@ -82,7 +82,8 @@
     (b * sin r - d * cos r)
     e
     f
-  where r = 2 * th
+  where
+    r = 2 * th
 
 setColorDS :: Color -> DrawState -> DrawState
 setColorDS col = mapDSColor $ \mcol ->
diff --git a/src/CodeWorld/Driver.hs b/src/CodeWorld/Driver.hs
--- a/src/CodeWorld/Driver.hs
+++ b/src/CodeWorld/Driver.hs
@@ -1,5 +1,3 @@
-{-# OPTIONS_GHC -Wno-name-shadowing -Wno-orphans -Wno-unticked-promoted-constructors #-}
-
 {-# LANGUAGE CPP #-}
 {-# LANGUAGE DataKinds #-}
 {-# LANGUAGE DeriveGeneric #-}
@@ -18,9 +16,10 @@
 {-# LANGUAGE StandaloneDeriving #-}
 {-# LANGUAGE TypeFamilies #-}
 {-# LANGUAGE UndecidableInstances #-}
+{-# OPTIONS_GHC -Wno-name-shadowing -Wno-orphans -Wno-unticked-promoted-constructors #-}
 
 {-
-  Copyright 2019 The CodeWorld Authors. All rights reserved.
+  Copyright 2020 The CodeWorld Authors. All rights reserved.
 
   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
@@ -53,7 +52,7 @@
 import Data.Dependent.Sum
 import Data.Foldable
 import Data.IORef
-import Data.List (zip4, intercalate)
+import Data.List (intercalate, zip4)
 import Data.Maybe
 import Data.Serialize
 import Data.Serialize.Text ()
@@ -86,14 +85,16 @@
 import Data.Aeson (ToJSON(..), (.=), object)
 import Data.Hashable
 import qualified Data.JSString
-import qualified GHCJS.DOM.ClientRect as ClientRect
 import GHCJS.Concurrent (withoutPreemption)
 import GHCJS.DOM
+import qualified GHCJS.DOM.DOMRect as DOMRect
+import GHCJS.DOM.Document (createElement, getBodyUnsafe)
 import GHCJS.DOM.Element
 import GHCJS.DOM.EventM
 import GHCJS.DOM.GlobalEventHandlers hiding (error, keyPress)
 import GHCJS.DOM.KeyboardEvent
 import GHCJS.DOM.MouseEvent
+import GHCJS.DOM.Node (appendChild)
 import GHCJS.DOM.NonElementParentNode
 import GHCJS.DOM.Types (Window, Element, unElement)
 import GHCJS.Foreign.Callback
@@ -101,7 +102,6 @@
 import GHCJS.Marshal.Pure
 import GHCJS.Types
 import JavaScript.Object
-import JavaScript.Web.AnimationFrame
 import qualified JavaScript.Web.Canvas as Canvas
 import qualified JavaScript.Web.Canvas.Internal as Canvas
 import qualified JavaScript.Web.Location as Loc
@@ -125,28 +125,28 @@
 -- the action that sets up the geometry.
 withDS :: MonadCanvas m => DrawState -> m a -> m a
 withDS (DrawState (AffineTransformation ta tb tc td te tf) _col) action =
-    CM.saveRestore $ do
-        CM.transform ta tb tc td te tf
-        CM.beginPath
-        action
+  CM.saveRestore $ do
+    CM.transform ta tb tc td te tf
+    CM.beginPath
+    action
 
 setColor :: MonadCanvas m => Color -> m ()
 setColor (RGBA r g b a) = do
-    CM.strokeColor
-        (round $ r * 255)
-        (round $ g * 255)
-        (round $ b * 255)
-        a
-    CM.fillColor
-        (round $ r * 255)
-        (round $ g * 255)
-        (round $ b * 255)
-        a
+  CM.strokeColor
+    (round $ r * 255)
+    (round $ g * 255)
+    (round $ b * 255)
+    a
+  CM.fillColor
+    (round $ r * 255)
+    (round $ g * 255)
+    (round $ b * 255)
+    a
 
 applyColor :: MonadCanvas m => DrawState -> m ()
 applyColor ds = case getColorDS ds of
-    Nothing -> setColor (RGBA 0 0 0 1)
-    Just c -> setColor c
+  Nothing -> setColor (RGBA 0 0 0 1)
+  Just c -> setColor c
 
 -- | A slower way to draw a picture, which has some useful properties.  It
 -- can draw images in non-standard colors, and apply transparent colors
@@ -154,75 +154,75 @@
 -- color in the DrawState.
 viaOffscreen :: MonadCanvas m => Color -> (Color -> m ()) -> m ()
 viaOffscreen (RGBA r g b a) pic = do
-    w <- CM.getScreenWidth
-    h <- CM.getScreenHeight
-    when (w > 0.5 && h > 0.5) $ do
-        img <- CM.newImage (round w) (round h)
-        CM.withImage img $ do
-            setupScreenContext (round w) (round h)
-            pic (RGBA r g b 1)
-        CM.saveRestore $ do
-            px <- pixelSize
-            CM.scale px (-px)
-            CM.globalAlpha a
-            CM.drawImage img (round (-w/2)) (round (-h/2)) (round w) (round h)
+  w <- CM.getScreenWidth
+  h <- CM.getScreenHeight
+  when (w > 0.5 && h > 0.5) $ do
+    img <- CM.newImage (round w) (round h)
+    CM.withImage img $ do
+      setupScreenContext (round w) (round h)
+      pic (RGBA r g b 1)
+    CM.saveRestore $ do
+      px <- pixelSize
+      CM.scale px (- px)
+      CM.globalAlpha a
+      CM.drawImage img (round (- w / 2)) (round (- h / 2)) (round w) (round h)
 
 followPath :: MonadCanvas m => [Point] -> Bool -> Bool -> m ()
 followPath [] _ _ = return ()
 followPath [_] _ _ = return ()
-followPath ((sx, sy):ps) closed False = do
-    CM.moveTo (sx, sy)
-    forM_ ps $ \(x, y) -> CM.lineTo (x, y)
-    when closed CM.closePath
+followPath ((sx, sy) : ps) closed False = do
+  CM.moveTo (sx, sy)
+  forM_ ps $ \(x, y) -> CM.lineTo (x, y)
+  when closed CM.closePath
 followPath [p1, p2] False True = followPath [p1, p2] False False
 followPath ps False True = do
-    let [p1@(x1, y1), p2@(x2, y2), p3@(x3, y3)] = take 3 ps
-        dprev = euclideanDistance p1 p2
-        dnext = euclideanDistance p2 p3
-        p = dprev / (dprev + dnext)
-        cx = x2 + p * (x1 - x3) / 2
-        cy = y2 + p * (y1 - y3) / 2
-    CM.moveTo (x1, y1)
-    CM.quadraticCurveTo (cx, cy) (x2, y2)
-    forM_ (zip4 ps (tail ps) (tail $ tail ps) (tail $ tail $ tail ps)) $ \(p1@(x1, y1), p2@(x2, y2), p3@(x3, y3), p4@(x4, y4)) -> do
-        let dp = euclideanDistance p1 p2
-            d1 = euclideanDistance p2 p3
-            d2 = euclideanDistance p3 p4
-            p = d1 / (d1 + d2)
-            r = d1 / (dp + d1)
-            cx1 = x2 + r * (x3 - x1) / 2
-            cy1 = y2 + r * (y3 - y1) / 2
-            cx2 = x3 + p * (x2 - x4) / 2
-            cy2 = y3 + p * (y2 - y4) / 2
-        CM.bezierCurveTo
-            (cx1, cy1)
-            (cx2, cy2)
-            (x3,  y3)
-    let [p1@(x1, y1), p2@(x2, y2), p3@(x3, y3)] = reverse $ take 3 $ reverse ps
-        dp = euclideanDistance p1 p2
+  let [p1@(x1, y1), p2@(x2, y2), p3@(x3, y3)] = take 3 ps
+      dprev = euclideanDistance p1 p2
+      dnext = euclideanDistance p2 p3
+      p = dprev / (dprev + dnext)
+      cx = x2 + p * (x1 - x3) / 2
+      cy = y2 + p * (y1 - y3) / 2
+  CM.moveTo (x1, y1)
+  CM.quadraticCurveTo (cx, cy) (x2, y2)
+  forM_ (zip4 ps (tail ps) (tail $ tail ps) (tail $ tail $ tail ps)) $ \(p1@(x1, y1), p2@(x2, y2), p3@(x3, y3), p4@(x4, y4)) -> do
+    let dp = euclideanDistance p1 p2
         d1 = euclideanDistance p2 p3
+        d2 = euclideanDistance p3 p4
+        p = d1 / (d1 + d2)
         r = d1 / (dp + d1)
-        cx = x2 + r * (x3 - x1) / 2
-        cy = y2 + r * (y3 - y1) / 2
-    CM.quadraticCurveTo (cx, cy) (x3, y3)
-followPath ps@(_:(sx, sy):_) True True = do
-    CM.moveTo (sx, sy)
-    let rep = cycle ps
-    forM_ (zip4 ps (tail rep) (tail $ tail rep) (tail $ tail $ tail rep)) $ \(p1@(x1, y1), p2@(x2, y2), p3@(x3, y3), p4@(x4, y4)) -> do
-        let dp = euclideanDistance p1 p2
-            d1 = euclideanDistance p2 p3
-            d2 = euclideanDistance p3 p4
-            p = d1 / (d1 + d2)
-            r = d1 / (dp + d1)
-            cx1 = x2 + r * (x3 - x1) / 2
-            cy1 = y2 + r * (y3 - y1) / 2
-            cx2 = x3 + p * (x2 - x4) / 2
-            cy2 = y3 + p * (y2 - y4) / 2
-        CM.bezierCurveTo
-            (cx1, cy1)
-            (cx2, cy2)
-            (x3,  y3)
-    CM.closePath
+        cx1 = x2 + r * (x3 - x1) / 2
+        cy1 = y2 + r * (y3 - y1) / 2
+        cx2 = x3 + p * (x2 - x4) / 2
+        cy2 = y3 + p * (y2 - y4) / 2
+    CM.bezierCurveTo
+      (cx1, cy1)
+      (cx2, cy2)
+      (x3, y3)
+  let [p1@(x1, y1), p2@(x2, y2), p3@(x3, y3)] = reverse $ take 3 $ reverse ps
+      dp = euclideanDistance p1 p2
+      d1 = euclideanDistance p2 p3
+      r = d1 / (dp + d1)
+      cx = x2 + r * (x3 - x1) / 2
+      cy = y2 + r * (y3 - y1) / 2
+  CM.quadraticCurveTo (cx, cy) (x3, y3)
+followPath ps@(_ : (sx, sy) : _) True True = do
+  CM.moveTo (sx, sy)
+  let rep = cycle ps
+  forM_ (zip4 ps (tail rep) (tail $ tail rep) (tail $ tail $ tail rep)) $ \(p1@(x1, y1), p2@(x2, y2), p3@(x3, y3), p4@(x4, y4)) -> do
+    let dp = euclideanDistance p1 p2
+        d1 = euclideanDistance p2 p3
+        d2 = euclideanDistance p3 p4
+        p = d1 / (d1 + d2)
+        r = d1 / (dp + d1)
+        cx1 = x2 + r * (x3 - x1) / 2
+        cy1 = y2 + r * (y3 - y1) / 2
+        cx2 = x3 + p * (x2 - x4) / 2
+        cy2 = y3 + p * (y2 - y4) / 2
+    CM.bezierCurveTo
+      (cx1, cy1)
+      (cx2, cy2)
+      (x3, y3)
+  CM.closePath
 
 euclideanDistance :: Point -> Point -> Double
 euclideanDistance (x1, y1) (x2, y2) = sqrt $ square (x2 - x1) + square (y2 - y1)
@@ -231,22 +231,22 @@
 
 drawFigure :: MonadCanvas m => DrawState -> Double -> m () -> m ()
 drawFigure ds w figure = do
-    withDS ds $ do
-        figure
-        when (w /= 0) $ do
-            CM.lineWidth w
-            applyColor ds
-            CM.stroke
-    when (w == 0) $ do
-        CM.lineWidth =<< pixelSize
-        applyColor ds
-        CM.stroke
+  withDS ds $ do
+    figure
+    when (w /= 0) $ do
+      CM.lineWidth w
+      applyColor ds
+      CM.stroke
+  when (w == 0) $ do
+    CM.lineWidth =<< pixelSize
+    applyColor ds
+    CM.stroke
 
 fillFigure :: MonadCanvas m => DrawState -> m () -> m ()
 fillFigure ds figure = do
-    withDS ds figure
-    applyColor ds
-    CM.fill
+  withDS ds figure
+  applyColor ds
+  CM.fill
 
 --------------------------------------------------------------------------------
 
@@ -284,8 +284,8 @@
 drawPicture (Rotate _ r p) ds = drawPicture p (rotateDS r ds)
 drawPicture (Reflect _ r p) ds = drawPicture p (reflectDS r ds)
 drawPicture (Clip _ x y p) ds = do
-    withDS ds $ followPath (rectangleVertices x y) True False
-    CM.saveRestore $ CM.clip >> drawPicture p ds
+  withDS ds $ followPath (rectangleVertices x y) True False
+  CM.saveRestore $ CM.clip >> drawPicture p ds
 drawPicture (Pictures _ ps) ds = forM_ (reverse ps) $ \p -> drawPicture p ds
 drawPicture (PictureAnd _ ps) ds = forM_ (reverse ps) $ \p -> drawPicture p ds
 
@@ -321,8 +321,8 @@
 pictureContains (Rotate _ r p) ds pt = pictureContains p (rotateDS r ds) pt
 pictureContains (Reflect _ r p) ds pt = pictureContains p (reflectDS r ds) pt
 pictureContains (Clip _ x y p) ds pt =
-    (&&) <$> polygonContains (rectangleVertices x y) False ds pt
-         <*> pictureContains p ds pt
+  (&&) <$> polygonContains (rectangleVertices x y) False ds pt
+    <*> pictureContains p ds pt
 pictureContains (Pictures _ ps) ds pt = orM [pictureContains p ds pt | p <- ps]
 pictureContains (PictureAnd _ ps) ds pt = orM [pictureContains p ds pt | p <- ps]
 
@@ -351,54 +351,54 @@
 
 polygonContains :: MonadCanvas m => [Point] -> Bool -> DrawState -> Point -> m Bool
 polygonContains ps smooth ds p = do
-    withDS ds $ followPath ps True smooth
-    CM.isPointInPath p
+  withDS ds $ followPath ps True smooth
+  CM.isPointInPath p
 
 drawPath :: MonadCanvas m => [Point] -> Double -> Bool -> Bool -> DrawState -> m ()
 drawPath ps w closed smooth ds = drawFigure ds w $ followPath ps closed smooth
 
 pathContains :: MonadCanvas m => [Point] -> Double -> Bool -> Bool -> DrawState -> Point -> m Bool
 pathContains ps w closed smooth ds p = do
-    s <- pixelSize
-    drawFigure ds (max s w) $ followPath ps closed smooth
-    CM.isPointInStroke p
+  s <- pixelSize
+  drawFigure ds (max s w) $ followPath ps closed smooth
+  CM.isPointInStroke p
 
 drawSector :: MonadCanvas m => Double -> Double -> Double -> DrawState -> m ()
 drawSector b e r ds =
-    fillFigure ds $ CM.arc 0 0 (abs r) b e (b > e) >> CM.lineTo (0, 0)
+  fillFigure ds $ CM.arc 0 0 (abs r) b e (b > e) >> CM.lineTo (0, 0)
 
 sectorContains :: MonadCanvas m => Double -> Double -> Double -> DrawState -> Point -> m Bool
 sectorContains b e r ds p = do
-    withDS ds $ CM.arc 0 0 (abs r) b e (b > e) >> CM.lineTo (0, 0)
-    CM.isPointInPath p
+  withDS ds $ CM.arc 0 0 (abs r) b e (b > e) >> CM.lineTo (0, 0)
+  CM.isPointInPath p
 
 drawArc :: MonadCanvas m => Double -> Double -> Double -> Double -> DrawState -> m ()
 drawArc b e r w ds =
-    drawFigure ds w $ CM.arc 0 0 (abs r) b e (b > e)
+  drawFigure ds w $ CM.arc 0 0 (abs r) b e (b > e)
 
 arcContains :: MonadCanvas m => Double -> Double -> Double -> Double -> DrawState -> Point -> m Bool
 arcContains b e r w ds p = do
-    s <- pixelSize
-    let width = max s w
-    CM.lineWidth width
-    drawFigure ds width $
-        CM.arc 0 0 (abs r) b e (b > e)
-    CM.isPointInStroke p
+  s <- pixelSize
+  let width = max s w
+  CM.lineWidth width
+  drawFigure ds width $
+    CM.arc 0 0 (abs r) b e (b > e)
+  CM.isPointInStroke p
 
 drawText :: MonadCanvas m => TextStyle -> Font -> Text -> DrawState -> m ()
 drawText sty fnt txt ds = withDS ds $ do
-    CM.scale (1/25) (-1/25)
-    applyColor ds
-    CM.font (fontString sty fnt)
-    CM.fillText txt (0, 0)
+  CM.scale (1 / 25) (-1 / 25)
+  applyColor ds
+  CM.font (fontString sty fnt)
+  CM.fillText txt (0, 0)
 
 textContains :: MonadCanvas m => TextStyle -> Font -> Text -> DrawState -> Point -> m Bool
 textContains sty fnt txt ds p = do
-    CM.font (fontString sty fnt)
-    width <- (/ 25) <$> CM.measureText txt
-    let height = 1 -- constant, defined in fontString
-    withDS ds $ CM.rect ((-0.5) * width) ((-0.5) * height) width height
-    CM.isPointInPath p
+  CM.font (fontString sty fnt)
+  width <- (/ 25) <$> CM.measureText txt
+  let height = 1 -- constant, defined in fontString
+  withDS ds $ CM.rect ((-0.5) * width) ((-0.5) * height) width height
+  CM.isPointInPath p
 
 fontString :: TextStyle -> Font -> Text
 fontString style font = stylePrefix style <> "25px " <> fontName font
@@ -406,7 +406,6 @@
     stylePrefix Plain = ""
     stylePrefix Bold = "bold "
     stylePrefix Italic = "italic "
-
     fontName SansSerif = "sans-serif"
     fontName Serif = "serif"
     fontName Monospace = "monospace"
@@ -416,26 +415,26 @@
 
 drawImage :: MonadCanvas m => Text -> Text -> Double -> Double -> DrawState -> m ()
 drawImage name url imgw imgh ds = case getColorDS ds of
-    -- Fast path: draw in original color.
-    Nothing -> withDS ds $ do
-        CM.scale 1 (-1)
-        CM.drawImgURL name url imgw imgh
+  -- Fast path: draw in original color.
+  Nothing -> withDS ds $ do
+    CM.scale 1 (-1)
+    CM.drawImgURL name url imgw imgh
 
-    -- Slow path: draw in a different color via an offscreen canvas.
-    Just oc -> viaOffscreen oc $ \c -> do
-        setColor c
-        w <- CM.getScreenWidth
-        h <- CM.getScreenHeight
-        CM.fillRect (-w/2) (-h/2) w h
-        CM.globalCompositeOperation "destination-in"
-        withDS ds $ do
-            CM.scale 1 (-1)
-            CM.drawImgURL name url imgw imgh
+  -- Slow path: draw in a different color via an offscreen canvas.
+  Just oc -> viaOffscreen oc $ \c -> do
+    setColor c
+    w <- CM.getScreenWidth
+    h <- CM.getScreenHeight
+    CM.fillRect (- w / 2) (- h / 2) w h
+    CM.globalCompositeOperation "destination-in"
+    withDS ds $ do
+      CM.scale 1 (-1)
+      CM.drawImgURL name url imgw imgh
 
 imageContains :: MonadCanvas m => Text -> Text -> Double -> Double -> DrawState -> Point -> m Bool
 imageContains _ _ imgw imgh ds p = withDS ds $ do
-    CM.rect (-imgw / 2) (-imgh / 2) imgw imgh
-    CM.isPointInPath p
+  CM.rect (- imgw / 2) (- imgh / 2) imgw imgh
+  CM.isPointInPath p
 
 coordinatePlanePic :: Picture
 coordinatePlanePic = axes <> numbers <> guidelines
@@ -443,62 +442,62 @@
     xline y = colored (RGBA 0 0 0 0.25) $ polyline [(-10, y), (10, y)]
     xaxis = colored (RGBA 0 0 0 0.75) $ polyline [(-10, 0), (10, 0)]
     axes = xaxis <> rotated (pi / 2) xaxis
-    xguidelines = pictures [xline k | k <- [-10,-9 .. 10]]
+    xguidelines = pictures [xline k | k <- [-10, -9 .. 10]]
     guidelines = xguidelines <> rotated (pi / 2) xguidelines
     numbers = xnumbers <> ynumbers
     xnumbers =
-        pictures
-            [ translated
-                (fromIntegral k)
-                0.3
-                (scaled 0.5 0.5 (lettering (T.pack (show k))))
-            | k <- [-9,-8 .. 9]
-            , k /= (0 :: Int)
-            ]
+      pictures
+        [ translated
+            (fromIntegral k)
+            0.3
+            (scaled 0.5 0.5 (lettering (T.pack (show k))))
+          | k <- [-9, -8 .. 9],
+            k /= (0 :: Int)
+        ]
     ynumbers =
-        pictures
-            [ translated
-                0.3
-                (fromIntegral k)
-                (scaled 0.5 0.5 (lettering (T.pack (show k))))
-            | k <- [-9,-8 .. 9]
-            , k /= (0 :: Int)
-            ]
+      pictures
+        [ translated
+            0.3
+            (fromIntegral k)
+            (scaled 0.5 0.5 (lettering (T.pack (show k))))
+          | k <- [-9, -8 .. 9],
+            k /= (0 :: Int)
+        ]
 
 --------------------------------------------------------------------------------
 
 clearScreen :: MonadCanvas m => m ()
 clearScreen = do
-    w <- CM.getScreenWidth
-    h <- CM.getScreenHeight
-    px <- pixelSize
-    CM.fillColor 255 255 255 1
-    CM.fillRect (-w/2 * px) (-h/2 * px) (w * px) (h * px)
+  w <- CM.getScreenWidth
+  h <- CM.getScreenHeight
+  px <- pixelSize
+  CM.fillColor 255 255 255 1
+  CM.fillRect (- w / 2 * px) (- h / 2 * px) (w * px) (h * px)
 
 drawFrame :: MonadCanvas m => Picture -> m ()
 drawFrame pic = clearScreen >> drawPicture pic initialDS
 
 pixelSize :: MonadCanvas m => m Double
 pixelSize = do
-    cw <- CM.getScreenWidth
-    ch <- CM.getScreenHeight
-    return $ max (20 / realToFrac cw) (20 / realToFrac ch)
+  cw <- CM.getScreenWidth
+  ch <- CM.getScreenHeight
+  return $ max (20 / realToFrac cw) (20 / realToFrac ch)
 
 setupScreenContext :: MonadCanvas m => Int -> Int -> m ()
 setupScreenContext cw ch = do
-    CM.translate (realToFrac cw / 2) (realToFrac ch / 2)
-    s <- pixelSize
-    CM.scale (1/s) (-1/s)
-    CM.lineWidth 0
-    CM.textCenter
-    CM.textMiddle
+  CM.translate (realToFrac cw / 2) (realToFrac ch / 2)
+  s <- pixelSize
+  CM.scale (1 / s) (-1 / s)
+  CM.lineWidth 0
+  CM.textCenter
+  CM.textMiddle
 
 --------------------------------------------------------------------------------
 
 -- A NodeId a unique id for each node in a Picture, chosen by the order the node
 -- appears in DFS.  Always >=0.
-newtype NodeId = NodeId { getNodeId :: Int}
-    deriving (Eq, Ord, Enum, Show)
+newtype NodeId = NodeId {getNodeId :: Int}
+  deriving (Eq, Ord, Enum, Show)
 
 getChildNodes :: Picture -> [Picture]
 getChildNodes (Color _ _ p) = [p]
@@ -514,79 +513,82 @@
 
 findTopShape :: MonadCanvas m => DrawState -> Picture -> Double -> Double -> m (Maybe NodeId)
 findTopShape ds pic x y = do
-    (found, n) <- searchSingle ds pic x y
-    return $ if found
-        then Just (NodeId n)
-        else Nothing
+  (found, n) <- searchSingle ds pic x y
+  return $
+    if found
+      then Just (NodeId n)
+      else Nothing
   where
     searchSingle ds (Color _ _ p) x y =
-        fmap (+ 1) <$> searchSingle ds p x y
+      fmap (+ 1) <$> searchSingle ds p x y
     searchSingle ds (Translate _ dx dy p) x y =
-        fmap (+ 1) <$> searchSingle (translateDS dx dy ds) p x y
+      fmap (+ 1) <$> searchSingle (translateDS dx dy ds) p x y
     searchSingle ds (Scale _ sx sy p) x y =
-        fmap (+ 1) <$> searchSingle (scaleDS sx sy ds) p x y
+      fmap (+ 1) <$> searchSingle (scaleDS sx sy ds) p x y
     searchSingle ds (Dilate _ k p) x y =
-        fmap (+ 1) <$> searchSingle (scaleDS k k ds) p x y
+      fmap (+ 1) <$> searchSingle (scaleDS k k ds) p x y
     searchSingle ds (Rotate _ a p) x y =
-        fmap (+ 1) <$> searchSingle (rotateDS a ds) p x y
+      fmap (+ 1) <$> searchSingle (rotateDS a ds) p x y
     searchSingle ds (Reflect _ a p) x y =
-        fmap (+ 1) <$> searchSingle (reflectDS a ds) p x y
+      fmap (+ 1) <$> searchSingle (reflectDS a ds) p x y
     searchSingle ds (Clip _ w h p) x y = do
-        inClip <- polygonContains (rectangleVertices w h) False ds (x, y)
-        fmap (+ 1) <$> if inClip
-                       then searchSingle ds p x y
-                       else return (False, countNodes p)
+      inClip <- polygonContains (rectangleVertices w h) False ds (x, y)
+      fmap (+ 1)
+        <$> if inClip
+          then searchSingle ds p x y
+          else return (False, countNodes p)
     searchSingle ds (Pictures _ ps) x y =
-        fmap (+ 1) <$> searchMulti ds ps x y
+      fmap (+ 1) <$> searchMulti ds ps x y
     searchSingle ds (PictureAnd _ ps) x y =
-        fmap (+ 1) <$> searchMulti ds ps x y
+      fmap (+ 1) <$> searchMulti ds ps x y
     searchSingle ds p x y = do
-        contained <- pictureContains p ds (x, y)
-        if contained
-          then pure (True, 0)
-          else pure (False, 1)
-
+      contained <- pictureContains p ds (x, y)
+      if contained
+        then pure (True, 0)
+        else pure (False, 1)
     searchMulti _ [] _ _ = return (False, 0)
-    searchMulti ds (pic:pics) x y = do
-        (found, count) <- searchSingle ds pic x y
-        if found
-          then pure (True, count)
-          else fmap (+ count) <$> searchMulti ds pics x y
-
+    searchMulti ds (pic : pics) x y = do
+      (found, count) <- searchSingle ds pic x y
+      if found
+        then pure (True, count)
+        else fmap (+ count) <$> searchMulti ds pics x y
     countNodes p = 1 + sum (map countNodes (getChildNodes p))
 
 -- If a picture is found, the result will include an array of the base picture
 -- and all transformations.
 findTopShapeFromPoint :: MonadCanvas m => Point -> Picture -> m (Maybe NodeId)
 findTopShapeFromPoint (x, y) pic = do
-    cw <- CM.getScreenWidth
-    ch <- CM.getScreenHeight
-    img <- CM.newImage (round cw) (round ch)
-    CM.withImage img $ do
-        setupScreenContext (round cw) (round ch)
-        findTopShape initialDS pic x y
+  cw <- CM.getScreenWidth
+  ch <- CM.getScreenHeight
+  img <- CM.newImage (round cw) (round ch)
+  CM.withImage img $ do
+    setupScreenContext (round cw) (round ch)
+    findTopShape initialDS pic x y
 
 trim :: Int -> String -> String
 trim x y
   | x >= length y = y
   | otherwise = take mid y ++ "..." ++ reverse (take mid $ reverse y)
-  where mid = (x - 3) `div` 2
+  where
+    mid = (x - 3) `div` 2
 
 showFloat :: Bool -> Double -> String
 showFloat needNegParens x
   | needNegParens && x < 0 = "(" ++ result ++ ")"
   | otherwise = result
-  where result = stripZeros (showFFloatAlt (Just 4) x "")
-        stripZeros = reverse . dropWhile (== '.') . dropWhile (== '0') . reverse
+  where
+    result = stripZeros (showFFloatAlt (Just 4) x "")
+    stripZeros = reverse . dropWhile (== '.') . dropWhile (== '0') . reverse
 
 showPoints :: [Point] -> String
 showPoints pts =
-    "[" ++
-    intercalate ", " [
-        "(" ++ showFloat False x ++ ", " ++ showFloat False y ++ ")"
+  "["
+    ++ intercalate
+      ", "
+      [ "(" ++ showFloat False x ++ ", " ++ showFloat False y ++ ")"
         | (x, y) <- pts
-    ] ++
-    "]"
+      ]
+    ++ "]"
 
 showColor :: Color -> String
 showColor c@(RGBA r g b a)
@@ -601,109 +603,110 @@
   | c == pink = "pink"
   | c == purple = "purple"
   | c == gray = "gray"
-  | haskellMode, a == 1 =
-      printf "(RGB %s %s %s)" (showFloat True r) (showFloat True g) (showFloat True b)
+  | haskellMode,
+    a == 1 =
+    printf "(RGB %s %s %s)" (showFloat True r) (showFloat True g) (showFloat True b)
   | a == 1 =
-      printf "RGB(%s, %s, %s)" (showFloat False r) (showFloat False g) (showFloat False b)
+    printf "RGB(%s, %s, %s)" (showFloat False r) (showFloat False g) (showFloat False b)
   | haskellMode =
-      printf "(RGBA %s %s %s %s)" (showFloat True r) (showFloat True g) (showFloat True b) (showFloat True a)
+    printf "(RGBA %s %s %s %s)" (showFloat True r) (showFloat True g) (showFloat True b) (showFloat True a)
   | otherwise =
-      printf "RGBA(%s, %s, %s, %s)" (showFloat False r) (showFloat False g) (showFloat False b) (showFloat False a)
+    printf "RGBA(%s, %s, %s, %s)" (showFloat False r) (showFloat False g) (showFloat False b) (showFloat False a)
 
 describePicture :: Picture -> String
 describePicture (Rectangle _ w h)
   | haskellMode = printf "rectangle %s %s" (showFloat True w) (showFloat True h)
-  | otherwise   = printf "rectangle(%s, %s)" (showFloat False w) (showFloat False h)
+  | otherwise = printf "rectangle(%s, %s)" (showFloat False w) (showFloat False h)
 describePicture (SolidRectangle _ w h)
   | haskellMode = printf "solidRectangle %s %s" (showFloat True w) (showFloat True h)
-  | otherwise   = printf "solidRectangle(%s, %s)" (showFloat False w) (showFloat False h)
+  | otherwise = printf "solidRectangle(%s, %s)" (showFloat False w) (showFloat False h)
 describePicture (ThickRectangle _ lw w h)
   | haskellMode = printf "thickRectangle %s %s %s" (showFloat True lw) (showFloat True w) (showFloat True h)
-  | otherwise   = printf "thickRectangle(%s, %s, %s)" (showFloat False w) (showFloat False h) (showFloat False lw)
+  | otherwise = printf "thickRectangle(%s, %s, %s)" (showFloat False w) (showFloat False h) (showFloat False lw)
 describePicture (Circle _ r)
   | haskellMode = printf "circle %s" (showFloat True r)
-  | otherwise   = printf "circle(%s)" (showFloat False r)
+  | otherwise = printf "circle(%s)" (showFloat False r)
 describePicture (SolidCircle _ r)
   | haskellMode = printf "solidCircle %s" (showFloat True r)
-  | otherwise   = printf "solidCircle(%s)" (showFloat False r)
+  | otherwise = printf "solidCircle(%s)" (showFloat False r)
 describePicture (ThickCircle _ lw r)
   | haskellMode = printf "thickCircle %s %s" (showFloat True lw) (showFloat True r)
-  | otherwise   = printf "thickCircle(%s, %s)" (showFloat False r) (showFloat False lw)
+  | otherwise = printf "thickCircle(%s, %s)" (showFloat False r) (showFloat False lw)
 describePicture (SolidPolygon _ pts)
   | haskellMode = printf "solidPolygon %s" (showPoints pts)
-  | otherwise   = printf "solidPolygon(%s)" (showPoints pts)
+  | otherwise = printf "solidPolygon(%s)" (showPoints pts)
 describePicture (SolidClosedCurve _ pts)
   | haskellMode = printf "solidClosedCurve %s" (showPoints pts)
-  | otherwise   = printf "solidClosedCurve(%s)" (showPoints pts)
+  | otherwise = printf "solidClosedCurve(%s)" (showPoints pts)
 describePicture (Polygon _ pts)
   | haskellMode = printf "polygon %s" (showPoints pts)
-  | otherwise   = printf "polygon(%s)" (showPoints pts)
+  | otherwise = printf "polygon(%s)" (showPoints pts)
 describePicture (ThickPolygon _ pts w)
   | haskellMode = printf "thickPolygon %s %s" (showFloat True w) (showPoints pts)
-  | otherwise   = printf "thickPolygon(%s, %s)" (showPoints pts) (showFloat False w)
+  | otherwise = printf "thickPolygon(%s, %s)" (showPoints pts) (showFloat False w)
 describePicture (ClosedCurve _ pts)
   | haskellMode = printf "closedCurve %s" (showPoints pts)
-  | otherwise   = printf "closedCurve(%s)" (showPoints pts)
+  | otherwise = printf "closedCurve(%s)" (showPoints pts)
 describePicture (ThickClosedCurve _ pts w)
   | haskellMode = printf "thickClosedCurve %s %s" (showFloat True w) (showPoints pts)
-  | otherwise   = printf "thickClosedCurve(%s, %s)" (showPoints pts) (showFloat False w)
+  | otherwise = printf "thickClosedCurve(%s, %s)" (showPoints pts) (showFloat False w)
 describePicture (Polyline _ pts)
   | haskellMode = printf "polyline %s" (showPoints pts)
-  | otherwise   = printf "polyline(%s)" (showPoints pts)
+  | otherwise = printf "polyline(%s)" (showPoints pts)
 describePicture (ThickPolyline _ pts w)
   | haskellMode = printf "thickPolyline %s %s" (showFloat True w) (showPoints pts)
-  | otherwise   = printf "thickPolyline(%s, %s)" (showPoints pts) (showFloat False w)
+  | otherwise = printf "thickPolyline(%s, %s)" (showPoints pts) (showFloat False w)
 describePicture (Curve _ pts)
   | haskellMode = printf "curve %s" (showPoints pts)
-  | otherwise   = printf "curve(%s)" (showPoints pts)
+  | otherwise = printf "curve(%s)" (showPoints pts)
 describePicture (ThickCurve _ pts w)
   | haskellMode = printf "thickCurve %s %s" (showFloat True w) (showPoints pts)
-  | otherwise   = printf "thickCurve(%s, %s)" (showPoints pts) (showFloat False w)
+  | otherwise = printf "thickCurve(%s, %s)" (showPoints pts) (showFloat False w)
 describePicture (Sector _ b e r)
   | haskellMode = printf "sector %s %s %s" (showFloat True b) (showFloat True e) (showFloat True r)
-  | otherwise   = printf "sector(%s°, %s°, %s)" (showFloat False (180 * b / pi)) (showFloat False (180 * e / pi)) (showFloat False r)
+  | otherwise = printf "sector(%s°, %s°, %s)" (showFloat False (180 * b / pi)) (showFloat False (180 * e / pi)) (showFloat False r)
 describePicture (Arc _ b e r)
   | haskellMode = printf "arc %s %s %s" (showFloat True b) (showFloat True e) (showFloat True r)
-  | otherwise   = printf "arc(%s°, %s°, %s)" (showFloat False (180 * b / pi)) (showFloat False (180 * e / pi)) (showFloat False r)
+  | otherwise = printf "arc(%s°, %s°, %s)" (showFloat False (180 * b / pi)) (showFloat False (180 * e / pi)) (showFloat False r)
 describePicture (ThickArc _ b e r w)
   | haskellMode = printf "thickArc %s %s %s %s" (showFloat True w) (showFloat True b) (showFloat True e) (showFloat True r)
-  | otherwise   = printf "thickArc(%s°, %s°, %s, %s)" (showFloat False (180 * b / pi)) (showFloat False (180 * e / pi)) (showFloat False r) (showFloat False w)
+  | otherwise = printf "thickArc(%s°, %s°, %s, %s)" (showFloat False (180 * b / pi)) (showFloat False (180 * e / pi)) (showFloat False r) (showFloat False w)
 describePicture (Lettering _ txt)
   | haskellMode = printf "lettering %s" (show txt)
-  | otherwise   = printf "lettering(%s)" (show txt)
+  | otherwise = printf "lettering(%s)" (show txt)
 describePicture (Blank _) = "blank"
 describePicture (StyledLettering _ style font txt)
   | haskellMode = printf "styledLettering %s %s %s" (showsPrec 10 style "") (showsPrec 10 font "") (show txt)
-  | otherwise   = printf "styledLettering(%s, %s, %s)" (show txt) (show font) (show style)
+  | otherwise = printf "styledLettering(%s, %s, %s)" (show txt) (show font) (show style)
 describePicture (Color _ c _)
   | haskellMode = printf "colored %s" (showColor c)
-  | otherwise   = printf "colored(..., %s)" (showColor c)
+  | otherwise = printf "colored(..., %s)" (showColor c)
 describePicture (Translate _ x y _)
   | haskellMode = printf "translated %s %s" (showFloat True x) (showFloat True y)
-  | otherwise   = printf "translated(..., %s, %s)" (showFloat False x) (showFloat False y)
+  | otherwise = printf "translated(..., %s, %s)" (showFloat False x) (showFloat False y)
 describePicture (Scale _ x y _)
   | haskellMode = printf "scaled %s %s" (showFloat True x) (showFloat True y)
-  | otherwise   = printf "scaled(..., %s, %s)" (showFloat False x) (showFloat False y)
+  | otherwise = printf "scaled(..., %s, %s)" (showFloat False x) (showFloat False y)
 describePicture (Rotate _ angle _)
   | haskellMode = printf "rotated %s" (showFloat True angle)
-  | otherwise   = printf "rotated(..., %s°)" (showFloat False (180 * angle / pi))
+  | otherwise = printf "rotated(..., %s°)" (showFloat False (180 * angle / pi))
 describePicture (Reflect _ angle _)
   | haskellMode = printf "reflected %s" (showFloat True angle)
-  | otherwise   = printf "reflected(..., %s°)" (showFloat False (180 * angle / pi))
+  | otherwise = printf "reflected(..., %s°)" (showFloat False (180 * angle / pi))
 describePicture (Clip _ x y _)
   | haskellMode = printf "clipped %s %s" (showFloat True x) (showFloat True y)
-  | otherwise   = printf "rotated(..., %s, %s)" (showFloat False x) (showFloat False y)
+  | otherwise = printf "clipped(..., %s, %s)" (showFloat False x) (showFloat False y)
 describePicture (Dilate _ k _)
   | haskellMode = printf "dilated %s" (showFloat True k)
-  | otherwise   = printf "dilated(..., %s)" (showFloat False k)
+  | otherwise = printf "dilated(..., %s)" (showFloat False k)
 describePicture (Sketch _ name _ _ _) = T.unpack name
 describePicture (CoordinatePlane _) = "coordinatePlane"
 describePicture (Pictures _ _)
   | haskellMode = "pictures"
-  | otherwise   = "pictures(...)"
+  | otherwise = "pictures(...)"
 describePicture (PictureAnd _ _)
   | haskellMode = "(&)"
-  | otherwise   = "... & ..."
+  | otherwise = "... & ..."
 
 getPictureSrcLoc :: Picture -> Maybe SrcLoc
 getPictureSrcLoc (SolidPolygon loc _) = loc
@@ -752,8 +755,26 @@
 foreign import javascript unsafe "$1.getContext('2d', { alpha: false })"
     getCodeWorldContext :: Canvas.Canvas -> IO Canvas.Context
 
+getCanvas :: IO Element
+getCanvas = do
+    js_showCanvas
+    Just doc <- currentDocument
+    mcanvas <- getElementById doc ("screen" :: JSString)
+    case mcanvas of
+        Just canvas -> return canvas
+        Nothing -> do
+            body <- getBodyUnsafe doc
+            setAttribute body ("style" :: JSString)
+                ("margin: 0; overflow: hidden" :: JSString)
+            canvas <- createElement doc ("canvas" :: JSString)
+            setAttribute canvas ("id" :: JSString) ("screen" :: JSString)
+            setAttribute canvas ("style" :: JSString)
+                ("cursor: default; width: 100vw; height: 100vh;" :: JSString)
+            _ <- appendChild body canvas
+            return canvas
+
 foreign import javascript unsafe "showCanvas()"
-    showCanvas :: IO ()
+    js_showCanvas :: IO ()
 
 canvasFromElement :: Element -> Canvas.Canvas
 canvasFromElement = Canvas.Canvas . unElement
@@ -769,8 +790,8 @@
         setCanvasSize (elementFromCanvas offscreenCanvas) canvas
         rect <- getBoundingClientRect canvas
         withScreen (elementFromCanvas offscreenCanvas) rect (drawFrame pic)
-        cw <- ClientRect.getWidth rect
-        ch <- ClientRect.getHeight rect
+        cw <- DOMRect.getWidth rect
+        ch <- DOMRect.getHeight rect
         when (cw > 0.5 && ch > 0.5) $
             canvasDrawImage screen (elementFromCanvas offscreenCanvas)
                             0 0 (round cw) (round ch)
@@ -859,15 +880,15 @@
         let nodeName = trim 80 . describePicture $ pic
         let nodeSrcLoc = getPictureSrcLoc pic
         nodeSubs <- getSubNodes
-        pure Node{..}
+        pure (Node {..})
 
 foreign import javascript unsafe "/\\bmode=haskell\\b/.test(location.search)"
     haskellMode :: Bool
 
-withScreen :: Element -> ClientRect.ClientRect -> CanvasM a -> IO a
+withScreen :: Element -> DOMRect.DOMRect -> CanvasM a -> IO a
 withScreen canvas rect action = do
-    cw <- realToFrac <$> ClientRect.getWidth rect
-    ch <- realToFrac <$> ClientRect.getHeight rect
+    cw <- realToFrac <$> DOMRect.getWidth rect
+    ch <- realToFrac <$> DOMRect.getHeight rect
     ctx <- getCodeWorldContext (canvasFromElement canvas)
     runCanvasM (cw, ch) ctx $ CM.saveRestore $ do
         setupScreenContext (round cw) (round ch)
@@ -876,8 +897,8 @@
 setCanvasSize :: Element -> Element -> IO ()
 setCanvasSize target canvas = do
     rect <- getBoundingClientRect canvas
-    cx <- ClientRect.getWidth rect
-    cy <- ClientRect.getHeight rect
+    cx <- DOMRect.getWidth rect
+    cy <- DOMRect.getHeight rect
     setAttribute target ("width" :: JSString) (show (round cx :: Int))
     setAttribute target ("height" :: JSString) (show (round cy :: Int))
 
@@ -916,106 +937,111 @@
 
 keyCodeToText :: Word -> Text
 keyCodeToText n =
-    case n of
-        _ | n >= 47 && n <= 90 -> fromAscii n
-        _ | n >= 96 && n <= 105 -> fromNum (n - 96)
-        _ | n >= 112 && n <= 135 -> "F" <> fromNum (n - 111)
-        3 -> "Cancel"
-        6 -> "Help"
-        8 -> "Backspace"
-        9 -> "Tab"
-        12 -> "5"
-        13 -> "Enter"
-        16 -> "Shift"
-        17 -> "Ctrl"
-        18 -> "Alt"
-        19 -> "Break"
-        20 -> "CapsLock"
-        27 -> "Esc"
-        32 -> " "
-        33 -> "PageUp"
-        34 -> "PageDown"
-        35 -> "End"
-        36 -> "Home"
-        37 -> "Left"
-        38 -> "Up"
-        39 -> "Right"
-        40 -> "Down"
-        42 -> "*"
-        43 -> "+"
-        44 -> "PrintScreen"
-        45 -> "Insert"
-        46 -> "Delete"
-        47 -> "Help"
-        91 -> "OS"
-        92 -> "OS"
-        93 -> "ContextMenu"
-        106 -> "*"
-        107 -> "+"
-        108 -> ","
-        109 -> "-"
-        110 -> "."
-        111 -> "/"
-        144 -> "NumLock"
-        145 -> "ScrollLock"
-        173 -> "-"
-        186 -> ";"
-        187 -> "="
-        188 -> ","
-        189 -> "-"
-        190 -> "."
-        191 -> "/"
-        192 -> "`"
-        193 -> "IntlRo"
-        194 -> ","
-        219 -> "["
-        220 -> "\\"
-        221 -> "]"
-        222 -> "'"
-        225 -> "AltGraph"
-        255 -> "IntlYen"
-        _ -> "Unknown:" <> fromNum n
+  case n of
+    _ | n >= 47 && n <= 90 -> fromAscii n
+    _ | n >= 96 && n <= 105 -> fromNum (n - 96)
+    _ | n >= 112 && n <= 135 -> "F" <> fromNum (n - 111)
+    3 -> "Cancel"
+    6 -> "Help"
+    8 -> "Backspace"
+    9 -> "Tab"
+    12 -> "5"
+    13 -> "Enter"
+    16 -> "Shift"
+    17 -> "Ctrl"
+    18 -> "Alt"
+    19 -> "Break"
+    20 -> "CapsLock"
+    27 -> "Esc"
+    32 -> " "
+    33 -> "PageUp"
+    34 -> "PageDown"
+    35 -> "End"
+    36 -> "Home"
+    37 -> "Left"
+    38 -> "Up"
+    39 -> "Right"
+    40 -> "Down"
+    42 -> "*"
+    43 -> "+"
+    44 -> "PrintScreen"
+    45 -> "Insert"
+    46 -> "Delete"
+    47 -> "Help"
+    91 -> "OS"
+    92 -> "OS"
+    93 -> "ContextMenu"
+    106 -> "*"
+    107 -> "+"
+    108 -> ","
+    109 -> "-"
+    110 -> "."
+    111 -> "/"
+    144 -> "NumLock"
+    145 -> "ScrollLock"
+    173 -> "-"
+    186 -> ";"
+    187 -> "="
+    188 -> ","
+    189 -> "-"
+    190 -> "."
+    191 -> "/"
+    192 -> "`"
+    193 -> "IntlRo"
+    194 -> ","
+    219 -> "["
+    220 -> "\\"
+    221 -> "]"
+    222 -> "'"
+    225 -> "AltGraph"
+    255 -> "IntlYen"
+    _ -> "Unknown:" <> fromNum n
   where
     fromAscii n = T.singleton (chr (fromIntegral n))
     fromNum n = T.pack (show n)
 
 isUniversallyConstant :: (a -> s -> s) -> s -> Bool
 isUniversallyConstant f old =
-    unsafePerformIO $ falseOr $ do
-        oldName <- makeStableName $! old
-        genName <- makeStableName $! f undefined old
-        return (genName == oldName)
+  unsafePerformIO $ falseOr $ do
+    oldName <- makeStableName $! old
+    genName <- makeStableName $! f undefined old
+    return (genName == oldName)
   where
     falseOr x = x `catch` \(_ :: SomeException) -> return False
 
 ifDifferent :: (s -> s) -> s -> Maybe s
 ifDifferent f s0 = unsafePerformIO $ do
-    oldName <- makeStableName $! s0
-    newName <- makeStableName $! s1
-    if newName == oldName then return Nothing else return (Just s1)
-  where s1 = f s0
+  oldName <- makeStableName $! s0
+  newName <- makeStableName $! s1
+  if newName == oldName then return Nothing else return (Just s1)
+  where
+    s1 = f s0
 
 modifyMVarIfDifferent :: MVar s -> (s -> s) -> IO Bool
 modifyMVarIfDifferent var f =
-    modifyMVar var $ \s0 ->
-        case ifDifferent f s0 of
-            Nothing -> return (s0, False)
-            Just s1 -> return (s1, True)
+  modifyMVar var $ \s0 ->
+    case ifDifferent f s0 of
+      Nothing -> return (s0, False)
+      Just s1 -> return (s1, True)
 
 data GameToken
-    = FullToken { tokenDeployHash :: Text
-                , tokenNumPlayers :: Int
-                , tokenInitial :: StaticKey
-                , tokenStep :: StaticKey
-                , tokenEvent :: StaticKey
-                , tokenDraw :: StaticKey }
-    | SteplessToken { tokenDeployHash :: Text
-                    , tokenNumPlayers :: Int
-                    , tokenInitial :: StaticKey
-                    , tokenEvent :: StaticKey
-                    , tokenDraw :: StaticKey }
-    | PartialToken { tokenDeployHash :: Text }
-    deriving (Generic)
+  = FullToken
+      { tokenDeployHash :: Text,
+        tokenNumPlayers :: Int,
+        tokenInitial :: StaticKey,
+        tokenStep :: StaticKey,
+        tokenEvent :: StaticKey,
+        tokenDraw :: StaticKey
+      }
+  | SteplessToken
+      { tokenDeployHash :: Text,
+        tokenNumPlayers :: Int,
+        tokenInitial :: StaticKey,
+        tokenEvent :: StaticKey,
+        tokenDraw :: StaticKey
+      }
+  | PartialToken {tokenDeployHash :: Text}
+  deriving (Generic)
 
 deriving instance Generic Fingerprint
 
@@ -1031,10 +1057,10 @@
 screenCoordsToPoint :: Element -> Double -> Double -> IO Point
 screenCoordsToPoint canvas sx sy = do
     rect <- getBoundingClientRect canvas
-    cx <- realToFrac <$> ClientRect.getLeft rect
-    cy <- realToFrac <$> ClientRect.getTop rect
-    cw <- realToFrac <$> ClientRect.getWidth rect
-    ch <- realToFrac <$> ClientRect.getHeight rect
+    cx <- realToFrac <$> DOMRect.getX rect
+    cy <- realToFrac <$> DOMRect.getY rect
+    cw <- realToFrac <$> DOMRect.getWidth rect
+    ch <- realToFrac <$> DOMRect.getHeight rect
     let unitLen = min cw ch / 20
     let midx = cx + cw / 2
     let midy = cy + ch / 2
@@ -1292,16 +1318,13 @@
     enableDeterministicMath
     let fullStepHandler dt = stepHandler dt . eventHandler (-1) (TimePassing dt)
 
-    Just window <- currentWindow
-    Just doc <- currentDocument
-    Just canvas <- getElementById doc ("screen" :: JSString)
-
+    canvas <- getCanvas
     setCanvasSize canvas canvas
+
+    Just window <- currentWindow
     _ <- on window resize $ do
         liftIO $ setCanvasSize canvas canvas
 
-    showCanvas
-
     frameRenderer <- createFrameRenderer canvas
 
     currentGameState <- newMVar initialGameState
@@ -1344,18 +1367,15 @@
 run initial stepHandler eventHandler drawHandler injectTime = do
     let fullStepHandler dt = stepHandler dt . eventHandler (injectTime dt)
 
-    Just window <- currentWindow
-    Just doc <- currentDocument
-    Just canvas <- getElementById doc ("screen" :: JSString)
+    canvas <- getCanvas
 
     needsRedraw <- newMVar ()
+    Just window <- currentWindow
     _ <- on window resize $ void $ liftIO $ do
         setCanvasSize canvas canvas
         tryPutMVar needsRedraw ()
     setCanvasSize canvas canvas
 
-    showCanvas
-
     frameRenderer <- createFrameRenderer canvas
     currentState <- newMVar initial
     eventHappened <- newMVar ()
@@ -1400,10 +1420,10 @@
 getNodeAtCoords :: Element -> Double -> Double -> Picture -> IO (Maybe NodeId)
 getNodeAtCoords canvas x y pic = do
     rect <- getBoundingClientRect canvas
-    cx <- realToFrac <$> ClientRect.getLeft rect
-    cy <- realToFrac <$> ClientRect.getTop rect
-    cw <- realToFrac <$> ClientRect.getWidth rect
-    ch <- realToFrac <$> ClientRect.getHeight rect
+    cx <- realToFrac <$> DOMRect.getX rect
+    cy <- realToFrac <$> DOMRect.getY rect
+    cw <- realToFrac <$> DOMRect.getWidth rect
+    ch <- realToFrac <$> DOMRect.getHeight rect
 
     -- It's safe to pass undefined for the context because
     -- findTopShapeFromPoint only draws to an offscreen buffer.
@@ -1518,12 +1538,6 @@
     -- Sample the current user picture to return the scene tree.
     getPicCB <- syncCallback' $ samplePicture >>= toJSVal_aeson . pictureToNode
 
-    -- Sample the current user picture to draw to a canvas.
-    drawCB <- syncCallback2 ContinueAsync $ \c n -> do
-        let canvas = unsafeCoerce c :: Element
-        let nodeId = NodeId (pFromJSVal n)
-        drawPartialPic canvas nodeId =<< samplePicture
-
     -- Fire an event to change debug active state.
     setActiveCB <- syncCallback1 ContinueAsync $ \ active -> case pFromJSVal active of
         True  -> fireUpdate startDebugState
@@ -1537,14 +1551,13 @@
         if isHighlight then fireUpdate (highlightDebugState nodeId)
                        else fireUpdate (selectDebugState nodeId)
 
-    js_initDebugMode getNodeCB setActiveCB getPicCB highlightCB drawCB
+    js_initDebugMode getNodeCB setActiveCB getPicCB highlightCB
 
-foreign import javascript unsafe "initDebugMode($1,$2,$3,$4,$5)"
+foreign import javascript unsafe "initDebugMode($1,$2,$3,$4)"
     js_initDebugMode :: Callback (JSVal -> IO JSVal)
                      -> Callback (JSVal -> IO ())
                      -> Callback (IO JSVal)
                      -> Callback (JSVal -> JSVal -> IO ())
-                     -> Callback (JSVal -> JSVal -> IO ())
                      -> IO ()
 
 -- Utility functions that apply a function in either the left or right half of a
@@ -1584,8 +1597,6 @@
     -- there are deferred type errors that are effectively compile errors.
     evaluate $ rnf $ rawDraw initial
 
-    Just doc <- currentDocument
-    Just canvas <- getElementById doc ("screen" :: JSString)
     let debugInitial = (debugStateInit, initial)
         debugStep dt s@(debugState, _) =
             case debugStateActive debugState of
@@ -1601,8 +1612,11 @@
         debugRawDraw (_debugState, s) = rawDraw s
     (sendEvent, getState) <-
         run debugInitial debugStep debugEvent debugDraw (Right . TimePassing)
+
+    canvas <- getCanvas
     onEvents canvas (sendEvent . Right)
     connectInspect canvas (debugRawDraw <$> getState) (sendEvent . Left)
+
     waitForever
 
 #else
@@ -1621,7 +1635,7 @@
     my = h' / 2
 
 toEvent :: (Int, Int) -> Canvas.Event -> Maybe Event
-toEvent rect Canvas.Event {..}
+toEvent rect (Canvas.Event {..})
     | eType == "keydown"
     , Just code <- eWhich = Just $ KeyPress (keyCodeToText (fromIntegral code))
     | eType == "keyup"
@@ -1715,8 +1729,8 @@
 --------------------------------------------------------------------------------
 -- FRP implementation
 
-data ReactiveInput t = ReactiveInput {
-    keyPress :: R.Event t Text,
+data ReactiveInput t = ReactiveInput
+  { keyPress :: R.Event t Text,
     keyRelease :: R.Event t Text,
     textEntry :: R.Event t Text,
     pointerPress :: R.Event t Point,
@@ -1724,86 +1738,98 @@
     pointerPosition :: R.Dynamic t Point,
     pointerDown :: R.Dynamic t Bool,
     timePassing :: R.Event t Double
-    }
+  }
 
-data ReactiveOutput = ReactiveOutput {
-    userPictures :: [Picture],
+data ReactiveOutput = ReactiveOutput
+  { userPictures :: [Picture],
     userTransform :: Picture -> Picture,
     systemPicture :: Picture
-    }
+  }
 
 instance Semigroup ReactiveOutput where
-    a <> b = ReactiveOutput {
-        userPictures = userPictures a ++ userPictures b,
+  a <> b =
+    ReactiveOutput
+      { userPictures = userPictures a ++ userPictures b,
         userTransform = userTransform a . userTransform b,
         systemPicture = systemPicture a & systemPicture b
-        }
+      }
 
 instance Monoid ReactiveOutput where
-    mempty = ReactiveOutput [] id blank
+  mempty = ReactiveOutput [] id blank
 
-newtype ReactiveProgram t m a = ReactiveProgram {
-    unReactiveProgram :: ReaderT (ReactiveInput t) (R.DynamicWriterT t ReactiveOutput m) a
-    }
+newtype ReactiveProgram t m a = ReactiveProgram
+  { unReactiveProgram :: ReaderT (ReactiveInput t) (R.DynamicWriterT t ReactiveOutput m) a
+  }
 
 deriving instance Functor m => Functor (ReactiveProgram t m)
+
 deriving instance Monad m => Applicative (ReactiveProgram t m)
+
 deriving instance Monad m => Monad (ReactiveProgram t m)
+
 deriving instance MonadFix m => MonadFix (ReactiveProgram t m)
+
 deriving instance MonadIO m => MonadIO (ReactiveProgram t m)
+
 deriving instance R.MonadSample t m => R.MonadSample t (ReactiveProgram t m)
+
 deriving instance R.MonadHold t m => R.MonadHold t (ReactiveProgram t m)
+
 deriving instance R.NotReady t m => R.NotReady t (ReactiveProgram t m)
+
 deriving instance R.PerformEvent t m => R.PerformEvent t (ReactiveProgram t m)
+
 deriving instance R.TriggerEvent t m => R.TriggerEvent t (ReactiveProgram t m)
+
 deriving instance R.PostBuild t m => R.PostBuild t (ReactiveProgram t m)
 
 instance (MonadFix m, R.MonadHold t m, R.Adjustable t m) => R.Adjustable t (ReactiveProgram t m) where
-    runWithReplace a0 a' =
-        ReactiveProgram $ R.runWithReplace (unReactiveProgram a0) $ fmap unReactiveProgram a'
-    traverseIntMapWithKeyWithAdjust f dm0 dm' =
-        ReactiveProgram $ R.traverseIntMapWithKeyWithAdjust (\k v -> unReactiveProgram (f k v)) dm0 dm'
-    traverseDMapWithKeyWithAdjust f dm0 dm' =
-        ReactiveProgram $ R.traverseDMapWithKeyWithAdjust (\k v -> unReactiveProgram (f k v)) dm0 dm'
-    traverseDMapWithKeyWithAdjustWithMove f dm0 dm' =
-        ReactiveProgram $ R.traverseDMapWithKeyWithAdjustWithMove (\k v -> unReactiveProgram (f k v)) dm0 dm'
+  runWithReplace a0 a' =
+    ReactiveProgram $ R.runWithReplace (unReactiveProgram a0) $ fmap unReactiveProgram a'
+  traverseIntMapWithKeyWithAdjust f dm0 dm' =
+    ReactiveProgram $ R.traverseIntMapWithKeyWithAdjust (\k v -> unReactiveProgram (f k v)) dm0 dm'
+  traverseDMapWithKeyWithAdjust f dm0 dm' =
+    ReactiveProgram $ R.traverseDMapWithKeyWithAdjust (\k v -> unReactiveProgram (f k v)) dm0 dm'
+  traverseDMapWithKeyWithAdjustWithMove f dm0 dm' =
+    ReactiveProgram $ R.traverseDMapWithKeyWithAdjustWithMove (\k v -> unReactiveProgram (f k v)) dm0 dm'
 
-runReactiveProgram
-    :: (R.Reflex t, MonadFix m)
-    => ReactiveProgram t m ()
-    -> ReactiveInput t
-    -> m (R.Dynamic t Picture, R.Dynamic t Picture)
+runReactiveProgram ::
+  (R.Reflex t, MonadFix m) =>
+  ReactiveProgram t m () ->
+  ReactiveInput t ->
+  m (R.Dynamic t Picture, R.Dynamic t Picture)
 runReactiveProgram (ReactiveProgram program) input = do
-    (_, output) <- R.runDynamicWriterT (runReaderT program input)
-    let pic = coalescePics . userPictures <$> output
-    let sysPic = (&) <$> (systemPicture <$> output)
-                     <*> (userTransform <$> output <*> pic)
-    return (pic, sysPic)
-  where coalescePics []  = blank
-        coalescePics [p] = p
-        coalescePics ps  = pictures ps
+  (_, output) <- R.runDynamicWriterT (runReaderT program input)
+  let pic = coalescePics . userPictures <$> output
+  let sysPic =
+        (&) <$> (systemPicture <$> output)
+          <*> (userTransform <$> output <*> pic)
+  return (pic, sysPic)
+  where
+    coalescePics [] = blank
+    coalescePics [p] = p
+    coalescePics ps = pictures ps
 
-withReactiveInput
-    :: ReactiveInput t
-    -> (ReactiveProgram t m a -> ReactiveProgram t m a)
-withReactiveInput input (ReactiveProgram program)
-    = ReactiveProgram (withReaderT (const input) program)
+withReactiveInput ::
+  ReactiveInput t ->
+  (ReactiveProgram t m a -> ReactiveProgram t m a)
+withReactiveInput input (ReactiveProgram program) =
+  ReactiveProgram (withReaderT (const input) program)
 
 getReactiveInput :: Monad m => ReactiveProgram t m (ReactiveInput t)
 getReactiveInput = ReactiveProgram ask
 
 systemDraw :: (R.Reflex t, Monad m) => R.Dynamic t Picture -> ReactiveProgram t m ()
-systemDraw = ReactiveProgram . R.tellDyn . fmap (\a -> mempty { systemPicture = a })
+systemDraw = ReactiveProgram . R.tellDyn . fmap (\a -> mempty {systemPicture = a})
 
-transformUserPicture
-    :: (R.Reflex t, Monad m) => R.Dynamic t (Picture -> Picture) -> ReactiveProgram t m ()
+transformUserPicture ::
+  (R.Reflex t, Monad m) => R.Dynamic t (Picture -> Picture) -> ReactiveProgram t m ()
 transformUserPicture =
-    ReactiveProgram . R.tellDyn . fmap (\a -> mempty { userTransform = a })
+  ReactiveProgram . R.tellDyn . fmap (\a -> mempty {userTransform = a})
 
 -- | Type class for the builder monad of a CodeWorld/Reflex app.
 class
-  (
-    R.Reflex t,
+  ( R.Reflex t,
     R.Adjustable t m,
     R.MonadHold t m,
     R.NotReady t m,
@@ -1813,35 +1839,37 @@
     MonadFix m,
     MonadIO m,
     MonadIO (R.Performable m)
-  ) => ReflexCodeWorld t m | m -> t where
-    -- | Gets an Event of key presses.  The event value is a logical key name.
-    getKeyPress :: m (R.Event t Text)
+  ) =>
+  ReflexCodeWorld t m
+    | m -> t
+  where
+  -- | Gets an Event of key presses.  The event value is a logical key name.
+  getKeyPress :: m (R.Event t Text)
 
-    -- | Gets an Event of key presses.  The event value is a logical key name.
-    getKeyRelease :: m (R.Event t Text)
+  -- | Gets an Event of key presses.  The event value is a logical key name.
+  getKeyRelease :: m (R.Event t Text)
 
-    -- | Gets an Event of text entered.  The event value is the typed text.
-    getTextEntry :: m (R.Event t Text)
+  -- | Gets an Event of text entered.  The event value is the typed text.
+  getTextEntry :: m (R.Event t Text)
 
-    -- | Gets an event of pointer clicks.  The event value is the location of
-    -- the click.
-    getPointerClick :: m (R.Event t Point)
+  -- | Gets an event of pointer clicks.  The event value is the location of
+  -- the click.
+  getPointerClick :: m (R.Event t Point)
 
-    -- | Gets the Dynamic position of the pointer.
-    getPointerPosition :: m (R.Dynamic t Point)
+  -- | Gets the Dynamic position of the pointer.
+  getPointerPosition :: m (R.Dynamic t Point)
 
-    -- | Gets a Dynamic indicator whether the pointer is held down.
-    isPointerDown :: m (R.Dynamic t Bool)
+  -- | Gets a Dynamic indicator whether the pointer is held down.
+  isPointerDown :: m (R.Dynamic t Bool)
 
-    -- | Gets an Event indicating the passage of time.
-    getTimePassing :: m (R.Event t Double)
+  -- | Gets an Event indicating the passage of time.
+  getTimePassing :: m (R.Event t Double)
 
-    -- | Emits a given Dynamic picture to be drawn to the screen.
-    draw :: R.Dynamic t Picture -> m ()
+  -- | Emits a given Dynamic picture to be drawn to the screen.
+  draw :: R.Dynamic t Picture -> m ()
 
 instance
-  (
-    R.Reflex t,
+  ( R.Reflex t,
     R.Adjustable t m,
     R.MonadHold t m,
     R.NotReady t m,
@@ -1851,22 +1879,24 @@
     MonadFix m,
     MonadIO m,
     MonadIO (R.Performable m)
-  ) => ReflexCodeWorld t (ReactiveProgram t m) where
-    getKeyPress = ReactiveProgram $ asks keyPress
+  ) =>
+  ReflexCodeWorld t (ReactiveProgram t m)
+  where
+  getKeyPress = ReactiveProgram $ asks keyPress
 
-    getKeyRelease = ReactiveProgram $ asks keyRelease
+  getKeyRelease = ReactiveProgram $ asks keyRelease
 
-    getTextEntry = ReactiveProgram $ asks textEntry
+  getTextEntry = ReactiveProgram $ asks textEntry
 
-    getPointerClick = ReactiveProgram $ asks pointerPress
+  getPointerClick = ReactiveProgram $ asks pointerPress
 
-    getPointerPosition = ReactiveProgram $ asks pointerPosition
+  getPointerPosition = ReactiveProgram $ asks pointerPosition
 
-    isPointerDown = ReactiveProgram $ asks pointerDown
+  isPointerDown = ReactiveProgram $ asks pointerDown
 
-    getTimePassing = ReactiveProgram $ asks timePassing
+  getTimePassing = ReactiveProgram $ asks timePassing
 
-    draw = ReactiveProgram . R.tellDyn . fmap (\a -> mempty { userPictures = [a] })
+  draw = ReactiveProgram . R.tellDyn . fmap (\a -> mempty {userPictures = [a]})
 
 gateDyn :: forall t a. R.Reflex t => R.Dynamic t Bool -> R.Event t a -> R.Event t a
 gateDyn dyn e = R.switchDyn (bool R.never e <$> dyn)
@@ -1874,29 +1904,30 @@
 type EventChannel t = Chan [DSum (R.EventTriggerRef t) R.TriggerInvocation]
 
 -- | Handle the event channel used with 'runTriggerEventT'.
-asyncProcessEventTriggers
-    :: EventChannel t
-    -> R.FireCommand t (R.SpiderHost R.Global)
-    -> IO ThreadId
+asyncProcessEventTriggers ::
+  EventChannel t ->
+  R.FireCommand t (R.SpiderHost R.Global) ->
+  IO ThreadId
 asyncProcessEventTriggers events fireCommand = forkIO . forever $ do
-    -- Collect event triggers, and fire callbacks after propagation
-    eventsAndTriggers <- readChan events
-    eventsToFire <- flip wither eventsAndTriggers $
-        \(R.EventTriggerRef ref :=> R.TriggerInvocation a _) ->
-            fmap (==> a) <$> readRef ref
-    void . R.runSpiderHost $
-        R.runFireCommand fireCommand eventsToFire (pure ())
-    -- Run callbacks
-    traverse_ (\(_ :=> R.TriggerInvocation _ cb) -> cb) eventsAndTriggers
+  -- Collect event triggers, and fire callbacks after propagation
+  eventsAndTriggers <- readChan events
+  eventsToFire <- flip wither eventsAndTriggers $
+    \(R.EventTriggerRef ref :=> R.TriggerInvocation a _) ->
+      fmap (==> a) <$> readRef ref
+  void . R.runSpiderHost $
+    R.runFireCommand fireCommand eventsToFire (pure ())
+  -- Run callbacks
+  traverse_ (\(_ :=> R.TriggerInvocation _ cb) -> cb) eventsAndTriggers
 
-sendEvent
-    :: R.FireCommand t (R.SpiderHost R.Global)
-    -> IORef (Maybe (R.EventTrigger t a))
-    -> a
-    -> IO ()
+sendEvent ::
+  R.FireCommand t (R.SpiderHost R.Global) ->
+  IORef (Maybe (R.EventTrigger t a)) ->
+  a ->
+  IO ()
 sendEvent (R.FireCommand fire) triggerRef a =
-    R.runSpiderHost $ readRef triggerRef
-        >>= traverse_ (\t -> fire [t ==> a] (pure ()))
+  R.runSpiderHost $
+    readRef triggerRef
+      >>= traverse_ (\t -> fire [t ==> a] (pure ()))
 
 #ifdef ghcjs_HOST_OS
 
@@ -1957,7 +1988,7 @@
     pointerDown <- R.holdDyn False $
         R.leftmost [True <$ pointerPress, False <$ pointerRelease]
 
-    return ReactiveInput{..}
+    return (ReactiveInput {..})
 
 inspectLogicalInput
     :: forall t m. (R.Reflex t, R.MonadHold t m)
@@ -2001,11 +2032,7 @@
         ) => (ReactiveInput t -> m (R.Dynamic t Picture, R.Dynamic t Picture)))
     -> IO ()
 runReactive program = do
-    showCanvas
-
-    Just window <- currentWindow
-    Just doc <- currentDocument
-    Just canvas <- getElementById doc ("screen" :: JSString)
+    canvas <- getCanvas
     setCanvasSize canvas canvas
 
     frameRenderer <- createFrameRenderer canvas
@@ -2021,6 +2048,8 @@
     (debugUpdate, debugUpdateTriggerRef) <- R.runSpiderHost R.newEventWithTriggerRef
     debugState <- R.runSpiderHost $ R.holdUniqDyn =<< R.foldDyn ($) debugStateInit debugUpdate
 
+    Just window <- currentWindow
+
     rec
         physicalInput <- R.runSpiderHost $
             createPhysicalReactiveInput window canvas fireAndRedraw
@@ -2099,7 +2128,7 @@
     pointerDown <- R.runSpiderHost $ R.holdDyn False $
         R.leftmost [True <$ pointerPress, False <$ pointerRelease]
 
-    let input = ReactiveInput{..}
+    let input = ReactiveInput {..}
 
     triggeredEvents <- newChan
     (_, fireCommand) <- R.runSpiderHost $ R.hostPerformEventT $ do
diff --git a/src/CodeWorld/EntryPoints.hs b/src/CodeWorld/EntryPoints.hs
--- a/src/CodeWorld/EntryPoints.hs
+++ b/src/CodeWorld/EntryPoints.hs
@@ -8,7 +8,7 @@
 {-# OPTIONS_GHC -Wno-name-shadowing #-}
 
 {-
-  Copyright 2019 The CodeWorld Authors. All rights reserved.
+  Copyright 2020 The CodeWorld Authors. All rights reserved.
 
   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
@@ -72,74 +72,48 @@
   --   the state into a picture to display.
   (world -> Picture) ->
   IO ()
-activityOf initial change picture =
-  interactionOf initial (const id) change picture
-
--- | Runs an interactive event-driven CodeWorld program.  This is a
--- generalization of simulations that can respond to events like key presses
--- and mouse movement.
-interactionOf ::
-  -- | The initial state of the interaction.
-  world ->
-  -- | The time step function, which advances
-  --   the state given the time difference.
-  (Double -> world -> world) ->
-  -- | The event handling function, which updates
-  --   the state given a user interface event.
-  (Event -> world -> world) ->
-  -- | The visualization function, which converts
-  --   the state into a picture to display.
-  (world -> Picture) ->
-  IO ()
-interactionOf initial step event draw = do
+activityOf initial change picture = do
   hFlush stdout
-  runInspect initial step event draw draw
-{-# WARNING
-  interactionOf
-  [ "Please use activityOf instead of interactionOf.",
-    "interactionOf may be removed July 2020."
-  ]
-  #-}
+  runInspect initial (const id) change picture picture
 
-data Timeline a
-  = Timeline
-      { past :: [a], -- reversed list of past states
-        present :: !a, -- present state
-        future :: [a] -- list of future states
-      }
+data Timeline a = Timeline
+  { past :: [a], -- reversed list of past states
+    present :: !a, -- present state
+    future :: [a] -- list of future states
+  }
 
 newTimeline :: a -> Timeline a
 newTimeline x = Timeline [] x []
 
 applyToTimeline :: (a -> a) -> Timeline a -> Timeline a
-applyToTimeline f timeline@Timeline {..}
+applyToTimeline f timeline@(Timeline {..})
   | identical present new = timeline
   | otherwise = Timeline (present : past) new []
   where
     new = f present
 
 undoTimeline :: Timeline a -> Timeline a
-undoTimeline timeline@Timeline {..} = case past of
+undoTimeline timeline@(Timeline {..}) = case past of
   [] -> timeline
   (x : xs) -> Timeline xs x (present : future)
 
 redoTimeline :: Timeline a -> Timeline a
-redoTimeline timeline@Timeline {..} = case future of
+redoTimeline timeline@(Timeline {..}) = case future of
   [] -> timeline
   (x : xs) -> Timeline (present : past) x xs
 
 restartTimeline :: Timeline a -> Timeline a
-restartTimeline timeline@Timeline {..}
+restartTimeline timeline@(Timeline {..})
   | null past = timeline
   | otherwise = Timeline [] x (xs ++ present : future)
   where
     x : xs = reverse past
 
 timelineLength :: Timeline a -> Int
-timelineLength Timeline {..} = length past + 1 + length future
+timelineLength (Timeline {..}) = length past + 1 + length future
 
 travelToTime :: Double -> Timeline a -> Timeline a
-travelToTime t timeline@Timeline {..}
+travelToTime t timeline@(Timeline {..})
   | diff >= 0 = iterate redoTimeline timeline !! diff
   | otherwise = iterate undoTimeline timeline !! (- diff)
   where
@@ -148,7 +122,7 @@
     diff = desiredPast - actualPast
 
 timelinePos :: Timeline a -> Double
-timelinePos Timeline {..}
+timelinePos (Timeline {..})
   | null past && null future = 1
   | otherwise = fromIntegral (length past) / fromIntegral (length past + length future)
 
@@ -175,32 +149,32 @@
 
 data StrictMaybe a = SNothing | SJust !a deriving (Functor, Show)
 
-data Wrapped a
-  = Wrapped
-      { state :: a,
-        playbackSpeed :: !Double,
-        lastInteractionTime :: !Double,
-        zoomFactor :: !Double,
-        panCenter :: !StrictPoint,
-        panDraggingAnchor :: !(StrictMaybe StrictPoint),
-        isDraggingSpeed :: !Bool,
-        isDraggingHistory :: !Bool,
-        isDraggingZoom :: !Bool
-      }
+data Wrapped a = Wrapped
+  { state :: a,
+    playbackSpeed :: !Double,
+    lastInteractionTime :: !Double,
+    zoomFactor :: !Double,
+    panCenter :: !StrictPoint,
+    panDraggingAnchor :: !(StrictMaybe StrictPoint),
+    isDraggingSpeed :: !Bool,
+    isDraggingHistory :: !Bool,
+    isDraggingZoom :: !Bool
+  }
   deriving (Show, Functor)
 
 wrappedInitial :: a -> Wrapped a
-wrappedInitial w = Wrapped
-  { state = w,
-    playbackSpeed = 1,
-    lastInteractionTime = 1000,
-    zoomFactor = 1,
-    panCenter = SP 0 0,
-    panDraggingAnchor = SNothing,
-    isDraggingSpeed = False,
-    isDraggingHistory = False,
-    isDraggingZoom = False
-  }
+wrappedInitial w =
+  Wrapped
+    { state = w,
+      playbackSpeed = 1,
+      lastInteractionTime = 1000,
+      zoomFactor = 1,
+      panCenter = SP 0 0,
+      panDraggingAnchor = SNothing,
+      isDraggingSpeed = False,
+      isDraggingHistory = False,
+      isDraggingZoom = False
+    }
 
 identical :: a -> a -> Bool
 identical !x !y = isTrue# (reallyUnsafePtrEquality# x y)
@@ -679,95 +653,6 @@
       | playbackSpeed w == 0 = [PanningLayer]
       | otherwise = []
 
--- | Shows a simulation, which is essentially a continuous-time dynamical
--- system described by an initial value and step function.
-simulationOf ::
-  -- | The initial state of the simulation.
-  world ->
-  -- | The time step function, which advances
-  --   the state given the time difference.
-  (Double -> world -> world) ->
-  -- | The visualization function, which converts
-  --   the state into a picture to display.
-  (world -> Picture) ->
-  IO ()
-simulationOf initial step draw = do
-  hFlush stdout
-  runInspect
-    (wrappedInitial initial)
-    (wrappedStep step)
-    (wrappedEvent simulationControls step (const id))
-    (wrappedDraw simulationControls draw)
-    (draw . state)
-{-# WARNING
-  simulationOf
-  [ "Please use activityOf instead of simulationOf.",
-    "simulationOf may be removed July 2020."
-  ]
-  #-}
-
-debugSimulationOf ::
-  -- | The initial state of the simulation.
-  world ->
-  -- | The time step function, which advances
-  --   the state given the time difference.
-  (Double -> world -> world) ->
-  -- | The visualization function, which converts
-  --   the state into a picture to display.
-  (world -> Picture) ->
-  IO ()
-debugSimulationOf simInitial simStep simDraw = do
-  hFlush stdout
-  runInspect
-    (wrappedInitial initial)
-    (wrappedStep step)
-    (wrappedEvent statefulDebugControls step (const id))
-    (wrappedDraw statefulDebugControls draw)
-    (draw . state)
-  where
-    initial = newTimeline simInitial
-    step = applyToTimeline . simStep
-    draw = simDraw . present
-{-# WARNING
-  debugSimulationOf
-  [ "Please use debugActivityOf instead of debugSimulationOf.",
-    "debugSimulationOf may be removed July 2020."
-  ]
-  #-}
-
-debugInteractionOf ::
-  -- | The initial state of the interaction.
-  world ->
-  -- | The time step function, which advances
-  --   the state given the time difference.
-  (Double -> world -> world) ->
-  -- | The event handling function, which updates
-  --   the state given a user interface event.
-  (Event -> world -> world) ->
-  -- | The visualization function, which converts
-  --   the state into a picture to display.
-  (world -> Picture) ->
-  IO ()
-debugInteractionOf baseInitial baseStep baseEvent baseDraw = do
-  hFlush stdout
-  runInspect
-    (wrappedInitial initial)
-    (wrappedStep step)
-    (wrappedEvent statefulDebugControls step event)
-    (wrappedDraw statefulDebugControls draw)
-    (draw . state)
-  where
-    initial = newTimeline baseInitial
-    step = applyToTimeline . baseStep
-    event = applyToTimeline . baseEvent
-    draw = baseDraw . present
-{-# WARNING
-  debugInteractionOf
-  [ "Please use debugActivityOf instead of debugInteractionOf.",
-    "debugInteractionOf may be removed July 2020."
-  ]
-  #-}
-
 -- | A version of 'activityOf' which runs an interactive CodeWorld program
 -- in debugging mode.  In this mode, the program gets controls to pause and
 -- manipulate time, and even go back in time to look at past states.
@@ -781,8 +666,14 @@
   --   the state into a picture to display.
   (world -> Picture) ->
   IO ()
-debugActivityOf initial change picture =
-  debugInteractionOf initial (const id) change picture
+debugActivityOf initial change picture = do
+  hFlush stdout
+  runInspect
+    (wrappedInitial (newTimeline initial))
+    (wrappedStep (const id))
+    (wrappedEvent statefulDebugControls (const id) (applyToTimeline . change))
+    (wrappedDraw statefulDebugControls (picture . present))
+    (picture . present . state)
 
 -- | Runs an interactive multi-user CodeWorld program that is joined by several
 -- participants over the internet.
@@ -846,82 +737,11 @@
   --   and the state into a picture to display.
   (Int -> world -> Picture) ->
   IO ()
-unsafeGroupActivityOf numPlayers initial event draw =
-  unsafeCollaborationOf numPlayers initial (const id) event draw
-
--- | A version of 'collaborationOf' that avoids static pointers, and does not
--- check for consistent parameters.
-unsafeCollaborationOf ::
-  -- | The number of participants to expect.  The participants will be
-  -- numbered starting at 0.
-  Int ->
-  -- | The initial state of the collaboration.
-  (StdGen -> world) ->
-  -- | The time step function, which advances the state given the time
-  --   difference.
-  (Double -> world -> world) ->
-  -- | The event handling function, which updates the state given a
-  --   participant number and user interface event.
-  (Int -> Event -> world -> world) ->
-  -- | The visualization function, which converts a participant number
-  --   and the state into a picture to display.
-  (Int -> world -> Picture) ->
-  IO ()
-unsafeCollaborationOf numPlayers initial step event draw = do
+unsafeGroupActivityOf numPlayers initial event draw = do
   hFlush stdout
   dhash <- getDeployHash
   let token = PartialToken dhash
-  runGame token numPlayers initial step event draw
-{-# WARNING
-  unsafeCollaborationOf
-  [ "Please use unsafeGroupActivityOf instead of unsafeCollaborationOf.",
-    "unsafeCollaborationOf may be removed July 2020."
-  ]
-  #-}
-
--- | Runs an interactive multi-user CodeWorld program, involving multiple
--- participants over the internet.
-collaborationOf ::
-  -- | The number of participants to expect.  The participants will be
-  -- numbered starting at 0.
-  Int ->
-  -- | The initial state of the collaboration.
-  StaticPtr (StdGen -> world) ->
-  -- | The time step function, which advances the state given the time
-  --   difference.
-  StaticPtr (Double -> world -> world) ->
-  -- | The event handling function, which updates the state given a
-  --   participant number and user interface event.
-  StaticPtr (Int -> Event -> world -> world) ->
-  -- | The visualization function, which converts a participant number
-  --   and the state into a picture to display.
-  StaticPtr (Int -> world -> Picture) ->
-  IO ()
-collaborationOf numPlayers initial step event draw = do
-  hFlush stdout
-  dhash <- getDeployHash
-  let token =
-        FullToken
-          { tokenDeployHash = dhash,
-            tokenNumPlayers = numPlayers,
-            tokenInitial = staticKey initial,
-            tokenStep = staticKey step,
-            tokenEvent = staticKey event,
-            tokenDraw = staticKey draw
-          }
-  runGame
-    token
-    numPlayers
-    (deRefStaticPtr initial)
-    (deRefStaticPtr step)
-    (deRefStaticPtr event)
-    (deRefStaticPtr draw)
-{-# WARNING
-  collaborationOf
-  [ "Please use groupActivityOf instead of collaborationOf.",
-    "collaborationOf may be removed July 2020."
-  ]
-  #-}
+  runGame token numPlayers initial (const id) event draw
 
 -- | Prints a debug message to the CodeWorld console when a value is forced.
 -- This is equivalent to the similarly named function in `Debug.Trace`, except
diff --git a/src/CodeWorld/Event.hs b/src/CodeWorld/Event.hs
--- a/src/CodeWorld/Event.hs
+++ b/src/CodeWorld/Event.hs
@@ -1,7 +1,7 @@
 {-# LANGUAGE PatternSynonyms #-}
 
 {-
-  Copyright 2019 The CodeWorld Authors. All rights reserved.
+  Copyright 2020 The CodeWorld Authors. All rights reserved.
 
   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
diff --git a/src/CodeWorld/Image.hs b/src/CodeWorld/Image.hs
--- a/src/CodeWorld/Image.hs
+++ b/src/CodeWorld/Image.hs
@@ -1,5 +1,5 @@
 {-
-  Copyright 2019 The CodeWorld Authors. All rights reserved.
+  Copyright 2020 The CodeWorld Authors. All rights reserved.
 
   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
diff --git a/src/CodeWorld/Parameter.hs b/src/CodeWorld/Parameter.hs
--- a/src/CodeWorld/Parameter.hs
+++ b/src/CodeWorld/Parameter.hs
@@ -5,7 +5,7 @@
 {-# LANGUAGE RankNTypes #-}
 
 {-
-  Copyright 2019 The CodeWorld Authors. All rights reserved.
+  Copyright 2020 The CodeWorld Authors. All rights reserved.
 
   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
diff --git a/src/CodeWorld/Picture.hs b/src/CodeWorld/Picture.hs
--- a/src/CodeWorld/Picture.hs
+++ b/src/CodeWorld/Picture.hs
@@ -4,7 +4,7 @@
 {-# LANGUAGE TemplateHaskell #-}
 
 {-
-  Copyright 2019 The CodeWorld Authors. All rights reserved.
+  Copyright 2020 The CodeWorld Authors. All rights reserved.
 
   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
@@ -56,7 +56,8 @@
 -- point horizontally across the y axis.
 reflectedPoint :: Double -> Point -> Point
 reflectedPoint th (x, y) = (x * cos a + y * sin a, x * sin a - y * cos a)
-  where a = 2 * th
+  where
+    a = 2 * th
 
 -- | Scales a given point by given x and y scaling factor.  Scaling by a
 -- negative factor also reflects across that axis.
@@ -82,7 +83,7 @@
 -- >>> vectorLength (10, 10)
 -- 14.14
 vectorLength :: Vector -> Double
-vectorLength (x, y) = sqrt (x*x + y*y)
+vectorLength (x, y) = sqrt (x * x + y * y)
 
 -- | The counter-clockwise angle, in radians, that a given vector make with the X-axis
 --
@@ -118,7 +119,7 @@
 -- (6.123233995736766e-17, 1.0)
 rotatedVector :: Double -> Vector -> Vector
 rotatedVector angle (x, y) =
-    (x * cos angle - y * sin angle, x * sin angle + y * cos angle)
+  (x * cos angle - y * sin angle, x * sin angle + y * cos angle)
 
 -- | The dot product of two vectors
 dotProduct :: Vector -> Vector -> Double
@@ -134,50 +135,53 @@
 -- Ultimately, a picture can be drawn on the screen using one of the
 -- CodeWorld entry points such as 'drawingOf'.
 data Picture
-    = SolidPolygon (Maybe SrcLoc) [Point]
-    | SolidClosedCurve (Maybe SrcLoc) [Point]
-    | Polygon (Maybe SrcLoc) [Point]
-    | ThickPolygon (Maybe SrcLoc) [Point] !Double
-    | Rectangle (Maybe SrcLoc) !Double !Double
-    | SolidRectangle (Maybe SrcLoc) !Double !Double
-    | ThickRectangle (Maybe SrcLoc) !Double !Double !Double
-    | ClosedCurve (Maybe SrcLoc) [Point]
-    | ThickClosedCurve (Maybe SrcLoc) [Point] !Double
-    | Polyline (Maybe SrcLoc) [Point]
-    | ThickPolyline (Maybe SrcLoc) [Point] !Double
-    | Curve (Maybe SrcLoc) [Point]
-    | ThickCurve (Maybe SrcLoc) [Point] !Double
-    | Circle (Maybe SrcLoc) !Double
-    | SolidCircle (Maybe SrcLoc) !Double
-    | ThickCircle (Maybe SrcLoc) !Double !Double
-    | Sector (Maybe SrcLoc) !Double !Double !Double
-    | Arc (Maybe SrcLoc) !Double !Double !Double
-    | ThickArc (Maybe SrcLoc) !Double !Double !Double !Double
-    | StyledLettering (Maybe SrcLoc) !TextStyle !Font !Text
-    | Lettering (Maybe SrcLoc) !Text
-    | Color (Maybe SrcLoc) !Color !Picture
-    | Translate (Maybe SrcLoc) !Double !Double !Picture
-    | Scale (Maybe SrcLoc) !Double !Double !Picture
-    | Dilate (Maybe SrcLoc) !Double !Picture
-    | Rotate (Maybe SrcLoc) !Double !Picture
-    | Reflect (Maybe SrcLoc) !Double !Picture
-    | Clip (Maybe SrcLoc) !Double !Double !Picture
-    | CoordinatePlane (Maybe SrcLoc)
-    | Sketch (Maybe SrcLoc) !Text !Text !Double !Double
-    | Pictures (Maybe SrcLoc) [Picture]
-    | PictureAnd (Maybe SrcLoc) [Picture]
-    | Blank (Maybe SrcLoc)
-    deriving (Generic)
+  = SolidPolygon (Maybe SrcLoc) [Point]
+  | SolidClosedCurve (Maybe SrcLoc) [Point]
+  | Polygon (Maybe SrcLoc) [Point]
+  | ThickPolygon (Maybe SrcLoc) [Point] !Double
+  | Rectangle (Maybe SrcLoc) !Double !Double
+  | SolidRectangle (Maybe SrcLoc) !Double !Double
+  | ThickRectangle (Maybe SrcLoc) !Double !Double !Double
+  | ClosedCurve (Maybe SrcLoc) [Point]
+  | ThickClosedCurve (Maybe SrcLoc) [Point] !Double
+  | Polyline (Maybe SrcLoc) [Point]
+  | ThickPolyline (Maybe SrcLoc) [Point] !Double
+  | Curve (Maybe SrcLoc) [Point]
+  | ThickCurve (Maybe SrcLoc) [Point] !Double
+  | Circle (Maybe SrcLoc) !Double
+  | SolidCircle (Maybe SrcLoc) !Double
+  | ThickCircle (Maybe SrcLoc) !Double !Double
+  | Sector (Maybe SrcLoc) !Double !Double !Double
+  | Arc (Maybe SrcLoc) !Double !Double !Double
+  | ThickArc (Maybe SrcLoc) !Double !Double !Double !Double
+  | StyledLettering (Maybe SrcLoc) !TextStyle !Font !Text
+  | Lettering (Maybe SrcLoc) !Text
+  | Color (Maybe SrcLoc) !Color !Picture
+  | Translate (Maybe SrcLoc) !Double !Double !Picture
+  | Scale (Maybe SrcLoc) !Double !Double !Picture
+  | Dilate (Maybe SrcLoc) !Double !Picture
+  | Rotate (Maybe SrcLoc) !Double !Picture
+  | Reflect (Maybe SrcLoc) !Double !Picture
+  | Clip (Maybe SrcLoc) !Double !Double !Picture
+  | CoordinatePlane (Maybe SrcLoc)
+  | Sketch (Maybe SrcLoc) !Text !Text !Double !Double
+  | Pictures (Maybe SrcLoc) [Picture]
+  | PictureAnd (Maybe SrcLoc) [Picture]
+  | Blank (Maybe SrcLoc)
+  deriving (Generic)
 
 instance NFData Picture
 
 -- A style in which to draw lettering.  Either 'Plain', 'Bold', or
 -- 'Italic'
 data TextStyle
-    = Plain   -- ^ Plain letters with no style
-    | Bold    -- ^ Heavy, thick lettering used for emphasis
-    | Italic  -- ^ Slanted script-like lettering used for emphasis
-    deriving (Generic, Show)
+  = -- | Plain letters with no style
+    Plain
+  | -- | Heavy, thick lettering used for emphasis
+    Bold
+  | -- | Slanted script-like lettering used for emphasis
+    Italic
+  deriving (Generic, Show)
 
 instance NFData TextStyle
 
@@ -188,13 +192,13 @@
 -- installed on the computer running your program, a different font
 -- may be used instead.
 data Font
-    = SansSerif
-    | Serif
-    | Monospace
-    | Handwriting
-    | Fancy
-    | NamedFont !Text
-    deriving (Generic, Show)
+  = SansSerif
+  | Serif
+  | Monospace
+  | Handwriting
+  | Fancy
+  | NamedFont !Text
+  deriving (Generic, Show)
 
 instance NFData Font
 
@@ -206,24 +210,10 @@
 polyline :: HasCallStack => [Point] -> Picture
 polyline ps = Polyline (getDebugSrcLoc callStack) ps
 
--- | A thin sequence of line segments, with these points as endpoints
-path :: HasCallStack => [Point] -> Picture
-path ps = Polyline (getDebugSrcLoc callStack) ps
-
-{-# WARNING path ["Please use polyline instead of path.",
-                  "path may be removed July 2020."] #-}
-
 -- | A thick sequence of line segments, with given line width and endpoints
 thickPolyline :: HasCallStack => Double -> [Point] -> Picture
 thickPolyline n ps = ThickPolyline (getDebugSrcLoc callStack) ps n
 
--- | A thick sequence of line segments, with given line width and endpoints
-thickPath :: HasCallStack => Double -> [Point] -> Picture
-thickPath n ps = ThickPolyline (getDebugSrcLoc callStack) ps n
-
-{-# WARNING thickPath ["Please used thickPolyline instead of thickPath.",
-                       "thickPath may be removed July 2020."] #-}
-
 -- | A thin polygon with these points as vertices
 polygon :: HasCallStack => [Point] -> Picture
 polygon ps = Polygon (getDebugSrcLoc callStack) ps
@@ -258,7 +248,7 @@
 solidClosedCurve ps = SolidClosedCurve (getDebugSrcLoc callStack) ps
 
 rectangleVertices :: Double -> Double -> [Point]
-rectangleVertices w h = [ (w / 2, h / 2), (w / 2, -h / 2), (-w / 2, -h / 2), (-w / 2, h / 2) ]
+rectangleVertices w h = [(w / 2, h / 2), (w / 2, - h / 2), (- w / 2, - h / 2), (- w / 2, h / 2)]
 
 -- | A thin rectangle, with this width and height
 rectangle :: HasCallStack => Double -> Double -> Picture
@@ -305,23 +295,9 @@
 sector = Sector (getDebugSrcLoc callStack)
 
 -- | A rendering of text characters.
-text :: HasCallStack => Text -> Picture
-text = Lettering (getDebugSrcLoc callStack)
-
-{-# WARNING text ["Please used lettering instead of text.",
-                  "text may be removed July 2020."] #-}
-
--- | A rendering of text characters.
 lettering :: HasCallStack => Text -> Picture
 lettering = Lettering (getDebugSrcLoc callStack)
 
--- | A rendering of text characters, with a specific choice of font and style.
-styledText :: HasCallStack => TextStyle -> Font -> Text -> Picture
-styledText = StyledLettering (getDebugSrcLoc callStack)
-
-{-# WARNING styledText ["Please used styledLettering instead of styledText.",
-                        "styledText may be removed July 2020."] #-}
-
 -- | A rendering of text characters onto a Picture, with a specific
 -- choice of font and style.
 styledLettering :: HasCallStack => TextStyle -> Font -> Text -> Picture
@@ -372,17 +348,19 @@
 
 -- | Binary composition of pictures.
 (&) :: HasCallStack => Picture -> Picture -> Picture
+
 infixr 0 &
 
 a & PictureAnd loc2 bs
-  | srcContains loc1 loc2 = PictureAnd loc1 (a:bs)
-  where loc1 = getDebugSrcLoc callStack
+  | srcContains loc1 loc2 = PictureAnd loc1 (a : bs)
+  where
+    loc1 = getDebugSrcLoc callStack
 a & b = PictureAnd (getDebugSrcLoc callStack) [a, b]
 
 instance Monoid Picture where
-    mempty = blank
-    mappend = (&)
-    mconcat = pictures
+  mempty = blank
+  mappend = (&)
+  mconcat = pictures
 
 #if MIN_VERSION_base(4,11,0)
 
@@ -405,22 +383,27 @@
 -- | The CodeWorld logo.
 codeWorldLogo :: HasCallStack => Picture
 codeWorldLogo =
-    Sketch
-        (getDebugSrcLoc callStack)
-        "codeWorldLogo"
-        $(embedAsUrl "image/svg+xml" "data/codeworld.svg")
-        17.68 7.28
+  Sketch
+    (getDebugSrcLoc callStack)
+    "codeWorldLogo"
+    $(embedAsUrl "image/svg+xml" "data/codeworld.svg")
+    17.68
+    7.28
 
 -- | An image from a standard image format.  The image can be any universally
 -- supported format, including SVG, PNG, JPG, etc.  SVG should be preferred, as
 -- it behaves better with transformations.
-image
-  :: HasCallStack
-  => Text  -- ^ Name for the picture, used for debugging
-  -> Text  -- ^ Data-scheme URI for the image data
-  -> Double  -- ^ Width, in CodeWorld screen units
-  -> Double  -- ^ Height, in CodeWorld screen units
-  -> Picture
+image ::
+  HasCallStack =>
+  -- | Name for the picture, used for debugging
+  Text ->
+  -- | Data-scheme URI for the image data
+  Text ->
+  -- | Width, in CodeWorld screen units
+  Double ->
+  -- | Height, in CodeWorld screen units
+  Double ->
+  Picture
 image = Sketch (getDebugSrcLoc callStack)
 
 getDebugSrcLoc :: CallStack -> Maybe SrcLoc
@@ -432,8 +415,9 @@
 srcContains Nothing _ = False
 srcContains _ Nothing = True
 srcContains (Just a) (Just b) =
-    srcLocFile a == srcLocFile b && srcLocStartLine a < srcLocStartLine b ||
-    (srcLocStartLine a == srcLocStartLine b &&
-     srcLocStartCol a <= srcLocStartCol b) &&
-    srcLocEndLine a > srcLocEndLine b ||
-    (srcLocEndLine a == srcLocEndLine b && srcLocEndCol a >= srcLocEndCol b)
+  srcLocFile a == srcLocFile b && srcLocStartLine a < srcLocStartLine b
+    || ( srcLocStartLine a == srcLocStartLine b
+           && srcLocStartCol a <= srcLocStartCol b
+       )
+    && srcLocEndLine a > srcLocEndLine b
+    || (srcLocEndLine a == srcLocEndLine b && srcLocEndCol a >= srcLocEndCol b)
diff --git a/src/CodeWorld/Reflex.hs b/src/CodeWorld/Reflex.hs
--- a/src/CodeWorld/Reflex.hs
+++ b/src/CodeWorld/Reflex.hs
@@ -5,7 +5,7 @@
 {-# LANGUAGE RecursiveDo #-}
 
 {-
-  Copyright 2019 The CodeWorld Authors. All rights reserved.
+  Copyright 2020 The CodeWorld Authors. All rights reserved.
 
   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
@@ -143,7 +143,7 @@
 -- When using this module, you can build pictures using the same combinators as
 -- the main 'CodeWorld' module.  However, the way you handle user input and draw
 -- to the screen is different.  The 'ReflexCodeWorld' constraint gives you a
--- a monad that has access to Reflex versions of input, such as keys, the mouse
+-- monad that has access to Reflex versions of input, such as keys, the mouse
 -- pointer, and the time.  Based on these inputs, you'll use 'draw' to draw
 -- output to the screen.
 --
@@ -165,16 +165,15 @@
   logicalInputs <- makeLogicalInputs controlState =<< getReactiveInput
   withReactiveInput logicalInputs program
 
-data ControlState t
-  = ControlState
-      { csRunning :: Dynamic t Bool,
-        csTimeDilation :: Dynamic t Double,
-        csPointTransform :: Dynamic t (Point -> Point),
-        csSyntheticStep :: Event t ()
-      }
+data ControlState t = ControlState
+  { csRunning :: Dynamic t Bool,
+    csTimeDilation :: Dynamic t Double,
+    csPointTransform :: Dynamic t (Point -> Point),
+    csSyntheticStep :: Event t ()
+  }
 
 makeLogicalInputs :: (Reflex t, MonadHold t m) => ControlState t -> ReactiveInput t -> m (ReactiveInput t)
-makeLogicalInputs ControlState {..} input = do
+makeLogicalInputs (ControlState {..}) input = do
   keyPress <- return $ gateDyn csRunning $ keyPress input
   keyRelease <- return $ gateDyn csRunning $ keyRelease input
   textEntry <- return $ gateDyn csRunning $ textEntry input
@@ -189,7 +188,7 @@
         [ gateDyn csRunning $ attachWith (*) (current csTimeDilation) (timePassing input),
           0.1 <$ csSyntheticStep
         ]
-  return ReactiveInput {..}
+  return (ReactiveInput {..})
 
 freezeDyn :: (Reflex t, MonadHold t m) => Dynamic t Bool -> Dynamic t a -> m (Dynamic t a)
 freezeDyn predicate dyn = do
@@ -231,12 +230,13 @@
   stepClick <- stepButton hoverAlpha (-2, -9) running
   transformUserPicture $ uncurry translated <$> panOffset
   transformUserPicture $ dilated <$> zoomFactor
-  return $ ControlState
-    { csRunning = running,
-      csTimeDilation = speedFactor,
-      csPointTransform = transformPoint <$> zoomFactor <*> panOffset,
-      csSyntheticStep = stepClick
-    }
+  return $
+    ControlState
+      { csRunning = running,
+        csTimeDilation = speedFactor,
+        csPointTransform = transformPoint <$> zoomFactor <*> panOffset,
+        csSyntheticStep = stepClick
+      }
   where
     transformPoint z (dx, dy) (x, y) = ((x - dx) / z, (y - dy) / z)
 
diff --git a/src/CodeWorld/Sketches.hs b/src/CodeWorld/Sketches.hs
--- a/src/CodeWorld/Sketches.hs
+++ b/src/CodeWorld/Sketches.hs
@@ -2,7 +2,7 @@
 {-# LANGUAGE TemplateHaskell #-}
 
 {-
-  Copyright 2019 The CodeWorld Authors. All rights reserved.
+  Copyright 2020 The CodeWorld Authors. All rights reserved.
 
   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
diff --git a/src/Util/EmbedAsUrl.hs b/src/Util/EmbedAsUrl.hs
--- a/src/Util/EmbedAsUrl.hs
+++ b/src/Util/EmbedAsUrl.hs
@@ -2,7 +2,7 @@
 {-# LANGUAGE TemplateHaskell #-}
 
 {-
-  Copyright 2019 The CodeWorld Authors. All rights reserved.
+  Copyright 2020 The CodeWorld Authors. All rights reserved.
 
   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
diff --git a/test/Main.hs b/test/Main.hs
--- a/test/Main.hs
+++ b/test/Main.hs
@@ -4,7 +4,7 @@
 {-# LANGUAGE BangPatterns #-}
 
 {-
-  Copyright 2019 The CodeWorld Authors. All rights reserved.
+  Copyright 2020 The CodeWorld Authors. All rights reserved.
 
   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
