<commit_before>---
layout: post
title: "Pixi Buckles - Using PixiJS with BuckleScript"
---


# Introduction

In my [last post][1], I talked about what BuckleScript is and how to get started.  I found that when writing posts, my weakest posts come after I have been spending a lot of time on a topic and then go back and try to fit a post around it.  That's what happened with that post as I had been fooling around with BuckleScript for several weeks before writing the post.  This time, I'm beginning with the end in mind by starting the post at the beginning of the project.

# Goal

My goals for this project are:
1. Learn more about BuckleScript's JS interoperation
2. Make something pretty

# Why PixiJS?

I chose [PixiJS][4] pretty arbitrarily.  I actually started down this whole BuckleScript path after playing around a little bit with [Halite.io][2].  That site is an AI programming competition.  I wanted to be able to simulate different scenarios in that game, and I found they wrote their visualization with [PixiJS][4].  I didn't end up doing anything with [halite.io][2] partially because my friend introduced me to [Screeps][3] which I got hooked on.  Still, I liked the visualization they used, and I've been wanting to create some visualizations that are sort of outside the intended audience for things like [d3.js][5] which I've worked with before.

# Getting started

First, I want to draw a circle without using BuckleScript to make sure I can get that working.  What I want is a single javascript file `main.js` that calls the PixiJS drawing API's.  I wanted to get this working without any other distractions like "webpack" and npm scripts, so I made a simple `index.html` that included `main.js` in the body.

```
// Set up renderer and append to body. This ends up as a canvas.
var renderer = PIXI.autoDetectRenderer(800, 600, { antialias: true });
document.body.appendChild(renderer.view);

// create the root of the scene graph
var stage = new PIXI.Container();
var graphics = new PIXI.Graphics();
stage.addChild(graphics);

// Create a function to draw a circle with our
// graphics object.
function drawCircle(x, y, r) {
    graphics.lineStyle(0);
    graphics.beginFill(0xFFFF0B, 0.5);
    graphics.drawCircle(x, y, r);
    graphics.endFill();
}

// Initialize variables.  We're drawing a circle
// with radius littleR and it follows the path
// centered at (centerX, centerY) with radius bigR
var t = 0;
var centerX = 300;
var centerY = 300;
var bigR = 200;
var littleR = 60;

// run the render loop
animate();

function animate() {
    var x = bigR*Math.sin(t) + centerX;
    var y = bigR*Math.cos(t) + centerY;

    graphics.clear();
    drawCircle(x, y, littleR);
    t += .05;

    renderer.render(stage);
    requestAnimationFrame( animate );
}
```



[1]:{% post_url 2017-01-02-bucklescript-1 %}
[2]:https://halite.io/
[3]:https://screeps.com/
[4]:http://www.pixijs.com/
[5]:https://d3js.org/<commit_msg>Add section about calling document API's<commit_after>---
layout: post
title: "Pixi Buckles - Using PixiJS with BuckleScript"
---


# Introduction

In my [last post][1], I talked about what BuckleScript is and how to get started.  I found that when writing posts, my weakest posts come after I have been spending a lot of time on a topic and then go back and try to fit a post around it.  That's what happened with that post as I had been fooling around with BuckleScript for several weeks before writing the post.  This time, I'm beginning with the end in mind by starting the post at the beginning of the project.

# Goal

My goals for this project are:
1. Learn more about BuckleScript's JS interoperation
2. Make something pretty

# Why PixiJS?

I chose [PixiJS][4] pretty arbitrarily.  I actually started down this whole BuckleScript path after playing around a little bit with [Halite.io][2].  That site is an AI programming competition.  I wanted to be able to simulate different scenarios in that game, and I found they wrote their visualization with [PixiJS][4].  I didn't end up doing anything with [halite.io][2] partially because my friend introduced me to [Screeps][3] which I got hooked on.  Still, I liked the visualization they used, and I've been wanting to create some visualizations that are sort of outside the intended audience for things like [d3.js][5] which I've worked with before.

# Drawing a Circle

First, I want to draw a circle without using BuckleScript to make sure I can get that working.  What I want is a single javascript file `main.js` that calls the PixiJS drawing API's.  I wanted to get this working without any other distractions like "webpack" and npm scripts, so I made a simple `index.html` that included `main.js` in the body.

