From Shadow Canvas to Shadow Script



Not so long ago I’d introduced a concept of Shadow Canvas that was used in rerenderer. Basically it was just a mechanism, that remembers all actions performed to a canvas, and applies it on browser or android canvas, if the sequence of actions changed. Like Shadow DOM from React.

But it was very limited, supported only calls and attributes changes, so it wasn’t possible to render something on offscreen canvas or load some bitmap and draw. So I rethought and came up with a concept of Shadow Script, it’s a simple DSL, that has only a few constructions:

; Create instance of `cls` with `args` (list of values or vars) and put result in
; variables hash-map with key `result-var`:
[:new result-var cls args]
; Change `var` attribute `attr` to `value` (can be variable):
[:set var attr value]
; Put value of `var` attribute `attr` in variables hash-map with key `result-var`:
[:get result-var var attr]
; Call method `method` of `var` with `args` (list of values or vars) and put result in
; variables hash-map with key `result-var`:
[:call result-var var method args]

It will be painful to write this constructions manually, so I implemented new, .. and set! macros. So code looks like an ordinary Clojure code. For example — a code for drawing a red rectangle:

(let [canvas (new Canvas)
      context (.. canvas (getContext "2d"))]
  (set! (.. canvas -width) 200)    
  (set! (.. canvas -height) 200)
  (set! (.. context -fillStyle) "red")
  (.. context (fillRect 0 0 100 100))) 

Will be translated to:

[[:new "G_01" :Canvas []]
 [:call "G_02" "G_01" "getContext" ["2d"]]
 [:set "G_01" "width" 200]
 [:set "G_01" "height" 200]
 [:set "G_02" "fillStyle" "red"]
 [:call "G_03" "G_02" "fillRect" [0 0 100 100]]]

(open on a new page)

A huge benefit of Shadow Script, is that an interpreter can be build very easily, and this is significant, because we need to implement interpreter three or more times: for browsers in ClojureScript, for Android in Java (or Kotlin?) and for iOS in Objective-C (or Swift). And interpreter in ClojureScript is basically just:

(defn interprete-line
  "Interpretes a single `line` of script and returns changed `vars`."
  [vars line]
  (match line
    [:new result-var cls args] (create-instance vars result-var cls args)
    [:set var attr value] (set-attr vars var attr value)
    [:get result-var var attr] (get-attr vars result-var var attr)
    [:call result-var var method args] (call-method vars result-var var
                                                    method args)))

(defn interprete
  "Interpretes `script` and returns hash-map with vars."
  [script]
  (reduce interprete-line {} script))

(full code)

Another cool stuff is that we can construct a dependencies tree and recreate only changed canvases/bitmaps/etc. So, for example we need to draw a red rectangle on another rectangle, which color stored in a state:

(defn draw-box
  [color w h]
  (let [canvas (new Canvas)
        context (.. canvas (getContext "2d"))]
    (set! (.. canvas -width) w)
    (set! (.. canvas -height) h)
    (set! (.. context -fillStyle) color)
    (.. context (fillRect 0 0 w h))
    canvas))

(let [red-box (draw-box "red" 50 50)
      another-box (draw-box (:color state) 800 600)
      another-box-ctx (.. another-box (getContext "2d"))]
  (.. another-box-ctx (drawImage red-box 50 50)))

With state {:color "yellow"} script we’ll be:

[[:new "G_01" :Canvas []]
 [:call "G_02" "G_01" "getContext" ["2d"]]
 [:set "G_01" "width" 50]
 [:set "G_01" "height" 50]
 [:set "G_02" "fillStyle" "red"]
 [:call "G_03" "G_02" "fillRect" [0 0 50 50]]
 [:new "G_04" :Canvas []]
 [:call "G_05" "G_04" "getContext" ["2d"]]
 [:set "G_04" "width" 800]
 [:set "G_04" "height" 600]
 [:set "G_05" "fillStyle" "yellow"]
 [:call "G_06" "G_05" "fillRect" [0 0 800 600]]
 [:call "G_07" "G_04" "getContext" ["2d"]]
 [:call "G_08" "G_07" "drawImage" ["G_01" 50 50]]]

(open on a new page)

