Welcome to johnbintz.com

2017 Year In Review

Dec 29, 2017

This year was the first year that I went into my personal creative projects with a real, solid plan.

What worked?


I moved the majority of my cloud-based document services to a Sandstorm instance, inside of which I ran numerous text documents, spreadsheets, wikis, git repos, file shares, and even more. I did this for two reasons: to get my data off of cloud providers that I don’t trust to varying degrees, and to experiment with developing for this platformm, which I was doing earlier this year.


There’ll be a lot of links to Cortex episodes, so be ready. Episode 4 starts the conversation about checklists for codifying repeatable tasks. I’ve shared a Remember The Milk account with my wife for years now, but didn’t start really digging in until after Cortex. I discovered that it’s possible to add subtasks to a task and then duplicate a task, preserving the subtasks, which gave me the power of repeatable templates I could develop over time.

Personally, I have a bunch of checklists for packing lists and weekly reviews. For the comic business, I have monthly and quarterly reviews mapped out, a packling list for cons, steps for posting something to Patreon that gets promoted elsewhere, and other smaller ones. Big win for remembering how to do stuff I don’t do too often, and for staying motivated when I don’t feel like doing everything in a review.

Regular Reviews

I now do reviews the following times:

These let me catch up on ongoing things, like financial tracking and such, and give me time to reflect and pivot in different directions. They’ve been super useful.

For the business reviews, I was, at the beginning of the year, very good about getting out of the house to a coffee shop for an hour and planning things out without distraction or diving into art or code or writing. I need to start doing this again, especially as 2018 gets started.

Super-Focused Work Periods

Another Cortex recommendation. I’m now using either All Day, Feed The Animals, or Night Ripper by Girl Talk if I have either 70, 55, or 45 minutes available to work without distraction. Noise-Cancelling Earbuds help too (affiliate link, I bought them, like them a lot, and recommend them to whoever I can).

By working this way, I can crank out several full panels of art super-fast and stay on target with the work, with way less context switching which just drains energy. It works great with my programming as well. A+++, would work this way again.

What didn’t?

Having something non-kid friendly with my particular art style

I wouldn’t say Baltimore Comic-Con fell flat for me this year, but I would say it would have gone a lot better if I had something on the table for ages 8 and up. I’m looking to fill that gap in 2018.

Not putting in enough buffer for life stuff

A lot of crazy things happened this year which set me back in my creative projects a lot. I don’t feel bad about not getting this stuff done – life happens, and it’s often more important than drawing comics – but I wish that, when I put my content plan together at the beginning of the year, I had lowered my expectations more than I had. I would have been more focused on the things I really wanted to get done, like Issue 3 of Wizard/Metalsmith.

Non-memetic social media promotion

I keep forgetting that longform comics like the ones I typically do just don’t get the likes on Facebook and Instagram like single-image, easily shared images. It works better on Tumblr, but you really have to find that niche community to get that going. Next year’s marketing plan…well, it’s still in flux.

What’s still up for debate?

Using Tumblr to cross-promote work

187 Football Heads has been great, but I need to figure out good ways to get folks from there to look at my other stuff when it’s done. Still mulling this one over.

Krita Canvas Corruption Fix for Laptops

Dec 16, 2017

I don’t know how many others experience this issue, but when I have Krita open and I close the lid on my Lenovo laptop w/ an nVidia card, running Kubuntu, then open it, the art area becomes corrupted, most likely because the graphics card’s memory becomes screwy or something during sleep. The fix is simple: pick a layer or a few layers that cover large parts of the canvas and toggle them on and off. This will force Krita to have to redraw these areas and get them back into the video card’s RAM correctly. The layer on which I draw comic panel borders is the one I ususally use, since they cover nearly the whole canvas.

Connectable Desktop 3d Prints up on Thingiverse

Dec 09, 2017

I have way too many keyboards:

I also have way too many fountain pens (is that possible?), notebooks, and other writing tools:

