Minecraft tree orbs, tree farm upgrade

| minecraft

A+ was inspired by the SapWing villages from Wings of Fire to make a couple of orb houses up in the trees.

2025-01-16_17.33.21.png
Figure 1: A+'s latest creation: tree orbs

I think she used copycat blocks and vertical slabs from the modpack in order to get it to look so round. "I'm excellent at creating things that are not supposed to exist in Minecraft, in Minecraft," she says. The rope ladder is from me, as I needed a non-creative-mode way to get up there.

2025-01-16_18.01.13.png
Figure 2: A bridge connects the two tree orbs. A+ is a big fan of safety railings.
2025-01-16_18.02.05.png
Figure 3: My orb has a hammock, a furnace, and a crafting table
2025-01-16_18.29.08.png
Figure 4: She also decided to upgrade my tree farm with rich soil, a portable storage interface, and an item sorter.

The smart chute is set to drop only full stacks (64 items) so that the extra saplings will stay in the chest and feed the deployer. The brass funnels have the different items in their filter slots. She has them feeding into netherite backpacks.

2025-01-16_17.36.34.png
Figure 5: As for me, I made a simple library with an enchanting table.

I've got a couple of librarians. I'll probably set up some more eventually, maybe in a large wing focused on trading. I've also been upgrading the wheat farm with organic compost that's broken down into rich soil. I started some flax plants for string.

Just toodling along…

View org source for this post

Changing planet.emacslife.com

| emacs

For the longest time, planet.emacslife.com was generated with the Planet Venus aggregator, which required Python 2.7. My recent blog post about Yay Emacs 8: which-key-replacement-alist had some emojis that the parser couldn't handle, though (unichr() arg not in range(0x10000) (narrow Python build)). I decided to rewrite the aggregator using NodeJS.

Here are some differences between the current implementation and the previous ones:

  • The website shows the last two weeks of posts, since I can filter by date. It should also ignore future-dated posts.
  • The list of feeds on the right side is now sorted by last post date, so it's easier to see active blogs.
  • I can now filter a general feed by a regular expression.
  • I've removed a number of unreachable blogs.
  • The feed list is loaded from a JSON instead of an INI.

The Atom feed and the OPML file should validate, but let me know at sacha@sachachua.com if there are any hiccups (or if you have an Atom/RSS feed we can add to the aggregator =) ).

View org source for this post

Learning more about looking ahead together

| parenting, planning

Text from sketch

A+ is 8 years old. We're letting her be part of managing more things for her future self, like keeping track of when we're running low on her laundry or her favourite yogurt or toilet paper under the sink. She doesn't always get it right, but then again, even grown-ups have a hard time. She still sometimes melts down. Maybe I can break this down into subskills so that we can get better at them together.

  • Anticipating: Noticing an opportunity is the first step. Predicting what might be helpful is another.
    • Plan out loud
    • Talk about future self
    • Walk through questions.
  • Choosing your future self: Delayed gratification, investing in future
    • Talk about tradeoffs
    • Add more benefits
  • Preparing: Cues & memory aids
    • Show us using lists, checklists, notes, cues
  • Celebrating: Patting ourselves on the back helps reinforce the habit
    • "I'm glad we…"
    • catch her doing well
  • Adapting: Sometimes we forget or things don't work out. What are we going to do now?
    • This is hard for A+ to do in the moment, but my staying calm will help, and experience helps too.
  • Experimenting: Instead of blaming ourselves or blaming other people, it's more useful to treat it as a data point that can help us improve our processes.
    • Best done during a calm moment, maybe at the next opportunity

These things are challenging when we're dysregulated. We can grow together when things settle down.

There will be tons of opportunities to practice, and we can all grow.

One of the neat things about parenting is that I get to think about how to develop different skills. Today I want to think about planning ahead. I can see the beginnings of it developing in A+, like when she says, "I'm going to put on my boots before I put on my mittens because that's easier when you have fingers." I can see when it's more of a struggle, like when we've forgotten to bring the stuffed toy she wanted to take along and she's overwhelmed with frustration. I can draw parallels between that and the way I'm learning more about this skill myself, like when we use the Band-aids I've stashed in my emergency kit or when I've forgotten to pack lunch and have to find something that A+ will like within walking distance. Even grown-ups have a hard time with these skills. We've got plenty of examples around us of people working on improving that skill and people who struggle.