```
// Set up renderer and append to body. This ends up as a canvas.
var renderer = PIXI.autoDetectRenderer(800, 600, { antialias: true });
document.body.appendChild(renderer.view);

// create the root of the scene graph
var stage = new PIXI.Container();
var graphics = new PIXI.Graphics();
stage.addChild(graphics);

// Create a function to draw a circle with our
// graphics object.
function drawCircle(x, y, r) {
    graphics.lineStyle(0);
    graphics.beginFill(0xFFFF0B, 0.5);
    graphics.drawCircle(x, y, r);
    graphics.endFill();
}

// Initialize variables.  We're drawing a circle
// with radius littleR and it follows the path
// centered at (centerX, centerY) with radius bigR
var t = 0;
var centerX = 300;
var centerY = 300;
var bigR = 200;
var littleR = 60;

// run the render loop
animate();

function animate() {
    var x = bigR*Math.sin(t) + centerX;
    var y = bigR*Math.cos(t) + centerY;

    graphics.clear();
    drawCircle(x, y, littleR);
    t += .05;

    renderer.render(stage);
    requestAnimationFrame( animate );
}
```

# Adding BuckleScript

In the example above, I could download the PixiJS library and stick it a "js" folder.  While something similar may be possible with BuckleScript, the happier path is to use NPM.  Running `npm init` in a new directory prompts you to fill out the fields needed for a barebones `package.json`.  Once that's done, I installed BuckleScript with `npm install --save bs-platform`.  This gave me version `1.4.1`.

Next up is to create a `bsconfig.json`.  Mine looks like this:

```
{
    "name": "buckle-pixi",
    "sources": { "dir": "src"},
    "generate-merlin": true
}
```

This tells the `bsb` command where to look for your `.ml` files.  The `generate-merlin` piece generates a `.merlin` file.  See my [last post][1] for more about Merlin and `.merlin` files. (I've had Merlin really barf on me a couple times.  Each time it's been related to paths in my `.merlin` file being incorrect, once because I changed the directory and once because the `ppx` path was not absolute. If you get inscrutable error messages, carefully inspect your paths.)

Next, I put a simple main file in `src` that logs to the console like this:

```
let () =
    print_endline "hi"
```

I can then run `./node_modules/.bin/bsb` which will generate a `main.js` file in a directory `lib/js/src/main.js` with these contents:

```
// Generated by BUCKLESCRIPT VERSION 1.4.1 , PLEASE EDIT WITH CARE
'use strict';


console.log("hi");

/*  Not a pure module */
```

Instead of running `./node_modules/.bin/bsb` directly, I can add it to my scripts in the `package.json` under `build` so it looks like:

```
"scripts": {"build": "bsb"}
```

Then to build, I run `npm run build` instead.

I included this JS file in the index.html, I saw the output in the console. Exciting stuff!

# Calling browser API's

The first thing the demo script I am using does is append a node to the `body`, so the first thing I am going to tackle is interacting with the document API's.  I  based my calling loosely off of the "ReasonML" bindings that I found on GitHub [here][6].  TODO: look up Cheng Lou's role with Reason.  Here is what I came up with to append a simple text node to the document body:

```
type element

external body : element = "document.body" [@@bs.val]
external appendChild : element -> element -> unit = "appendChild" [@@bs.send]
external createTextNode : string -> element = "document.createTextNode" [@@bs.val]

let () =
    appendChild body (createTextNode "hi there!")
```

First, I declared an abstract type `element`.  The next line lets me use `body` as an element, and whenever I use it, the resulting JS will use `document.body` to get the value (this what the `[@@bs.val]` piece does.)

Next is the `appendChild` definition.  This uses the `[@@bs.send]` macro (TODO: are they called macros?).  This means that the first argument is the object, and the next arguments are the arguments to be sent to that object.  In this case, the first `element` has `appendChild` called on it with the second `element` as its argument and returns nothing (aka `unit`).  A more comprehensive description of these attributes can be found on the BuckleScript wiki [here][7].

The last external definition is for `createTextNode`.  We use `[@@bs.val]` again here.  We could also have created an external declaration for `document` and used `[@@bs.send]` like we did for `appendChild`, but this way seemed simpler since there will only ever be one `document` (i.e. we won't benefit from having the general type for `document` and general functions for it).






[1]:{% post_url 2017-01-02-bucklescript-1 %}
[2]:https://halite.io/
[3]:https://screeps.com/
[4]:http://www.pixijs.com/
[5]:https://d3js.org/
[6]:https://github.com/chenglou/reason-js/blob/master/src/reasonJs.re
[7]:https://github.com/bloomberg/bucklescript/wiki/OCaml-call-JS
{'fraction_non_alphanumeric': 0.09592326139088729, 'fraction_numerical': 0.011573350015639663, 'mean_word_length': 3.8913819479857215, 'pattern_counts': {'":': 6, '<': 3, '<?xml version=': 0, '>': 6, 'https://': 8, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5862797', 'n_tokens_mistral': 2955, 'n_tokens_neox': 2780, 'n_words': 1366}