Colours

| drawing

(View sketch)

Text and links from sketch

Colours (August IndieWeb Carnival theme) sach.ac/2025-08-31-02

I don't draw with lots of colours these days, even though I can have as many as I want. Usually:

  • black
  • highlight
  • maybe gray
  • maybe an accent colour

I've drawn with more colours before. I think it's when I feel more relaxed about time. A+ is playing Minecraft with her cousins. I could do many other things, but I want to draw.

I looked at 18 years of sketches and picked some things I like.

I came across this collection I made, too: highlighter (style I tend to use), decorations (Luigi Mengato), toned text (Kazumi Koyama), contrasting text (Timothy J. Reynolds), accent text (Eva-Lotta Lamm), spacer (Makayla Lewis), areas (Per Axbom), glow (Katharina Bluhm), background (Eva-Lotta Lamm), flood (ItsLilpeanut), text and outlines (Heather Willems), colourful outlines and fills (Liisa Sorsa), everything (Lynne Cazaly), shade (Makayla Lewis), shaded cartoon (Hamish MacDonald)

I circled the ones I want to try.

In Syllabus, Lynda Barry assigns colouring sheets. Don't rush. Students figure out that thicker colour = more fun.

The library always has crayons and sheets. I've been colouring while waiting for A+. I press hard and fill the space.

I like seeing these across the room as I draw in bed.

Someday I'll get the hang of this!

Feel free to use this sketch under the Creative Commons Attribution License.

Hmm… so many of the sketches from my post in 2014 are no longer accessible, or the sketchnoters haven't posted anything recently, or they no longer use that style, or I can't quite find an equivalent thing to link to. Time marches on, I guess.

More recent colour inspiration from active sketchnoters:

Check out the August IndieWeb Carnival for lots of other colour-related posts.

View org source for this post

Nginx maps: How I redirect sketch IDs to blog posts or sketches

| geek, tech

Assumed audience: I'm mostly writing these notes for myself, because I'd forgotten how this actually works. Maybe it might be interesting for people who also like identifying their posts or sketches and who use Nginx.