I like breaking skills down into smaller chunks so that they're easier to think about, practise, and learn. Breaking down the idea of looking ahead into anticipating, choosing your future self, preparing, celebrating, adapting, and experimenting makes more sense to me than treating it as one big lump. I want to think about these subskills in this blog post so that I can get better at them and so that we can swap notes.

The parts that are hardest for A+ at the moment are adapting and experimenting. That makes a lot of sense. That's when planning gets tested. That's when you get feedback from reality. That's difficult for lots of people, even grown-ups, and I have plenty to learn about those parts myself.

Adapting: cognitive flexibility

I think of adapting as handling things in the moment, switching to the question, "So, what are we going to do now?" To be able to do that, A+ needs to be able to manage or sidestep the fight-flight-freeze response. I think a large part of this might just be accumulating enough experiences to know that these things are survivable, and part of it is probably waiting for her brain to mature. I can't skip those things for her, but I can validate her feelings and show her that they're tolerable by staying calm myself. I'm pretty good at staying calm if I've paid attention to my basic needs. If I'm off-balance, I can ask W- for help. When I'm calm, I can be curious about what she feels and how she eventually calms down.

I also find this part challenging. When she asks me for something that she's thought of late, sometimes I'm not sure whether my figuring it out will mean she doesn't get as much practice or feedback in planning ahead or adapting. Sometimes I hesitate or say no, and then she gets grumpy and frustrated, and then I become even less flexible because I don't want to encourage grumping at me to get what she wants. I guess she's going to eventually figure out how and when to ask so that she has a higher likelihood of yes. For my part, I think it's okay to want most decisions to be slowed down and considered without pressure, so I can get better at tolerating A+'s discomfort so that she gets that feedback.

When it comes to accepting things, I like drawing on radical acceptance and Stoic philosophy, although A+'s probably a little young for me to talk about preferred and dispreferred indifferents, at least in those terms. I can model those ideas out loud, though.

Another part of adapting is having a wide vocabulary of ways we can solve problems, which we pick up through experience, skills, and learning from other people.

Sometimes I come up with ways to solve a problem, but she's not ready to move to that step yet because she's still dealing with strong feelings, and I can't help her co-regulate because she's grumpy with me. There's no rushing past that, there's no shortcut I can do to help her with her feelings, but I can be curious about what she does to eventually help herself cool down.

Besides, me coming up with ways to solve a problem is not nearly as useful as her eventually learning how to cool down and come up with her own ideas for solving it. I can save my ideas for wondering out loud, if she asks me for help. Might as well not waste a good motivating problem.

Resources:

Experimenting: reflective practice

It would be counterproductive for me to try to cushion A+ from failure. I want her to develop her own skills, so I want her to make decisions (especially ones without long-term negative consequences). Some of those decisions won't work out the way she wanted them to, but that's life. Besides, "How can we make things better next time?" is a question that can build on both positive and negative experiences, so even the uncomfortable moments can be useful.

When things don't work out, it's very tempting to blame ourselves or other people, but that doesn't really help us more forward. I want to be able to see the ups and downs as data points in our experiments and as opportunities to improve our processes. I keep working on getting better at responding to my own oopses and my delegated oopses. Fortunately, I have lots of opportunities to practice.

Swiss cheese

From James Reason's Swiss Cheese model of human errors:

The basic premise in the system approach is that humans are fallible and errors are to be expected, even in the best organisations. Errors are seen as consequences rather than causes, having their origins not so much in the perversity of human nature as in “upstream” systemic factors. … When an adverse event occurs, the important issue is not who blundered, but how and why the defences failed.

Failures point to multiple ways that we might be able to learn and to improve our systems. Paying attention to those opportunities could save us from bigger mistakes later on. Finding bugs when developing means dealing with fewer bugs in production, and this is basically her development environment. Besides, there's a lot of satisfaction in improving our systems.

