Starter page - interactive diagrams

from Red Blob Games
14 Apr 2020

Table of Contents

I have a interactive tutorial that takes you step by step to make an interactive tutorial. However, the code for that is more involved than I’d like, so I wanted to make something even simpler.

 1  Vanilla javascript#

No libraries, no build step.

Demo and code[1]

 2  Lit-html#

Small output library, no build step required.

Demo and code[2]

Tricky: need to use svg`` for svg elements instead of html``. Tricky: in html syntax, tags don’t self-close, so <element /> is only the open tag, and you still have to close it with </element>. Tricky: there’s no bundled version of the library, so it loads slower than other libraries. It’s possible to bundle it yourself with Snowpack but frustrating that it doesn’t come with a bundle like Vue does.

 3  Vue v2#

Medium sized input&output library, no build step required.

Demo and code[3]

Tricky: need to use view-box.camel instead of viewBox because of naming convention differences (js uses camel case; html uses kebab case, except for this property); only applies when writing the template in the html, and not when writing the template in javascript. Tricky: Vue 2 tracks changes to arrays and objects, including methods like push, but not to the new Set or Map types; have to force an update for these new types. Vue 3 tracks more types.

 4  React#

Medium sized input&output library, build step strongly recommended to convert code into regular Javascript.

Demo and code[4] (demo doesn’t use the build step)

Tricky: need to use the javascript names of elements and attributes instead of the html names. For example, use className=... instead of class=... like you would in html.

 5  TODO: Svelte#

Medium sized input&output library, build step required to convert Svelte code into regular Javascript

Tricky: Svelte tracks changes based on assignment statements, but not methods like push.

 6  My thoughts#

The main idea with templates is that instead of writing commands to generate html, we describe the html we want, with some placeholders for values that come from Javascript values. For example:

<rect fill=red x=${col} y=${row} width=1 height=1 />

Compare this to the vanilla approach:

let rect = document.createElementNS("", 'rect");
rect.setAttribute("fill", "red");
rect.setAttribute("x", col);
rect.setAttribute("y", row);
rect.setAttribute("width", 1);
rect.setAttribute("height", 1);

or the d3.js approach:

let rect = svg.append("rect")
              .attr("fill", "red")
              .attr("x", col)
              .attr("y", row)
              .attr("width", 1)
              .attr("height", 1);

I find templates to be a big win. The major libraries in this space (React, Vue, Svelte, lit-html) all use templates, but the details differ.

<rect fill=red x={col} y={row} width=1 height=1 />
<rect fill=red :x="col" :y="row" width=1 height=1 />
<rect fill=red x=${col} y=${row} width=1 height=1 />

There’s some difference in how the templates are written. React uses an extension of Javascript called JSX to allow you to write html in your Javascript. You run a compiler to translate that into regular Javascript. Vue reads HTML from your document, or in strings in the source code. Lit-html uses a relatively new feature, Javascript template literals. Svelte also uses its own file format that is compiled into regular Javascript.

In addition, React, Vue, and Svelte offer a component system that allows you to create custom elements like <GridWorld> that are then expanded into HTML. Lit-html doesn’t do this, and instead leaves that to a separate library, LitElement. For my small projects, the component system doesn’t help me, as I can use regular Javascript functions and classes instead. However, for larger projects, it provides some modularity and also allows you to reuse components that others have written.

Tricky: in some of these template systems, it is hard to programatically construct the html in certain ways. For example in lit-html the tag name has to be specified statically.

Email me , or tweet @redblobgames, or comment: