934 karma · joined January 14, 2012
twitter:@redblobgames
1. I often start making a diagram interactive by adding a slider connected to some state. The slider/state is in one "viewof" cell and the diagram is in another cell. But for more polished work I often want to use direct manipulation, where you move something around in the diagram itself. In my usual JS+Vue code it's a small amount of extra work. But in ObservableHQ it seems like a lot of work: the diagram has to modify state defined in a different cell (breaking the simple spreadsheet model in my head), and the diagram is being re-rendered while it has event handlers active.
2. I often start out by making one diagram. This is nice and easy. But then I want to make multiple diagrams with some shared state. In my usual JS+Vue code I can lift the diagram code into a function, pass in a shared object for shared state, and instantiate objects for non-shared state. In ObservableHQ those properties are in cells, and I can't generate multiple cells programatically (afaik).
I also would prefer to host things myself, both because of longevity, but also because I sometimes work offline (e.g. in a park or on a train). And the biggest reason I'm not using ObservableHQ is that I'm so much slower editing text on it than I am in Emacs. So I continue to use ObservableHQ for some simple projects/prototypes but I don't do a lot with it.
I usually mock visualizations on paper! I'm interested in using WYSIWIG interactive diagram tools like http://aprt.us/ but I never seem to get into them. When I started, making the visualizations was the largest part of the work, but now I've gotten better at it, and making the explanation is now the part that takes the most time.
After paper, I often use SVG to make a non interactive diagram, either by hand, or in inkscape. One of my guiding principles is that the page should be usable without interaction, so the static diagram is a test of that. If it looks promising I can then gradually transform it into an interactive diagram. For example if I had the circle above, and I am using vue.js, I can change it to <circle :cx=x :cy=y r=100 fill=red/> (note the ":" before attributes), and then vue will fill those values in from the object I give it. I can give it {x: 300, y: 400}, and any time I change x or y, it will automatically redraw. I can then hook up x or y to a slider to try out the interactivity. This allows me to start with a static diagram, gradually add interactivity, and then build reusable abstractions that I can apply to multiple diagrams. ObservableHQ and React/JSX allow something similar, with slightly different syntax.
I'd love to see an article about regexes with interactive diagrams. There's a standalone diagram tool https://regexper.com/ and an interactive tutorial https://regexone.com/ but neither is an essay in the style of the Gears article. If you're pursuing this, let me know at redblobgames@gmail.com and I can send over more resources.
The things I like:
1. Reactivity (ObservableHQ, Vue.js, hyperactiv.js, etc.). There's usually some underlying data and then a corresponding visualization. These reactive systems let you modify the underlying data and then the visualization updates automatically. You don't have to figure out which diagrams to update when. Even easier: just redraw everything every time you change anything.
2. Some easier way to write the DOM (d3.js, jsx, vue, lit-html, etc.). Since I'm writing a blog post with html, I usually prefer writing my js-in-html (vue) rather than html-in-js (jsx) but try both directions and see which you prefer.
3. No build step. This is especially important when I want to update a page years later and don't want to figure out which build tools I was using in 1997 or 2007 or 2017. I want my pages to last for decades, and I still update my pages from 25 years ago.
I tried recreating one of the gear page diagrams in ObservableHQ https://observablehq.com/@redblobgames/unwind-circle-example . It's not a lot of code. There's a slider, there's a loop to generate the lines, and there's the output svg. Whenever you move the slider it recalculates the output.
I admit that I'm not using ObservableHQ much for my own projects because I want more of a "hand-written" style. I used d3.js for my older pages and vue.js for my newer pages. Vue's reactivity and templates save me probably a factor of 2 or 3 over d3.js.
Opponent-process theory (https://psyc.ucalgary.ca/PACE/VA-Lab/colourperceptionweb/the...) says that the eye converts the three wavelength inputs into six orthogonal axes (dark-bright, yellow-blue, red-green). From these axes we get the four primary colors: red, yellow, green, blue. Of course things are never so simple. There are various attempts to measure the perception of color (https://www.handprint.com/HP/WCL/vismixmap.html#ncs), and none of them place red-yellow-green-blue exactly along the axes.
Algorithm-wise, it's built on Delaunay+Voronoi: https://azgaar.wordpress.com/2017/03/30/voronoi-graph/
The project started after Azgaar was inspired by Mewo2's map article and Scott Turner's amazing map blog: https://azgaar.wordpress.com/2017/03/30/first-post/
Things that get in the way of robustness: state is based on the physical world. You knock something over, the state has changed. To change the state, you need to move a physical object, which typically means you need a human to do it; the programs can't change state officially. They get around this by storing state anyway, which leads to some weird behavior at times. They've experimented with using magnets to have the system be able to change the physical state, but it's a hard limitation to get around. Also, you want to make a backup of the data? No can do, because we don't have a way to clone physical objects.
Things that get in the way of scaling: all programs are running in a global shared space. Every program can write anywhere to the display or generate audio etc. It's pretty cool! You can run a program that overwrites all output with rainbows. Even more, every program has access to every other program. There's no security. For example you can put a program down on the table and point it at another program to change the second program's code. Cool stuff!
All of this goes against the things we are taught about modularity and scaling and security.
There's a lot of magical stuff going on at Dynamicland but I think it's not a way to create "software" as we think of it. It's a type of computing that isn't easy to do now. It's kind of like comparing a smartphone to a crystal radio kit. The smartphone does a lot of amazing things, and it does it at scale, but the crystal radio kit lets you and your friends tinker and make new things. Apples and oranges.
Dynamicland makes me think of Morpheus's line, "Unfortunately, no one can be told what The Matrix is. You have to see it for yourself."
It was weird how shared content (what we think of as a wiki today) and discussion ("talk" pages on wikipedia) were all mixed together, and it somehow worked. The only Wiki I use these days that still does this is EmacsWiki. Google Wave felt like this in reverse, starting with discussion as default but you could edit everything into a document.
Also: hi Sunir!
For game related topics, I like http://gameprogrammingpatterns.com/ (book available for purchase, but also freely viewable on the web)
Diagrams are in SVG. Canvas would be faster but SVG is easier for me to work with, especially for attaching mouse events to each hexagon. It also automatically scales to high dpi displays. With SVG and HTML accessed the same way, I can use the same code for updating text/samples as I do for updating diagrams. This includes interpolating values as noted by anchpop.
I don't use a build step for the JS code. It's just <script> tags, like it's 1999! You can View Source and see them all. I realize it'd be better if I minified bundled etc. but I'm lazy and this was easier. The page is implemented differently from a "single page app". For that, you might want something like JSX so that you can stay on the JS side, and output HTML+CSS as needed. For this kind of page, I mostly write HTML+CSS, and I tap into JS when needed using Vue.js. For example, I want the text "w = 2 * size" to be next to the rest of the text for that paragraph, instead of in a separate JS file:
<p>
Next we want to put several hexagons together.
In the {{layout}} orientation, a hexagon
has width
<code v-if="layout === 'flat'">w = 2 * size</code>
<code v-else="">w = sqrt(3) * size</code>
…
</p>
I do use a build step for the HTML+SVG. Although the page works without this step (see pre-index.html), the user experience is a little bit better if I generate it on the server. I use cheesy pre-rendering for this: "$(CHROME) --headless --disable-gpu --dump-dom". It means more bytes :( but having all the HTML/SVG load at once is better for linking to a section, hitting the back button, etc. You don't lose the scroll position. Bonus: the page loads if you have Javascript turned off!The static SVG on the server doesn't include the interactive parts. I use InteractionObserver to replace the static diagram with an interactive one as soon as you scroll to that section of the page.
I said I don't have a JS build step, but that's not quite true. The core hexagon algorithms were originally implemented in Haxe, compiled to Javascript. At the time (2013), I was curious about Haxe as an alternative to Javascript. Because I was either bored or crazy or both, in 2015 I implemented a code generator that used Haxe macros to parse the algorithms in Haxe-ish syntax[1] and then generate C++, Javascript, Python, and other output. The Javascript output from that is what now powers the page. Well, it's even more convoluted than that. The Haxe code generates Typescript[2], which I turn into Javascript[3]. I don't know what I was thinking! Well, I do — I wanted my readers to be able to use my unit-tested hexagon algorithms even if they were using a different programming language.
I wrote [4] describing the process of making an interactive page like this with D3.js. Check out [5] for a collection of interactive explanations from other people.
It's unlikely that you will print the page, but if you do, it will show endnotes for all the links so that you can see the URLs.[6]
[1] https://www.redblobgames.com/grids/hexagons/codegen/Codegen.... [2] https://www.redblobgames.com/grids/hexagons/codegen/output/l... [3] https://www.redblobgames.com/grids/hexagons/codegen/output/l... [4] https://www.redblobgames.com/making-of/line-drawing/ [5] https://explorabl.es/ [6] https://simblob.blogspot.com/2018/12/printing-my-pages.html
brain.fm seems to work for me, so I bought a lifetime subscription back when it was available, but the iOS app is flaky enough that I don't use it that often. I don't understand what the "AI" is doing for me, but it makes the experience worse. I'd rather have a static set of music files that are in the app so that I can play them offline (e.g., while traveling). Or even better, not in the app so that I can put them into a music player. The app does have an offline mode but it's awkward.
I recently learned Pzizz (which is nice for sleep) added a focus mode. I should try that sometime. Their app is much more reliable than brain.fm's app. However they don't have a lifetime purchase option, and I almost never sign up for subscription services, so I'm only using the free version.