Since August 2022, I've been identifying sketches with YYYY-MM-DD-NN, where NN is a number derived from my journaling system. I used to use just YYYY-MM-DD and the title, but sometimes I renamed sketches. Then I used YYYY-MM-DDa (ex: 2022-08-01f). Sometimes optical character recognition had a hard time distinguishing my hand-drawn "d" from "a", though. Numbers were generally more reliable. And besides, that way, there's room for growth in case I have more than 26 journal entries or sketches in a day. (Not that I've gone anywhere near that volume.)

Anyway, I want to have short URLs like sachachua.com/2025-07-31-10 or sach.ac/2025-07-31-10 go to a blog post if one's available, or just the sketch if I haven't written about it yet, like sach.ac/2025-01-16-01. Here's how I do it.

To publish my site, I export HTML files from Org Mode and I use the 11ty static site generator to put them together in a blog.

One of my 11ty files is map.11ty.cjs, which has the following code:

map.11ty.cjs
module.exports = class AllPosts {
  data() {
    return {
      permalink: '/conf/nginx.map',
      eleventyExcludeFromCollections: true
    };
  }
  async render (data) {
    let list = data.collections._posts;
    let cats = data.siteCategoriesWithParents;
    let nested = cats.filter(o => o.parent);
    let hash = {};
    await list.reduce(async (prev, o) => {
      await prev;
      if (o.data?.zid) {
        hash[o.data.zid] = o.url;
      }
      let matches = (await o.template.inputContent).matchAll(/{% +sketchFull +\"([0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9](-[0-9][0-9]|[a-z]))?/g);
      for (const m of matches) {
        if (m[1] && !hash[m[1]]) {
          hash[m[1]] = o.url;
        }
      }
    });
    let byZIDs = Object.entries(hash).map((o) => `/${o[0]} ${o[1]};\n`).join('');
    let byBlogID = list.filter(o => o.data.id).map((o) => `/blog/p/${o.data.id} ${o.url};`).join("\n") + "\n";
    let nestedCategories = nested.map((o) => {
      let slugPath = o.parentPath.map((p) => p.slug).join('/') + '/' + o.slug;
      let catPage = `/blog/category/${slugPath} /blog/category/${o.slug};\n`;
      let catFeed = `/blog/category/${slugPath}/feed/ /blog/category/${o.slug}/feed/;\n`;
      let catAtom = `/blog/category/${slugPath}/feed/atom/ /blog/category/${o.slug}/feed/atom/;\n`;
      return catAtom + catFeed + catPage;
    }).join('');
    const result = byBlogID + nestedCategories + byZIDs;
    return result;
  }
};

The code analyzes each of my blog posts and looks for full-sized sketches. If it finds a full-size sketch, it writes a rule that redirects that ID to that blog post. This is what part of the resulting nginx.map looks like:

/2025-07-31-10 /blog/2025/08/monthly-review-july-2025/;
/2025-08-04-01 /blog/2025/08/turning-42-life-as-a-41-year-old/;
/2025-08-03-08 /blog/2025/08/turning-42-life-as-a-41-year-old/;
/2025-08-31-01 /blog/2025/08/emacs-elevator-pitch-tinkerers-unite/;

In my Nginx web server config (nginx.conf), I have:

http {
  # ...
  include /etc/nginx/redirections.map;
  # ...
}

And that redirections.map uses the map module and looks like this:

map $request_uri $new_uri {
   default "";
   include /var/www/static-blog/conf/nginx.map;
   / /blog;
   # ...
}

Then in my Nginx site configuration, I redirect to that $new_uri if available. As a fallback, I also detect yyyy-mm-dd-nn URLs and redirect them to my sketchbook.

server {
   # ... other rules
   if ($new_uri) {
       return 302 $new_uri;
   }
   location ~ ^/([0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9](a-z|-[0-9][0-9])?)$ {
      return 302 https://sketches.sachachua.com/$1;
   }
}

The Node app that runs sketches.sachachua.com searches by ID if it gets one. Here's the code in the Express router:

router.get('/:filename', controller.serveImagePageByFilename);

which calls this controller:

exports.serveImagePageByFilename = async (req, res) => {
  if (req.params.filename) {
    let f = await findImageByFilename(req.params.filename);
    if (f) {
      renderSingle(req, res, f);
    } else {
      res.sendStatus(404);
    }
  } else {
    res.sendStatus(404);
  }
};

which uses this function:

const findImageByFilename = (filename) => {
  return getSketches().then((sketches) => {
    let id = filename.match(/^[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]([a-z]|-[0-9][0-9])/);
    let m = filename.match(/^[^#]+/);
    let file = sketches.find((x) => path.parse(x.filename).name == filename);
    if (!file) {
      file = sketches.find((x) => x.filename.startsWith(id));
    }
    if (!file && m) {
      file = sketches.find((x) => x.filename.startsWith(m[0]));
    }
    if (!file) {
      file = sketches.find((x) => path.parse(x.filename).name.replace(' #.*') == filename);
    }
    if (!file) {
      file = sketches.find((x) => x.filename.startsWith(filename));
    }
    return file;
  });
};

(getSketches just reads the JSON I've saved.)

So my workflow for a public sketch is:

  1. Draw the sketch.
  2. In my journaling system, write the title and tags for the sketch. Get an ID.
  3. Write the ID on the sketch.
  4. Export the sketch from the iPad as a JPEG.
  5. Wait for things to sync in the background.
  6. Process the sketch. I can use my-image-rename-current-image-based-on-id to rename it manually, or I can use my-sketch-process to recognize the ID and process the text. (My Emacs configuration)
  7. Wait for things to sync in the background. In the meantime, edit the text version of the sketch.
  8. Reload my public sketches, which regenerates the sketches.json that lists all the sketches.
  9. Use my-write-about-sketch or my-insert-sketch-and-text to include the sketch and the text in a draft blog post. (My Emacs configuration) Do my usual blogging process.
View org source for this post

Emacs elevator pitch: tinkerers unite

| emacs, community

This is for the Emacs Carnival 2025-08: Your Elevator Pitch for Emacs hosted by Jeremy Friesen. Emacs is a text editor, but people have made it so much more.

Text and links from sketch

Emacs elevator pitch https://sach.ac/2025-08-31-01

That's the theme for the August Emacs Carnival.

I don't spend much time in elevators these days, and I didn't talk much to strangers even during the before-times.

So let's imagine this is more of, say, a meetup. (Someday I'll get back to going to those.) Could be tech, could be something else. Could be online, could be in person.

I don't have to convince everyone. I don't even have to convince a single person. My goal is to listen for the tinkerers: the ones who like to ask "Why?" and "What if?" and who try things out. They're interesting.

I can find them by:

  • watching talks (sketchnotes are a great thank-you gift)
  • eavesdropping or asking questions
  • sharing what I'm tinkering with

No: Why would anyone do that? Yes: Have you thought of trying xyz?

For tinkerers, the juice might be worth the squeeze. Emacs can be challenging, but it can also pay off. It can even be fun.

Even when I find a fellow tinkerer, the conversation isn't "Have you tried Emacs? You should try Emacs." It'll probably be more like:

"I'd love to keep hearing about your experiments. Do you have something I can subscribe to or follow?" (Side-quest: Try to convince them to blog.)

and then the conversation can unfold over time:

  • "Ooh, I like that idea. Here's my take on it."
  • "How did you do that? What's that?!"
  • "Oh, yeah, Emacs. It's very programmable, so I can get it to do all sorts of stuff for me. Wanna see?"

…and sometimes they fall into the rabbit hole themselves, as tinkerers often do. But even if they don't try Emacs (or don't stick with it), cross-pollination is great. And sometimes Emacs changes their life.

To get a sense of the kinds of things someone has gotten Emacs to do, check out Alvaro Ramirez's post. I have a list like that at emacs. On the topic of cross-pollination, I like Jeremy Friesen's EmacsConf 2023 talk on Mentoring VS-Coders as an Emacsian (or How to show not tell people about the wonders of Emacs).

It's always fun to come across a fellow tinkerer. I love seeing what people come up with. Emacs works out really well for tinkerers. It's not just about taking advantage of the technical capabilities (and you can do a surprising amount with text, images, and interaction), it's also about being part of a great community that's in it long-term. Good stuff.

Feel free to use this sketch under the Creative Commons Attribution License.

View org source for this post

2025-08-25 Emacs news

| emacs, emacs-news

I'm experimenting with commentary and formatting! =) The Emacs Carnival blogging theme of elevator pitch seems to have resonated with a lot of people: 18 entries so far, which is perfect timing because there's also a new online book for Emacs beginners. Also, if you're looking for a "Can your text editor do this?!" sort of example, there was a lively discussion about clipping videos with Emacs on Hacker News. (Be prepared for bewilderment, though.) On the other hand, if you're here for serious stuff and want a technical deep dive, check out Yuan Fu's post on Emacs tree-sitter integration. Here are the other links:

Links from reddit.com/r/emacs, r/orgmode, r/spacemacs, r/planetemacs, Mastodon #emacs, Bluesky #emacs, Hacker News, lobste.rs, programming.dev, lemmy.world, lemmy.ml, planet.emacslife.com, YouTube, the Emacs NEWS file, Emacs Calendar, and emacs-devel. Thanks to Andrés Ramírez for emacs-devel links. Do you have an Emacs-related link or announcement? Please e-mail me at sacha@sachachua.com. Thank you!

View org source for this post

Notes: Pottery wheel afternoon summer camp

| parenting

Today was the last day of A+'s week-long wheel-throwing afternoon summer camp at Parkdale Pottery in Toronto. She's focused on wheel throwing at the moment, not hand-building. It's hard to find pottery wheel lessons for 9-year-olds because of strength and safety concerns. A+'s been doing the all-ages 2-hour wheel-throwing workshops at Clay With Me independently around once a month, and she's also tried painting premade pieces. It felt like a minor miracle to find a half-day camp focused on just what she wanted.

Before the workshop, A+ wasn't sure about trying out a different studio, since she'd gotten comfortable at Clay With Me. She settled in quickly, though, and even took charge of packing her snacks and getting her clothes and apron ready for the next day. It was great to see her grow more independent.

A+ likes to work with smaller balls of clay so that they're easier to centre and handle. In Clay with Me workshops, she usually asks the instructors to divide a ball in half. Because the Parkdale Pottery camp was for kids 8-12 years old, the clay balls they provided were the right size for her hands, and the instructors also showed the kids how to prepare their own.

The first three days focused on wheel throwing. The instructor complimented A+ on her centreing skills. She's gotten pretty good at bracing herself so that she can form the puck right in the middle. She also learned about adding attachments by scoring the clay and adding slip. The fourth day was about refining and trimming, and the fifth day was about glazing. She enjoyed learning how to marble her pieces with interesting blue-and-white swirls, and I enjoyed her description of the process: layering the underglazes, then swirling them around to create the design. This was the first time she was able to trim and glaze her own pieces, since the Clay with Me workshops are one-off sessions where the pieces are all finished with a clear food-safe glaze. Parkdale Pottery will fire A+'s pieces with a food-safe glaze too, and we'll pick them up in a few weeks.

When kids finished early or wanted to take a break, they explored hand-building, drew circles with markers on paper attached to pottery wheels, worked with beads, and played the board game Trouble. The instructors did a good job of managing the occasional squabbles.

Looking at other students' work on the shelves and the instructional posters on the wall, I saw interesting ideas that we might try in future workshops. (Gotta make a face vase…)

The half-day summer camp was from 1 PM to 4 PM from Monday to Friday, and it cost $250+HST. There was a full-day option, but A+ wasn't interested in hand-building. I think the half-day was worth it, especially since I managed to squeeze in about 2 hours of consulting every day even with setting aside time to bike back and forth. We're gradually transitioning to the phase where she wants to learn about things I can't teach her, and paying for clay workshops is a great way to access people's specialized expertise and equipment. I don't know how many kids there were in the camp, but A+ was happy with the teacher-student ratio and felt like she had enough time to get whatever help she needed.

From her previous workshops, we've collected a good selection of little ice cream bowls and saucers. This camp will add a few more saucers and tiny bowls. It might be a good idea to learn how to make little treats (maybe chocolate truffles?) that we can place on the saucers for an extra-special birthday gift. ("Wrapped in plastic and tied with a bow?" she asks.)

Next steps: We'll probably continue with the Clay with Me workshops, since A+ likes the studio and is comfortable with the process. I also want to explore a little handbuilding with polymer clay and air dry clay, and some sketching to imagine pieces. Maybe she'll get into that too. When we come up with pieces we really like, we can do one of the handbuilding workshops at a pottery studio in order to make a food-safe version, or consider a clay-at-home package (Shaw Street Pottery) that can be fired. When A+ turns 10, she'll be old enough for the wheel courses at places like Create Art Studio and 4cats. They generally schedule their teen wheel courses on weekdays, though, and a weekend would probably be better for us.

A+ wants to do this summer camp again next year. She prefers unstructured time and plenty of afternoon playdates, so it'll probably be just one week, like this year. We'll see when we get there. Plenty to explore. It's nice to have a craft, and maybe this will be one of hers.

View org source for this post

2025-08-18 Emacs news

| emacs, emacs-news

If you're looking for something to write about, consider this month's Emacs Carnival theme: your elevator pitch for Emacs.

Links from reddit.com/r/emacs, r/orgmode, r/spacemacs, Mastodon #emacs, Bluesky #emacs, Hacker News, lobste.rs, programming.dev, lemmy.world, lemmy.ml, planet.emacslife.com, YouTube, the Emacs NEWS file, Emacs Calendar, and emacs-devel. Thanks to Andrés Ramírez for emacs-devel links. Do you have an Emacs-related link or announcement? Please e-mail me at sacha@sachachua.com. Thank you!

View org source for this post

2025-08-11 Emacs news

| emacs, emacs-news

Links from reddit.com/r/emacs, r/orgmode, r/spacemacs, r/planetemacs, Mastodon #emacs, Bluesky #emacs, Hacker News, lobste.rs, programming.dev, lemmy.world, lemmy.ml, planet.emacslife.com, YouTube, the Emacs NEWS file, Emacs Calendar, and emacs-devel. Thanks to Andrés Ramírez for emacs-devel links. Do you have an Emacs-related link or announcement? Please e-mail me at sacha@sachachua.com. Thank you!

View org source for this post