An open API service indexing awesome lists of open source software.

https://github.com/rm-hull/big-bang

ClojureScript event loop abstraction, loosely based on Racket's big-bang and implemented on top of core.async
https://github.com/rm-hull/big-bang

Last synced: over 1 year ago
JSON representation

ClojureScript event loop abstraction, loosely based on Racket's big-bang and implemented on top of core.async

Awesome Lists containing this project

README

          

# Big-Bang [![Build Status](https://secure.travis-ci.org/rm-hull/big-bang.png)](http://travis-ci.org/rm-hull/big-bang)

Big-Bang is a ClojureScript game-loop / event-loop abstraction, loosely based on
Racket's [big-bang][a] and implemented on top of [core.async][b]. It is a pure
ClojureScript implementation with no external Javascript dependencies. Using
_Big-Bang_ encourages you to implement what would be otherwise stateful code
in a pure functional manner; of course, inevitably, at some point you have to
punch outside and twiddle some IO or paint some pixels - this can be entirely
encapsulated in the render handler however.

See [Pacman](http://rm-hull.github.io/big-bang/example.html) (work-in-progress), a
[simple animation](http://programming-enchiladas.destructuring-bind.org/rm-hull/8623502), a
[tumbling 3D torus](http://programming-enchiladas.destructuring-bind.org/rm-hull/7098992),
[parametric equations](http://programming-enchiladas.destructuring-bind.org/rm-hull/8776719), and
[Rock Paper Scissors](http://programming-enchiladas.destructuring-bind.org/rm-hull/8723389)
for demos, and for a code comparison between Big-Bang and [OM][c], see here:

[Om mouse move][d] vs. [Big Bang mouse move][e] ツ

[a]: http://docs.racket-lang.org/teachpack/2htdpuniverse.html#(form._world._((lib._2htdp/universe..rkt)._big-bang))
[b]: http://github.com/clojure/core-async
[c]: https://github.com/swannodette/om
[d]: http://programming-enchiladas.destructuring-bind.org/rm-hull/8617445
[e]: http://programming-enchiladas.destructuring-bind.org/rm-hull/8617788

### Pre-requisites

You will need [Leiningen](https://github.com/technomancy/leiningen) 2.3.4 or
above installed.

### Building & Testing

To build and install the library locally, run:

$ lein cljsbuild once
$ lein install

To test against [PhantomJS](http://phantomjs.org/), ensure that that
package is installed properly, and run:

$ lein cljsbuild test

Alternatively, open ```resources/run-tests.html``` in a browser - this
executes the tests and the test results are displayed on the page.

### Including in your project

There is an 'alpha-quality' version hosted at [Clojars](https://clojars.org/rm-hull/big-bang).
For leiningen include a dependency:

```clojure
[rm-hull/big-bang "0.0.1-SNAPSHOT"]
```

For maven-based projects, add the following to your `pom.xml`:

```xml

rm-hull
big-bang
0.0.1-SNAPSHOT

```
## Basic Usage

Big bang takes a number of keyword arguments in its call, most of which are optional;
only ```:initial-state``` and ```:to-draw``` are required.

The ```:initial-state``` value should be a persistent data-structure which typically
means using a map or vector. It should be the basis of the starting state for the component.

Event handlers can be attached by adding a key starting with ```:on-...``` (for
example ```:on-keydown```, ```:on-click```) and a value of a function handler
reference: the function should take two arguments: an event and a world-state,
and return a (possibly modified) world state. The event naming follows typical
javascript event types, and unless a DOM element is specified in ```:event-target```,
the events are bound to _document.body_. If you find yourself wanting to bind to
multiple events from different targets within a single big-bang world, this is a
clear sign that you should be using multiple (smaller) big-bang components instead.

**NOTE:** There are two reserved event handlers:

* ```:on-tick``` which if present, invokes an interval timer every 17ms,
(i.e. an effective frame rate of approx 60 frames/sec) or whatever rate
is defined by ```:tick-rate```. If not defined, then no timer event
source will be installed,

* ```:on-receive``` which is a handler that is invoked
when external messages are received (on the ```:receive-channel```).

On start-up, all the event sources are assembled and any initialization occurs.
Inside a go loop, the associated channels (/ports) are passed to a _core.async_
alts! method. The resulting value ('the received event') is then dispatched to
the relevant handler function along with the world-state.

It is _part of the expected contract between big-bang and the event handlers_ that:

* The handler function accepts an event and world-state as arguments, and that
a modified world-state is returned. The world state can be packaged to
include a message which will be emitted on the ```:send-channel``` - just
return ```(make-package modified-world-state message)``` instead.

* To take advantage of structural sharing, rather than creating new states,
you are encouraged to use ```assoc```, ```assoc-in```, ```merge``` or
```update-in``` to modify the existing world state. The threading macros
(```->``` and ```->>```) are particularly useful constructs for making this
intent clear.

* The handler function _should_ generally be idempotent and free from side effects:
the event and the incoming world-state are the only things that will effect the
returned world-state.

The new world-state is compared to the old world-state, and if
there is a difference, then the ```:to-draw``` renderer is invoked. The renderer
handler accepts a single argument: the world-state. It should completely render
the component to the DOM according to the supplied world-state, whether this is
canvas operations or via some DOM manipulation library such as
[Dommy](https://github.com/Prismatic/dommy).

Big-bang can be terminated by supplying a ```:stop-when?``` handler (accepting a
single argument of the world-state, returning true will cease the event loop), or
after a fixed number of frames specified by the ```:max-frames``` value. By default,
it will run indefinitely however.

### A simple example

The following code sample gives a simple high level overview of how to program
a big-bang world. See http://programming-enchiladas.destructuring-bind.org/rm-hull/8623502
for a running demo of this code:

```clojure
(ns big-bang.example.cat-animation
(:require-macros [cljs.core.async.macros :refer [go]])
(:require [enchilada :refer [canvas ctx canvas-size proxy-request]]
[cljs.core.async :as async :refer [