And with state {:color "green"}:

[[:new "G_01" :Canvas []]
 [:call "G_02" "G_01" "getContext" ["2d"]]
 [:set "G_01" "width" 50]
 [:set "G_01" "height" 50]
 [:set "G_02" "fillStyle" "red"]
 [:call "G_03" "G_02" "fillRect" [0 0 50 50]]
 [:new "G_04" :Canvas []]
 [:call "G_05" "G_04" "getContext" ["2d"]]
 [:set "G_04" "width" 800]
 [:set "G_04" "height" 600]
 [:set "G_05" "fillStyle" "green"]
 [:call "G_06" "G_05" "fillRect" [0 0 800 600]]
 [:call "G_07" "G_04" "getContext" ["2d"]]
 [:call "G_08" "G_07" "drawImage" ["G_01" 50 50]]]

(open on a new page)

You can see that canvas G_01 wasn’t changed, and all lines before [:new "G_04" :Canvas []] can be skipped. This sounds cool, but it’s a bit complex, so it’s not yet implemented.

Gist with examples.

Functional testing of console apps with Docker



For one of my apps I’d been manually testing some basic functions in a bunch of environments, and it was a huge pain. So I decided to automatize it. As a simplest solution I chose to run an environment in Docker and interact with them through pexpect.

First of all I tried to use docker-py, but it’s almost impossible to interact with app run in Docker container, started from docker-py with pexpect. So I just used Docker binary:

from contextlib import contextmanager
import subprocess
import shutil
from tempfile import mkdtemp
from pathlib import Path
import sys
import pexpect

# Absolute path to your source root:
root = str(Path(__file__).parent.parent.parent.resolve())


def _build_container(tag, dockerfile):
    """Creates a temporary folder with Dockerfile, builds an image and
    removes the folder.
    
    """
    tmpdir = mkdtemp()
    with Path(tmpdir).joinpath('Dockerfile').open('w') as file:
        file.write(dockerfile)
    if subprocess.call(['docker', 'build', '--tag={}'.format(tag), tmpdir],
                       cwd=root) != 0:
        raise Exception("Can't build a container")
    shutil.rmtree(tmpdir)


@contextmanager
def spawn(tag, dockerfile, cmd):
    """Yields spawn object for `cmd` ran inside a Docker container with an
    image build with `tag` and `dockerfile`. Source root is available in `/src`.
    
    """
    _build_container(tag, dockerfile)
    proc = pexpect.spawnu('docker run --volume {}:/src --tty=true '
                          '--interactive=true {} {}'.format(root, tag, cmd))
    proc.logfile = sys.stdout

    try:
        yield proc
    finally:
        proc.terminate()

_build_container is a bit tricky, but it’s because Docker binary can build an image only for file named Dockerfile.

This code can be used for running something inside a Docker container very simple, code for printing content of your source root inside the container will be:

with spawn(u'ubuntu-test', u'FROM ubuntu:latest', u'bash') as proc:
    proc.sendline(u'ls /src')

Back to testing, if we want to test that some application can print version, you can easily write py.test test like this:

container = (u'ubuntu-python', u'''
FROM ubuntu:latest
RUN apt-get update
RUN apt-get install -yy python
''')


def test_version():
    """Ensure that app can print current version."""
    tag, dockerfile = container
    with spawn(tag, dockerfile, u'bash') as proc:
        proc.sendline(u'cd /src')
        proc.sendline(u'pip install .')
        proc.sendline(u'app --version')
        # Checks that `version:` is in the output:
        assert proc.expect([pexpect.TIMEOUT, u'version:'])

You can notice the strange assert proc.expect([pexpect.TIMEOUT, u'version:']) construction, it works very simple, if there’s version: in output, expect returns 1, if timeout came first - 0.

Also you can notice that all strings are in unicode (u''), it’s for compatibility with Python 2. If you use only Python 3, you can remove all u''.

Examples.

Changing version of App Engine application on checkout to a git branch



It’s very common and useful to use current branch name (or something dependent on it) as a version for App Engine application. And it’s painful and error-prone to change it manually.

It’s easily can be automatized with a git hook, we just need to fill .git/hooks/post-checkout with something like:

