A+ likes playing recent Minecraft snapshots because of the new features. The modding systems haven't been updated for the snaphots yet, so we couldn't use mods like JourneyMap to teleport around. I didn't want to be the keeper of coordinates and be in charge of teleporting people to various places.
It turns out that you can make clickable books using JSON. I used the Minecraft book editor to make a prototype book and figure out the syntax. Then I used a command block to give it to myself in order to work around the length limits on commands in chat. A+ loved being able to carry around a book that could teleport her to either of us or to specified places, change the time of day, clear the weather, and change game mode. That also meant that I no longer had to type all the commands to give her water breathing, night vision, or slow falling, or give her whatever tools she forgot to pack before she headed out. It was so handy, W- and I got our own copies too.
Manually creating the clickable targets was annoying, especially since we wanted the book to have slightly different content depending on the instance we were in. I wanted to be able to specify the contents using Org Mode tables and generate the JSON for the book using Emacs.
Here's a screenshot:

This is the code to make it:
(defun my-minecraft-book (title author book) "Generate a command to put into a command block in order to get a book. Label it with TITLE and AUTHOR. BOOK should be a list of lists of the form (text click-command color). Copy the command text to the kill ring for pasting into a command block." (let ((s (concat "/item replace entity @p weapon.mainhand with written_book" (json-encode `((title . ,title) (author . ,author) (pages . ,(apply 'vector (mapcar (lambda (page) (json-encode (apply 'vector (seq-mapcat (lambda (command) (let ((text (or (elt command 0) "")) (click (or (elt command 1) "")) (color (or (elt command 2) ""))) (when (string-match "^=\\(.+?\\)=$" click) (setq click (match-string 1 click))) (when (string-match "^=\\(.+?\\)=$" text) (setq text (match-string 1 text))) (unless (or (string-match "^<.*>$" text) (string-match "^<.*>$" click) (string-match "^<.*>$" color)) (list (append (list (cons 'text text)) (unless (string= click "") `((clickEvent (action . "run_command") (value . ,(concat "/" click))))) (unless (string= color "") (list (cons 'color color)))) (if (string= color "") '((text . "\n")) '((text . "\n") (color . "reset"))))))) page)))) (seq-partition book 14) )))))))) (kill-new s) s))
With this code, I can generate a simple book like this:
(my-minecraft-book "Simple book" "sachac" '(("Daytime" "set time 0800") ("Creative" "gamemode creative" "#0000cd")))
/item replace entity @p weapon.mainhand with written_book{"title":"Simple book","author":"sachac","pages":["[{\"text\":\"Daytime\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/set time 0800\"}},{\"text\":\"\\n\"},{\"text\":\"Creative\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/gamemode creative\"},\"color\":\"#0000cd\"},{\"text\":\"\\n\",\"color\":\"reset\"}]"]}
To place it in the world:
- I changed my
server.properties
to setenable-command-block=true
. - In the game, I used
/gamemode creative
to switch to creative mode. - I used
/give @p minecraft:command_block
to give myself a command block. - I right-clicked an empty place to set the block there.
- I right-clicked on the command block and pasted in the command.
- I added a button.
Then I clicked on the button and it replaced whatever I was holding
with the book. I used item replace
instead of give
so that it's
easy to replace old versions.
On the Org Mode side, it's much nicer to specify commands in a named
table. For example, if I name the following table with #+name:
mc-quick
, I can refer to it with :var quick=mc-quick
in the Emacs
Lisp source block. (You can check the Org source for this post if that makes it easier to understand.)
Daytime | time set 0800 | |
Clear weather | weather clear | |
Creative | gamemode creative | #0000cd |
Survival | gamemode survival | #ff4500 |
Spectator | gamemode spectator | #228b22 |
(my-minecraft-book "Book from table" "sachac" quick)
/item replace entity @p weapon.mainhand with written_book{"title":"Book from table","author":"sachac","pages":["[{\"text\":\"Daytime\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/time set 0800\"}},{\"text\":\"\\n\"},{\"text\":\"Clear weather\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/weather clear\"}},{\"text\":\"\\n\"},{\"text\":\"Creative\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/gamemode creative\"},\"color\":\"#0000cd\"},{\"text\":\"\\n\",\"color\":\"reset\"},{\"text\":\"Survival\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/gamemode survival\"},\"color\":\"#ff4500\"},{\"text\":\"\\n\",\"color\":\"reset\"},{\"text\":\"Spectator\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/gamemode spectator\"},\"color\":\"#228b22\"},{\"text\":\"\\n\",\"color\":\"reset\"}]"]}
Then I can define several named tables and append them together. Here's one for different effects:
Water breathing | effect give @p minecraft:water_breathing infinite |
|
Night vision | effect give @p minecraft:night_vision infinite |
|
Regeneration | effect give @p minecraft:regeneration infinite |
|
Haste | effect give @p minecraft:haste infinite |
|
Health boost | effect give @p minecraft:health_boost infinite |
|
Slow falling | effect give @p minecraft:slow_falling infinite |
|
Fire resist | effect give @p minecraft:fire_resistance infinite |
|
Resistance | effect give @p minecraft:resistance infinite |
|
Clear effects | effect clear @p |
Some commands are pretty long. Specifying a width like <20>
in the first row lets me use C-c TAB
to toggle width.
Pickaxe | give @p minecraft:diamond_pickaxe{Enchantments:[{id:"minecraft:fortune",lvl:4s},{id:"minecraft:mending",lvl:1s}]} |
|
Silk touch pickaxe | give @p minecraft:diamond_pickaxe{Enchantments:[{id:"minecraft:silk_touch",lvl:1s},{id:"minecraft:mending",lvl:1s}]} |
|
Sword | give @p minecraft:diamond_sword{Enchantments:[{id:"minecraft:looting",lvl:4s},{id:"minecraft:mending",lvl:1s}]} |
|
Axe | give @p minecraft:diamond_axe{Enchantments:[{id:"minecraft:looting",lvl:4s},{id:"minecraft:mending",lvl:1s}]} |
|
Bow | give @p minecraft:bow{Enchantments:[{id:"minecraft:infinity",lvl:1s},{id:"minecraft:mending",lvl:1s}]} |
|
Arrows | give @p minecraft:arrow 64 |
|
Torches | give @p minecraft:torch 64 |
|
Fishing | give @p minecraft:fishing_rod{Enchantments:[{id:"minecraft:lure",lvl:4s},{id:"minecraft:luck_of_the_sea",lvl:4s},{id:"minecraft:mending",lvl:1s}]} |
|
Trident | give @p minecraft:trident{Enchantments:[{id:"minecraft:loyalty",lvl:4s},{id:"minecraft:mending",lvl:1s},{id:"minecraft:channeling",lvl:1s},{id:"minecraft:riptide",lvl:4s}]} |
|
Weather rain | weather rain |
|
Weather thunder | weather thunder |
Here's what that table looks like in Org Mode:

Here's how to combine multiple tables:
#+begin_src emacs-lisp :results silent :var quick=mc-quick :var effects=mc-effects :var items=mc-items :exports code (my-minecraft-book "Book from multiple tables" "sachac" (append quick effects items)) #+end_src
Now producing instance-specific books is just a matter of including the sections I want, like a table that has coordinates for different bases in that particular instance.
I thought about making an Org link type for click commands and some way of exporting that will convert to JSON and keep the whitespace. That way, I might be able to write longer notes and export them to Minecraft book JSON for in-game references, such as notes on villager blocks or potion ingredients. The table + Emacs Lisp approach is already quite useful for quick shortcuts, though, and it was easy to write. We'll see if we need more fanciness!