Still, it's hard to think when people are dysregulated. It's easier to take that perspective when things are calm and there's an opportunity to try something new. So in the moment, my job is to weather the storm and adapt as well as I can. After the storm passes, I can think about what would make things better next time around. When I notice that A+ is calm and ready to learn, I can invite her to think along with me. She still gets defensive if I use the past events as an anchor for reflection. She responds better if we're planning for something that's coming up soon. I can use avoidance sparingly ("last time, that didn't work out so well") and lean more on building on things that worked well. That kind of reflection will probably be mostly on my side for now, but maybe she'll grow into it eventually.

I keep a brief journal, but life with A+ doesn't usually lend itself to quickly looking things up so that I can pull in the appropriate anecdotes at the right time. The tough moments tend to be easy to remember because they're emotionally-laden, but since I want to build on positive experiences as well, I can:

  1. slow down and notice things out loud in the moment,
  2. retell it shortly after, perhaps during dinnertime,
  3. capture it in my journal so I can look it up again, and
  4. think of the next little step, or some cues or situations it might be relevant to.

It's also probably easier for A+ to learn from my thinking out loud about my own processes than about hers. Fortunately, life gives me plenty of opportunities to practise learning out loud.

We already have a habit around drawing a moment of the day, and I could probably add something like Rose-Thorn-Bud to dinnertime or bedtime conversations. A+'s teachers sometimes add reflection to their assignments, too.

I probably don't even have to worry too much about explicitly teaching A+ these skills. I just have to try to not get in the way of her learning them. If we learn together, I think we'll figure all sorts of cool things out.

View org source for this post

2025-01-13 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, communick.news, 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

Treemap visualization of an Org Mode file

| org, visualization

[2025-01-12 Sun]: u/dr-timeous posted a treemap_org.py · GitHub that makes a coloured treemap that displays the body on hover. (Reddit) Also, I think librsvg doesn't support wrapped text, so that might mean manually wrapping if I want to figure out the kind of text density that webtreemap has.

One of the challenges with digital notes is that it's hard to get a sense of volume, of mass, of accumulation. Especially with Org Mode, everything gets folded away so neatly and I can jump around so readily with C-c j (org-goto) or C-u C-c C-w (org-refile) that I often don't stumble across the sorts of things I might encounter in a physical notebook.

Treemaps are a quick way to visualize hierarchical data using nested rectangles or squares, giving a sense of relative sizes. I was curious about what my main organizer.org file would look like as a treemap, so I wrote some code to transform it into the kind of data that https://github.com/danvk/webtreemap wants as input. webtreemap creates an HTML file that uses Javascript to let me click on nodes to navigate within them.

For this treemap prototype, I used org-map-entries to go over all the headings and make a report with the outline path and the size of the heading. To keep the tree visualization manageable, I excluded done/cancelled tasks and archived headings. I also wanted to exclude some headings from the visualization, like the way my Parenting subheading has lots of personal information underneath it. I added a :notree: tag to indicate that a tree should not be included.

Screencast of exploring a treemap

Reflections

2025-01-11_19-54-47.png
Figure 1: Screenshot of the treemap for my organizer.org

The video and the screenshot above show the treemap for my main Org Mode file, organizer.org. I feel like the treemap makes it easier to see projects and clusters where I'd accumulated notes, both in terms of length and quantity. (I've omitted some trees like "Parenting" which take up a fairly large chunk of space.)

To no one's surprise, Emacs takes up a large part of my notes and ideas. =)

When I look at this treemap, I notice a bunch of nodes I need to mark as DONE or CANCELLED because I forgot to update my organizer.org. That usually happens when I come up with an idea, don't remember that I'd come up with it before, put it in my inbox.org file, and do it from there or from the organizer.org location I've refiled it to without bumping into the first idea. Once in a blue moon, I go through my whole organizer.org file and clean out the cruft. Maybe a treemap like this will make it easier to quickly scan things.

Interestingly, "Explore AI" takes up a disproportionately large chunk of my "Inactive Projects" visualization, even though I spend more time and attention on other things. Large language models make it easy to generate a lot of text, but I haven't really done the work to process those. I've also collected a lot of links that I haven't done much with.

It might be neat to filter the headings by timestamp so that I can see things I've touched in the last 6 months.