#!/usr/bin/env python
import glob
import subprocess


def get_yaml_paths():
    """Returns all `.yaml` files where `version` can be changed."""
    for path in glob.glob('*.yaml'):
        with open(path) as yml:
            content = yml.read()
            if 'version:' in content:
                yield path


def get_version():
    """Returns `version`, currently just current branch."""
    proc = subprocess.Popen(['git', 'rev-parse', '--abbrev-ref', 'HEAD'],
                            stdout=subprocess.PIPE)
    return proc.stdout.read()


def replace_version(path, new_version):
    with open(path, 'r') as yml:
        lines = yml.readlines()
    with open(path, 'w') as yml:
        for line in lines:
            if line.startswith('version'):
                yml.write('version: {}\n'.format(new_version))
            else:
                yml.write(line)


version = get_version()
print("Change version in yaml files to", version)
for path in get_yaml_paths():
    replace_version(path, version)

And make it executable:

chmod +x .git/hooks/post-checkout

In action:

cat app.yaml | grep "^version:"
version: fixes
➜ git checkout feature
Switched to branch 'feature'
Your branch is up-to-date with 'origin/feature'.
Change version in yaml files to feature
➜ cat app.yaml | grep "^version:"
version: feature

Leonardo Borges: Clojure Reactive Programming



book cover Recently I’ve got a few free books from PACKT and as one to read I chose Clojure Reactive Programming by Leonardo Borges. I’m already familiar with most of concepts and libs described in this book, but I guess it’s a good book. The book explains Rx extensions and usage of them from Clojure and ClojureScript, explains core.async and React (and Om), so I think it touches all aspects of “reactive” (such a buzzword). And coolest part of this book is appendix, it about library design but with functors and monads.

So summing up everything, this book is a bit for newbies, but great.

Using Werkzeug with Django on App Engine



Werkzeug has a pretty decent error page with in-browser debugger and some other features. In just Django project it can be easily used with django-extensions with:

./manage.py runserver_plus

But we can’t use this approach with gae, because it doesn’t use runserver, it just works through wsgi. So instead we should wrap our wsgi application with DebuggedApplication. So in wsgi.py (or another file where wsgi app defined) we need to change an app initialization to something like:

from django.core.wsgi import get_wsgi_application
from django.conf import settings
from werkzeug.debug import DebuggedApplication

application = get_wsgi_application()
if settings.DEBUG:
    app = DebuggedApplication(app, True)
    # Werkzeug won't work without exceptions propagation
    settings.DEBUG_PROPAGATE_EXCEPTIONS = True

And that’s all.

Searching for a cheap flight ticket with Clojure and Chrome



Few days ago I had to find a cheap flight ticket. And all services that I know allows to search only for selected day, but I needed for a month. It’s a pain to select every day, search and manually choose a best deal. So I decided to automate it.

As I know all services uses tons of client-side code for searching and some times asks to type a captcha, so simplest solution is to write an extension from Chrome. As an enemy I selected Yandex Avia, because I just used to it, but It’s not so important, approach used in the article can be used with other services.

First of all, let’s create main function for searching:

(defn run
  [id-from id-to date-from date-to]
  (->> (days-range date-from date-to)
       (map #(get-flights id-from id-to %))
       concat-flights
       present))

Where’s id-from and id-to are airports ids, date-from and date-to are date range for searching. Code looks very straightforward, we just creates a date range, gets flights, concats results and presents it. Now we need to implement each function from this pipeline.

days-range isn’t interesting, so let’s start with get-flights. In this function we should open a tab with special url, get results from it and close the tab. So start with opening a tab with chrome.tabs.create:

(defn open-tab
  [url]
  (let [done (chan)]
    (.. js/chrome -tabs (create #js {:url url}
                                #(go (>! done %))))
    done))

This action is asynchronously, so we use core.async here.

So now let’s look to most complicated part – parsing. That part works on the background’s side and on the content side (on the service’s web app pages). Background side is a bit complicated: we should send a script to content with chrome.tabs.executeScript and wait for a message with result using chrome.runtime.onMessage.addListener, but it can be implemented very simple:

; Map of tab-id => chan
(def waiting (atom {}))

; Puts received message to the waiting channel
(.. js/chrome -runtime -onMessage (addListener
                                    #(go (let [result (js->clj %1 :keywordize-keys true)
                                               {:keys [tab]} (js->clj %2 :keywordize-keys true)
                                               waiter (get @waiting (:id tab))]
                                           (>! waiter result)))))