I decided to design two connectable keyboard/notebook/pen holders that I could 3d print out. You can grab them off of my Thingiverse designs profile. I printed these with orange Inland PLA and they’re quite sturdy. I even ended up printing a few more of the keyboard holders and using them for holding cutting boards in my kitchen.

PostGraphQL Dev Notes - Part 1

Nov 21, 2017

Warning: some of this stuff will look pretty n00b. I’m not the strongest PostgreSQL user, which is the whole point of diving in deep with PostGraphQL. So far, this “database as app server” approach is working for this simple CRUD app I’m building, and I’ll be writing up more notes like this as I go, both to help solidify it in my mind and to help out other n00bs like myself with this different approach.

Dependent Table Permissions

I have a thing that contain other things (a has_many/belongs_to relationship in Rails) and I want to enforce, in PostgreSQL, ownership of both using the JWT approach in the PostGraphQL when working with the child thing. Within a node-pg-migrate migration file, I did this and it enforced the parent/child relationship of everything. This was probably overkill on the DELETE policy, but eh, it’s more code reuse and less to write for this very basic app:

  var rowLevelCheck = `
    (select true from myschema.parent_table as a
    where user_id = current_setting('jwt.claims.user_id')::integer
    and parent_id = a.id
    and user_id = a.user_id)

    create policy insert_child_table on myschema.child_table
    for insert to myapp_user with check (${rowLevelCheck});

    create policy update_child_table on myschema.child_table
    for update to myapp_user using (${rowLevelCheck});

    create policy delete_child_table on myschema.child_table
    for delete to myapp_user using (${rowLevelCheck});

Sandstorm Dev Notes - Part 1

Nov 17, 2017

I like Sandstorm so much that I’m finally developing an app for it. It’ll use PostGraphQL to move all of the business logic into PostgreSQL, and React, Redux, and Apollo to handle the UI and data reading/manipulation. I’ll be documenting the weird issues I’ve run into when setting this up, since there aren’t a ton of docs on this particular combo of services.



Due to how grains have random UID/GID assigned to them for security purposes, and because /etc/passwd and /etc/group are not available when running launcher.sh, initdb will fail because it wants to look up the current UID in /etc/passwd for security reasons. You can get around this by using nss_wrapper:

export PGDATA=/var/lib/postgres

echo "postgres:x:$(id -u):$(id -g):PostgreSQL user:/var/lib/postgres:/bin/sh" > /var/passwd
echo "postgres:x:$(id -g):" > /var/group

if [ ! -d $PGDATA ]; then
  LD_PRELOAD=/usr/lib/libnss_wrapper.so NSS_WRAPPER_PASSWD=/var/passwd NSS_WRAPPER_GROUP=/var/group /usr/lib/postgresql/10/bin/initdb


Since you don’t have /etc. you also don’t have /etc/hosts, which is where the hostname localhost is defined. Use everywhere (your app, PostgreSQL config) instead.



Some Node modules want your HOME directory:

const home = os.homedir();

Error: ENOENT: no such file or directory, uv_os_homedir

export HOME=/var at the top of launcher.sh will fix it.

Apollo Client, and all XHR for that matter

You’ll want to send cookies from the grain frame along with your request, otherwise XHR won’t work. In an Apollo client for GraphQL requests, that looks like this (bonus Authentication header setting for PostGraphQL):

import { ApolloClient } from 'apollo-client';
import { createHttpLink } from 'apollo-link-http';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { setContext } from 'apollo-link-context';

const httpLink = createHttpLink({ uri: '/graphql' });
const authLink = setContext((_, { headers }) => {
  const { jwtToken } = place.where.jwt.token.stored;

  const newHeaders = {};
  if (jwtToken) {
    newHeaders.authorization = `Bearer ${jwtToken}`;

  return {
    headers: {
    credentials: 'include', // gets XHR working with Sandstorm

export default new ApolloClient({
  link: authLink.concat(httpLink),
  cache: new InMemoryCache(),

I’m slowly getting my websites put back together. For now, you should check out the other places I’m currently maintaining on the information superhighway that I have linked to on the left.