Hmm, looking at this treemap reminds me that I've got "organizer.org/Areas/Ideas for things to do with focused time/Writing/", which probably should get moved to the posts.org file that I tend to use for drafts. Let's take look at the treemap for that file. (Updated: cleared it out!)

2025-01-11_20-10-18.png
Figure 2: Drafts in my posts.org

Unlike my organizer.org file, my posts.org file tends to be fairly flat in terms of hierarchy. It's just a staging ground for ideas before I put them on my blog. I usually try to keep posts short, but a few of my posts have sub-headings. Since the treemap makes it easy to see nodes that are larger or more complex, that could be a good nudge to focus on getting those out the door. Looking at this treemap reminds me that I've got a bunch of EmacsConf posts that I want to finish so that I can document more of our processes and tools.

2025-01-11_14-52-28.png
Figure 3: Treemap of my inbox

My inbox.org is pretty flat too, since it's really just captured top-level notes that I'll either mark as done or move somewhere else (usually organizer.org). Because the treemap visualization tool uses / as a path separator, the treemap groups headings that are plain URLs together, grouped by domain and path.

2025-01-12_08-30-44.png
Figure 4: Treemap of my Emacs configuration

My Emacs configuration is organized as a hierarchy. I usually embed the explanatory blog posts in it, which explains the larger nodes. I like how the treemap makes it easy to see the major components of my configuration and where I might have a lot of notes/custom code. For example, my config has a surprising amount to do with multimedia considering Emacs is a text editor, and that's mostly because I like to tinker with my workflow for sketchnotes and subtitles. This treemap would be interesting to colour based on whether something has been described in a blog post, and it would be great to link the nodes in a published SVG to the blog post URLs. That way, I can more easily spot things that might be fun to write about.

The code

This assumes https://github.com/danvk/webtreemap is installed with npm install -g webtreemap-cli.

(defvar my-org-treemap-temp-file "~/treemap.html") ; Firefox inside Snap can't access /tmp
(defvar my-org-treemap-command "treemap" "Executable to generate a treemap.")

(defun my-org-treemap-include-p (node)
  (not (or (eq (org-element-property :todo-type node) 'done)
           (member "notree" (org-element-property :tags node))
           (org-element-property-inherited :archivedp node 'with-self))))

(defun my-org-treemap-data (node &optional path)
  "Output the size of headings underneath this one."
  (let ((sub
         (apply
          'append
          (org-element-map
              (org-element-contents node)
              '(headline)
            (lambda (child)
              (if (my-org-treemap-include-p child)
                  (my-org-treemap-data
                   child
                   (append path
                           (list
                            (org-no-properties
                             (org-element-property :raw-value node)))))
                (list
                 (list
                  (-
                   (org-element-end child)
                   (org-element-begin child))
                  (string-join
                   (cdr
                    (append path
                            (list
                             (org-no-properties
                              (org-element-property :raw-value node))
                             (org-no-properties
                              (org-element-property :raw-value child)))))
                   "/")
                  nil))))
            nil nil 'headline))))
    (append
     (list
      (list
       (-
        (org-element-end node)
        (org-element-begin node)
        (apply '+ (mapcar 'car sub))
        )
       (string-join
        (cdr
         (append path
                 (list
                  (org-no-properties (org-element-property :raw-value node)))))
        "/")
       (my-org-treemap-include-p node)))
     sub)))

(defun my-org-treemap ()
  "Generate a treemap."
  (interactive)
  (save-excursion
    (goto-char (point-min))
    (let ((file (expand-file-name (expand-file-name my-org-treemap-temp-file)))
          (data (cdr (my-org-treemap-data (org-element-parse-buffer)))))
      (with-temp-file file
        (call-process-region
         (mapconcat
          (lambda (entry)
            (if (elt entry 2)
                (format "%d %s\n" (car entry)
                        (replace-regexp-in-string org-link-bracket-re "\\2" (cadr entry)))
              ""))
          data
          "")
         nil
         my-org-treemap-command nil t t))
      (browse-url (concat "file://" (expand-file-name my-org-treemap-temp-file))))))

There's another treemap visualization tool that can produce squarified treemaps as coloured SVGs, so that style might be interesting to explore too.

Next steps

I think there's some value in being able to look at and think about my outline headings with a sense of scale. I can imagine a command that shows the treemap for the current subtree and allows people to click on a node to jump to it (or maybe shift-click to mark something for bulk action), or one that shows subtrees summing up :EFFORT: estimates or maybe clock times from the logbook, or one limited by a timestamp range, or one that highlights matching entries as you type in a query, or one that visualizes s-exps or JSON or project files or test coverage.

It would probably be more helpful if the treemap were in Emacs itself, so I could quickly jump to the Org nodes and read more or mark something as done when I notice it. boxy-headings uses text to show the spatial relationships of nested headings, which is neat but probably not up to handling this kind of information density. Emacs can also display SVG images in a buffer, animate them, and handle mouse-clicks, so it could be interesting to implement a general treemap visualization which could then be used for all sorts of things like disk space usage, files in project modules, etc. SVGs would probably be a better fit for this because that allows increased text density and more layout flexibility.

It would be useful to browse the treemap within Emacs, export it as an SVG so that I can include it in a webpage or blog post, and add some Javascript for web-based navigation.

The Emacs community being what it is (which is awesome!), I wouldn't be surprised if someone's already figured it out. Since a quick search for treemap in the package archives and various places doesn't seem to turn anything up, I thought I'd share these quick experiments in case they resonate with other people. I guess I (or someone) could figure out the squarified treemapping algorithm or the ordered treemap algorithm in Emacs Lisp, and then we can see what we can do with it.

I've also thought about other visualizations that can help me see my Org files a different way. Network graphs are pretty popular among the org-roam crew because org-roam-ui makes them. Aside from a few process checklists that link to headings that go into step-by-step detail and things that are meant to graph connections between concepts, most of my Org Mode notes don't intentionally link to other Org Mode notes. (There are also a bunch of random org-capture context annotations I haven't bothered removing.) I tend to link to my public blog posts, sketches, and source code rather than to other headings, so that's a layer of indirection that I'd have to custom-code. Treemaps might be a good start, though, as they take advantage of the built-in hierarchy. Hmm…

View org source for this post

Automatically correcting phrasing and misrecognized words in speech-to-text captions by using a script

| subed, emacs

I usually write my scripts with phrases that could be turned into the subtitles. I figured I might as well combine that information with the WhisperX transcripts which I use to cut out my false starts and oopses. To do that, I use the string-distance function, which calculates how similar strings are, based on the Levenshtein [distance] algorithm. If I take each line of the script and compare it with the list of words in the transcription, I can add one transcribed word at a time, until I find the number with the minimum distance from my current script phrase. This lets me approximately match strings despite misrecognized words. I use oopses to signal mistakes. When I detect those, I look for the previous script line that is closest to the words I restart with. I can then skip the previous lines automatically. When the script and the transcript are close, I can automatically correct the words. If not, I can use comments to easily compare them at that point. Even though I haven't optimized anything, it runs well enough for my short videos. With these subtitles as a base, I can get timestamps with subed-align and then there's just the matter of tweaking the times and adding the visuals.

Text from sketch

Matching a script with a transcript 2025-01-09-01

  • script
  • record on my phone
  • WhisperX transcript (with false starts and recognition errors)

My current implementation is totally unoptimized (n²) but it's fine for short videos.

Process:

  • While there are transcript words to process
    • Find the script line that has the minimum distance to the words left in the transcript. restart after oopses
  • Script
  • Transcript: min. distance between script phrase & transcript
  • Restarting after oops: find script phrase with minimum distance
  • Ex. script phrase: The Emacs text editor
  • Transcript: The Emax text editor is a…
  • Bar graph of distance decreasing, and then increasing again
  • Minimum distance
  • Oops?
    • N: Use transcript words, or diff > threshold?
      • Y: Add script words as comment
      • N: Correct minor errors
    • Y: Mark caption for skipping and look for the previous script line with minimum distance.

Result:

  • Untimed captions with comments
  • Aeneas
  • Timed captions for editing

This means I can edit a nicely-split, mostly-corrected file.

I've included the links to various files below so you can get a sense of how it works. Let's focus on an excerpt from the middle of my script file.

it runs well enough for my short videos.
With these subtitles as a base,
I can get timestamps with subed-align

When I call WhisperX with large-v2 as the model and --max_line_width 50 --segment_resolution chunk --max_line_count 1 as the options, it produces these captions corresponding to that part of the script.

01:25.087 --> 01:29.069
runs well enough for my short videos. With these subtitles

01:29.649 --> 01:32.431
as a base, I can get... Oops. With these subtitles as a base, I

01:33.939 --> 01:41.205
can get timestamps with subedeline, and then there's just

Running subed-word-data-use-script-file results in a VTT file containing this excerpt:

00:00:00.000 --> 00:00:00.000
it runs well enough for my short videos.

NOTE #+SKIP

00:00:00.000 --> 00:00:00.000
With these subtitles as a base,

NOTE #+SKIP

00:00:00.000 --> 00:00:00.000
I can get... Oops.

00:00:00.000 --> 00:00:00.000
With these subtitles as a base,

NOTE
#+TRANSCRIPT: I can get timestamps with subedeline,
#+DISTANCE: 0.14

00:00:00.000 --> 00:00:00.000
I can get timestamps with subed-align

There are no timestamps yet, but subed-align can add them. Because subed-align uses the Aeneas forced alignment tool to figure out timestamps by lining up waveforms for speech-synthesized text with the recorded audio, it's important to keep the false starts in the subtitle file. Once subed-align has filled in the timestamps and I've tweaked the timestamps by using the waveforms, I can use subed-record to create an audio file that omits the subtitles that have #+SKIP comments.

The code is available as subed-word-data-use-script-file in subed-word-data.el. I haven't released a new version of subed.el yet, but you can get it from the repository.

In addition to making my editing workflow a little more convenient, I think it might also come in handy for applying the segmentation from tools like sub-seg or lachesis to captions that might already have been edited by volunteers. (I got sub-seg working on my system, but I haven't figured out lachesis.) If I call subed-word-data-use-script-file with the universal prefix arg C-u, it should set keep-transcript-words to true and keep any corrections we've already made to the caption text while still approximately matching and using the other file's segments. Neatly-segmented captions might be more pleasant to read and may require less cognitive load.

There's probably some kind of fancy Python project that already does this kind of false start identification and script reconciliation. I just did it in Emacs Lisp because that was handy and because that way, I can make it part of subed. If you know of a more robust or full-featured approach, please let me know!

View org source for this post

Org Babel, Mermaid JS, and fixing "Failed to launch the browser process" on Ubuntu 24

| emacs, org

Mermaid makes pretty diagrams from text. It's Javascript-based, so the command-line tool (mmdc) uses Puppeteer to get the results of evaluating the diagram in the browser. I was running into some errors trying to get it to work from Org Mode over ob-mermaid on Ubuntu 24, since apparently AppArmor restricts Puppeteer. (Error: Failed to launch the browser process! · Issue #730 · mermaid-js/mermaid-cli).

I put together a pull request to modify ob-mermaid-cli-path so that it doesn't get quoted and can therefore have the aa-exec command needed to work around that. With that modified org-babel-execute:mermaid, I can then configure ob-mermaid like this:

(use-package ob-mermaid
  :load-path "~/vendor/ob-mermaid")
;; I need to override this so that the executable isn't quoted
(setq ob-mermaid-cli-path "aa-exec --profile chrome mmdc -c ~/.config/mermaid/config.json")

I also ran into a problem where the library that Emacs uses to display SVGs could not handle the foreignObject elements used for the labels. mermaid missing text in svg · Issue #112 · mermaid-js/mermaid-cli . Using the following ~/.config/mermaid/config.json fixed it, and I put the option in the ob-mermaid-cli-path above so that it always gets loaded.

{
  "flowchart": {
    "useMaxWidth": false,
    "htmlLabels": false
  }
}

Here's sample Mermaid markup and the file it creates:

mindmap
  root((test))
    Node 1
      Node 1A
      Node 1B
    Node 2
    Node 3
testNode 1Node 2Node 3Node 1ANode 1B

Now I can see the labeled diagrams inside Emacs, too.

This is part of my Emacs configuration.
View org source for this post