(defn run-script
  [{:keys [id]}]
  (let [result (chan)]
    (.. js/chrome -tabs (executeScript id #js {:file "content/main.js"}))
    ; Puts channel in waiting map
    (swap! waiting assoc id result)
    result))

And content side is more than simple:

(go-loop []
  (if (ready?)
    (.. js/chrome -runtime (sendMessage #js {:status :ok
                                             :flights (clj->js (get-flights))}))
    (do (<! (timeout 500))
        (recur))))

We skip content’s get-flights and ready? here, because it’s just a parsing of html.

Back to the background’s get-flights, now we can implement it:

(defn get-flights
  [id-from id-to date]
  (go (let [search-format (formatter "dd+MMM")
            tab (<! (open-tab (make-url id-from id-to (unparse search-format date))))
            {:keys [id]} (js->clj tab :keywordize-keys true)
            {:keys [flights]} (<! (run-script tab))]
        (.. js/chrome -tabs (remove id))
        (map #(assoc % :date date) flights))))

So that hardcore action was simplified to simple and flat code.

Now we can go back to main function. We can’t just use concat for a list of channels, so we should implement something similar:

(defn concat-flights
  [flights]
  (go-loop [[flight & flights] flights
            result []]
    (if flights
      (recur flights (concat result (<! flight)))
      result)))

It works just like concat, but accepts a list of channels and returns a single channel with concatenated result.

And now the latest part – presentat, we just use console.table here, it offers us fancy table view with sorting:

(defn present
  [prices]
  (let [present-format (formatter "MM.dd")]
    (go (->> (<! prices)
             (map #(update % :date (fn [date] (unparse present-format date))))
             clj->js
             (.table js/console)))))

Now we can look to the result with flights from Saint-Petersburg (Russia) to Denpasar (Indonesia, Bali) in range from the first day of September till the first day of October:

Result

Isn’t it cool that this very complicated logic can be written as a simple flat code almost without callback, and can be simplified to just a pipeline of short actions?

Gist with the sources.

VR with ClojureScript, three.js and Google Cardboard



cardboard

Not so long ago I read that John Carmack uses Lisp for VR, and also I found experiments for Cardboard with three.js and a good article about coding with three.js for Cardboard. I thought it will be good to combine this stuff and try to play with some poor man’s VR with cheap Cardboard and a browser. And use benefits of ClojureScript like figwheel with REPL and livecoding.

So for drawing I decided to use three.js with StereoEffect.js for drawing for both eyes and with DeviceOrientationControls.js for tracking head movements.

First of all we need to prepare a scene, a camera, a renderer for both eyes and a controls for tracking head movements:

(defn get-camera
  "Creates camera with desired aspect ratio."
  []
  (doto (js/THREE.PerspectiveCamera. 75 (/ (.-innerWidth js/window)
                                           (.-innerHeight js/window))
                                     0.1 1000)
    (.. -position (set 0 5 0))))

(defn get-canvas
  "Returns canvas that will be fullscreened after a click."
  []
  (let [canvas (.getElementById js/document "canvas")]
    (.addEventListener canvas "click" #(.webkitRequestFullscreen canvas))
    canvas))

(defn get-renderer
  "Creates renderer for both eyes."
  []
  (let [canvas (get-canvas)
        webgl (js/THREE.WebGLRenderer. #js {:canvas canvas})
        renderer (js/THREE.StereoEffect. webgl)]
    (.setSize renderer (.-innerWidth js/window) (.-innerHeight js/window))
    renderer))

(defn set-orientational-contorlls
  "Set in atom controlls that tracks device (and head) movements."
  [controlls camera e]
  (when (and (.-alpha e) (not @controlls))
    (let [ctrls (js/THREE.DeviceOrientationControls. camera true)]
      (.connect ctrls)
      (.update ctrls)
      (reset! controlls ctrls))))

(defn get-controlls
  "Returns atom with controlls."
  [camera]
  (let [controlls (atom)]
    (.addEventListener js/window "deviceorientation"
                       #(set-orientational-contorlls controlls camera %))
    controlls))

(def scene (js/THREE.Scene.))
(def camera (get-camera))
(def renderer (get-renderer))
(def controlls (get-controlls camera))

And then functions for rendering:

(defn do-render
  "Called on each render."
  [])

(defn render
  "Called on each render. This function not reloads on changes."
  []
  (js/requestAnimationFrame render)
  (when @controlls
    (.update @controlls))
  (.updateProjectionMatrix camera)
  (do-render)
  (.render renderer scene camera))

; Not reload render function when code changed:
(defonce render-started (atom false))
(when-not @render-started
  (render)
  (reset! render-started true))

When we need to do some actions (change color, rotate, etc) on each render — we need to change do-render.

Well, enough with boilerplate, look at some example — two rotating rectangles, you can see this example in the video. The code isn’t good looking, three.js api not so very friendly with ClojureScript, but it readable:

(defn create-rect
  "Creates a rect with given color and xyz."
  [color x y z]
  (js/THREE.Mesh. (js/THREE.BoxGeometry. x y z)
                  (js/THREE.MeshBasicMaterial. #js {:color color})))

; Creates white rect:
(def rect (create-rect "white" 1 1 1))
(.. rect -position (set 1 1 0))
(.add scene rect)

; Creates yellow rect:
(def other-rect (create-rect "yellow" 1 2 3))
(.. other-rect -position (set -0.5 -2 0))
(.add scene other-rect)

(defn do-render
  "Called on each render."
  []
  ; Rotates white rect:
  (set! (.. rect -rotation -x)
        (+ (.. rect -rotation -x) 0.01))
  (set! (.. rect -rotation -y)
        (+ (.. rect -rotation -y) 0.01))
  ; Rotates yellow rect:
  (set! (.. other-rect -rotation -x)
        (- (.. other-rect -rotation -x) 0.1))
  (set! (.. other-rect -rotation -y)
        (+ (.. other-rect -rotation -y) 0.1)))

Let’s see it in action, it’s not so fabulous without Cardboard, but livecoding makes it more interesting:

This way to work with Cardboard has a few problems: we can’t use the magnet trigger and we don’t have special lens distortion correction. And I guess next time I’ll try to use Cardboard SDK for Android with Clojure on Android.

Gist with the sources.

Chris Okasaki: Purely Functional Data Structures



book cover I was interested how common data structures were implemented in FP languages and decided to read Purely Functional Data Structures by Chris Okasaki. I can’t say that I understood all parts of this book, especially the last chapters. But reading and solving exercises from the book gave me some thoughts. And I guess I got more than enough answers to almost all my questions about functional data structures.

Also a good thing in this book — all examples are in SML and Haskell. And reading examples in SML is a more pleasure than reading them in C or Java, at least for me.

React-like tool for working with canvas



One of the greatest ideas in React is a shadow dom, it’s simple and fast. So I decided to implement something like shadow canvas and created the rerenderer — a special library that accumulates calls to shadow canvas methods, verifies that resulted script (or method set) changed and applies the script to a real canvas.

And the huge benefit of this way to work with a canvas — it’s easily to work not only with browser canvas, but with Android (partially implemented) and maybe even iOS.

Little note, if examples works slow on this page it’s because here’s too much animations for the single page. You can open it on a new page

So, first example – a rotating rectangle:

(defn rotating-rectangle
  [ctx {:keys [angle]} _]
  (r/call! ctx save)
  (r/call! ctx (clearRect 0 0 100 100))
  (r/set! (.. ctx -fillStyle) "red")
  (r/call! ctx (translate 35 35))
  (let [rangle (* angle (/ js/Math.PI 180))]
    (r/call! ctx (rotate rangle))
    (r/call! ctx (fillRect -25 -25 50 50)))
  (r/call! ctx restore))

(defn rotate-rectangle
  [state]
  (go-loop []
    (<! (timeout 5))
    (swap! state update-in [:angle]
           #(-> % inc (mod 360)))
    (recur)))

(defn scene-1
  [canvas]
  (let [state (atom {:angle 0})]
    (r/init! (browser canvas) rotating-rectangle state {})
    (rotate-rectangle state)))

Code is very low level (in comparison with the code for the same rectangle with svg), but it works pretty smooth:

(open on a new page)

You can notice that r/call! is very similar to .. macro, and r/set! works just set!, special macros are required for tracking interaction with the shadow canvas.

So, back to examples, let’s try to make the same rectangle moving, code was changed just a bit:

(defn rotating-and-moving-rectangle
  [ctx {:keys [angle x]} _]
  (r/call! ctx save)
  (r/call! ctx (clearRect 0 0 700 100))
  (r/set! (.. ctx -fillStyle) "red")
  (r/call! ctx (translate (+ x 25) 35))
  (let [rangle (* angle (/ js/Math.PI 180))]
    (r/call! ctx (rotate rangle))
    (r/call! ctx (fillRect -25 -25 50 50)))
  (r/call! ctx restore))

(defn rotate-and-move-rectangle
  [state]
  (go-loop []
    (<! (timeout 5))
    (swap! state update-in [:angle]
           #(-> % inc (mod 360)))
    (swap! state update-in [:x]
           #(-> % inc (mod 600)))
    (recur)))

(defn scene-2
  [canvas]
  (let [state (atom {:angle 0
                     :x 10})]
    (r/init! (browser canvas) rotating-and-moving-rectangle state {})
    (rotate-and-move-rectangle state)))

And it’s also works very smooth:

(open on a new page)

Then try to draw sprites, it’s very complicated with React and SVG, but very simple with this solution because we can use canvas drawImage method:

(defn mario
  [ctx atlas mario-state x y]
  (when mario-state
    (let [[sx sy] (get-in sprites mario-state)]
      (r/call! ctx (drawImage atlas sx sy 20 40 x y 40 80)))))

(defn all-marios
  [ctx {:keys [mario-0 mario-1 mario-2 mario-3 mario-4 mario-5]} {:keys [atlas]}]
  (r/call! ctx (clearRect 0 0 300 300))
  (mario ctx atlas mario-0 10 10)
  (mario ctx atlas mario-1 60 10)
  (mario ctx atlas mario-2 110 10)
  (mario ctx atlas mario-3 10 80)
  (mario ctx atlas mario-4 60 80)
  (mario ctx atlas mario-5 110 80))

(defn handle-mario
  [state state-key draw-state-key]
  (go-loop []
    (<! (timeout 100))
    (let [[mario-direction mario-state] (get @state state-key)
          [draw-direction draw-state] (get @state draw-state-key)
          next-draw-state (if (and (= mario-direction draw-direction)
                                   (= mario-state :run))
                            ; Changes drawing state (and sprite) when Mario running:
                            (condp = draw-state
                              :run :run-1
                              :run-1 :run-2
                              :run)
                            mario-state)]
      (swap! state assoc draw-state-key [mario-direction next-draw-state]))
    (recur)))

(defn scene-3
  [canvas]
  (go (let [state (atom {:mario-0-state [:right :stand]
                         :mario-1-state [:right :run]
                         :mario-2-state [:right :jump]
                         :mario-3-state [:left :stand]
                         :mario-4-state [:left :run]
                         :mario-5-state [:left :jump]})
            platform (browser canvas)
            options {:atlas (<! (r/image platform "mario.png"))}]
        (r/init! platform all-marios state options)
        (handle-mario state :mario-0-state :mario-0)
        (handle-mario state :mario-1-state :mario-1)
        (handle-mario state :mario-2-state :mario-2)
        (handle-mario state :mario-3-state :mario-3)
        (handle-mario state :mario-4-state :mario-4)
        (handle-mario state :mario-5-state :mario-5))))

Code is a bit redundant, but it shows how code for rendering and code for managing state can be easily separated. In action:

(open on a new page)

So let’s try something more complicated, a scene where the Mario goes to the right, jumps, goes to the left, jumps and repeats all actions:

(defn mario-scenario
  [state]
  (go-loop []
    ; Stand a half
    (swap! state assoc-in [:mario-state 1] :stand)
    (<! (timeout 500))
    ; Jump
    (swap! state assoc-in [:mario-state 1] :jump)
    (dotimes [_ 20]
      (<! (timeout 5))
      (swap! state update-in [:mario-y] dec))
    (dotimes [_ 20]
      (<! (timeout 5))
      (swap! state update-in [:mario-y] inc))
    ; Stand a half
    (swap! state assoc-in [:mario-state 1] :stand)
    (<! (timeout 500))
    ; Go right
    (swap! state assoc-in [:mario-state 1] :run)
    (dotimes [_ 300]
      (<! (timeout 5))
      (swap! state update-in [:mario-x] inc))
    ; Stand a second
    (swap! state assoc-in [:mario-state 1] :stand)
    (<! (timeout 500))
    (swap! state assoc-in [:mario-state 0] :left)
    (<! (timeout 500))
    ; Jump
    (swap! state assoc-in [:mario-state 1] :jump)
    (dotimes [_ 20]
      (<! (timeout 5))
      (swap! state update-in [:mario-y] dec))
    (dotimes [_ 20]
      (<! (timeout 5))
      (swap! state update-in [:mario-y] inc))
    ;Stand a half
    (swap! state assoc-in [:mario-state 1] :stand)
    (<! (timeout 500))
    ; Go back
    (swap! state assoc-in [:mario-state 1] :run)
    (dotimes [_ 300]
      (<! (timeout 5))
      (swap! state update-in [:mario-x] dec))
    ; Stand a half
    (swap! state assoc-in [:mario-state 0] :right)
    (<! (timeout 500))
    (recur)))

(defn moving-mario
  [ctx {:keys [mario-draw-state mario-x mario-y]} {:keys [atlas]}]
  (r/call! ctx (clearRect 0 0 500 300))
  (r/set! (.. ctx -fillStyle) "green")
  (r/call! ctx (fillRect 0 75 400 20))
  (mario ctx atlas mario-draw-state mario-x mario-y))

(defn scene-4
  [canvas]
  (go (let [state (atom {:mario-state [:right :stand]
                         :mario-x 20
                         :mario-y 15})
            platform (browser canvas)
            options {:atlas (<! (r/image platform "mario.png"))}]
        (r/init! platform moving-mario state options)
        (handle-mario state :mario-state :mario-draw-state)
        (mario-scenario state))))

There’s a bit too much code for managing the state of the Mario, but I guess it’s one of the simplest ways to write a scene like this:

(open on a new page)

Also rerenderer supports events (like clicks) and can play sounds, so as a bonus — a very simplified version of the Flappy Bird:

(open on a new page)

Flappy Bird code.

Rerenderer on github.

Gist with examples.

Add live reloading to Jekyll with Gulp and Browsersync



Live reloading is a very useful feature and it’s very popular in web development, but why don’t use it for writing blog articles and seeing changes in the real time?

I use Jekyll for this blog, and I already familiar with Gulp and Browsersync, so I decided to use them.

First of all, init a new package and install all dependencies:

npm init
sudo npm install -g gulp
npm install --save-dev gulp-shell lodash gulp browser-sync

And create a gulpfile.js with:

var gulp = require('gulp');
var shell = require('gulp-shell');
var browserSync = require('browser-sync').create();

// Task for building blog when something changed:
gulp.task('build', shell.task(['bundle exec jekyll serve']));
// If you don't use bundle:
// gulp.task('build', shell.task(['jekyll serve']));
// If you use  Windows Subsystem for Linux (thanks @SamuliAlajarvela):
// gulp.task('build', shell.task(['bundle exec jekyll serve --force_polling']));

// Task for serving blog with Browsersync
gulp.task('serve', function () {
    browserSync.init({server: {baseDir: '_site/'}});
    // Reloads page when some of the already built files changed:
    gulp.watch('_site/**/*.*').on('change', browserSync.reload);
});

gulp.task('default', ['build', 'serve']);

Then add created files and folders to Jekyll exclude, otherwise gulp will found more than one task with the same name. In _config.yml:

exclude: [node_modules, gulpfile.js]

And that’s all! For running it:

gulp

In action: