diff --git a/demos/README.md b/demos/README.md
new file mode 100644
index 0000000000..0e29a7c818
--- /dev/null
+++ b/demos/README.md
@@ -0,0 +1,42 @@
+# Screenshots with demos and scripts to generate them
+
+The `demo_*.sh` scripts in this directory demo
+various features of `jj`.
+
+The `run_scripts.sh` script can be used to:
+
+- Run them inside a standardized environment instead of the user's local
+ environment.
+- Generate SVG and PNG images for the scripts.
+
+The PNG images in the repo may be slightly older, as they take up more space in
+the repo.
+
+The SVG images have human-readable diffs, but may look different on different
+computers with different fonts installed.
+
+## Running `run_scripts.sh`
+
+This requires ImageMagick and `term-transcript-cli` to be installed. See
+`run_scripts.sh`'s error messages for some more details.
+
+One way to make all the images and check the output is:
+
+```shell
+cd demos
+./run_scripts.sh demo_*.sh |less
+```
+
+### A note on fonts
+
+The exact PNG output depends on the fonts you have installed on your system.
+
+The screenshots are usually generated on a Debian Linux system and use the "Fira
+Code" font. It can be installed with `sudo apt install fonts-firacode`. It seems
+to include all relevant Unicode symbols and be a little bolder and thus more
+readable than the "Liberation Mono" font, which is used if Fira Code is not
+installed. That font also works OK. See the CSS font specification in
+`run_scripts.sh` for other fonts tried (especially when viewing SVGs on the
+web). If none apply, the default `monospace` font will be used.
+
+`convert -list Fonts` will list the fonts ImageMagick is aware of.
diff --git a/demos/git_compat.svg b/demos/git_compat.svg
new file mode 100644
index 0000000000..eced37bf14
--- /dev/null
+++ b/demos/git_compat.svg
@@ -0,0 +1,87 @@
+
+
diff --git a/demos/juggle_conflicts.svg b/demos/juggle_conflicts.svg
new file mode 100644
index 0000000000..1ea98f849a
--- /dev/null
+++ b/demos/juggle_conflicts.svg
@@ -0,0 +1,130 @@
+
+
+
+
+
+
+
+# We are in a repo with three commits, all
+# editing the same line:
+
+$ jj log
+@ upqsurwqjjfan@example.com2023-10-01 22:29:22.258 -07:005d13bfb2
+│ (empty)(no description set)
+◉ ltqxzzvnjjfan@example.com2023-10-01 22:29:22.258 -07:00thirdd7689062
+│ third
+◉ nrlsumvrjjfan@example.com2023-10-01 22:29:22.202 -07:00second483c2b23
+│ second
+◉ pumwmyutjjfan@example.com2023-10-01 22:29:22.147 -07:00firsteb0ec5cc
+│ first
+◉ zzzzzzzzroot()00000000
+$ jj diff -r first
+Added regular file file:
+ 1: first
+$ jj diff -r second
+Modified regular file file:
+ 1 1: firstsecond
+$ jj diff -r third
+Modified regular file file:
+ 1 1: secondthird
+
+# Let's reorder the second and third commits:
+
+$ jj rebase -s third -d first
+Rebased 2 commits
+Working copy now at: upqsurwq4d810169(conflict)(empty)(no description set)
+Parent commit : ltqxzzvn0aa4eff7third | (conflict) third
+Added 0 files, modified 1 files, removed 0 files
+$ jj rebase -s second -d third
+Rebased 1 commits
+$ jj log
+◉ nrlsumvrjjfan@example.com2023-10-01 22:29:22.435 -07:00seconda8e2d400
+│ second
+│ @ upqsurwqjjfan@example.com2023-10-01 22:29:22.406 -07:004d810169conflict
+├─╯ (empty)(no description set)
+◉ ltqxzzvnjjfan@example.com2023-10-01 22:29:22.406 -07:00third0aa4eff7
+│ conflict
+│ third
+◉ pumwmyutjjfan@example.com2023-10-01 22:29:22.147 -07:00firsteb0ec5cc
+│ first
+◉ zzzzzzzzroot()00000000
+
+# The commit labeled "third" has a conflict,
+# as expected. What's more interesting is
+# that the top commit has no conflict! That's
+# because it has the changes from all three
+# commits applied to it.
+
+
+# Let's verify that by looking at its contents:
+
+$ jj co second
+Working copy now at: mqslnlrve1967a3c(empty)(no description set)
+Parent commit : nrlsumvra8e2d400second | second
+Added 0 files, modified 1 files, removed 0 files
+$ cat file
+third
+
+# Let's now instead make "second" and "third"
+# sibling and merge them:
+
+$ jj rebase -s second -d first
+Rebased 2 commits
+Working copy now at: mqslnlrv72803a85(empty)(no description set)
+Parent commit : nrlsumvr4b5d0b0dsecond | second
+Added 0 files, modified 1 files, removed 0 files
+$ jj merge second third -m merged
+Working copy now at: xpkuouzp7390c074(empty) merged
+Parent commit : nrlsumvr4b5d0b0dsecond | second
+Parent commit : ltqxzzvn0aa4eff7third | (conflict) third
+Added 0 files, modified 1 files, removed 0 files
+$ jj log
+@ xpkuouzpjjfan@example.com2023-10-01 22:29:22.561 -07:007390c074
+├─╮ (empty) merged
+│ ◉ ltqxzzvnjjfan@example.com2023-10-01 22:29:22.406 -07:00third0aa4eff7
+│ │ conflict
+│ │ third
+◉ │ nrlsumvrjjfan@example.com2023-10-01 22:29:22.530 -07:00second4b5d0b0d
+├─╯ second
+◉ pumwmyutjjfan@example.com2023-10-01 22:29:22.147 -07:00firsteb0ec5cc
+│ first
+◉ zzzzzzzzroot()00000000
+
+# Again, because the merge commit has the
+# changes from all three commits, it has no
+# conflict.
+
+
+
+
diff --git a/demos/operation_log.svg b/demos/operation_log.svg
new file mode 100644
index 0000000000..f3ea2aa8c6
--- /dev/null
+++ b/demos/operation_log.svg
@@ -0,0 +1,174 @@
+
+
+
+
+
+
+
+# We are in the octocat/Hello-World repo.
+# The "operation log" shows the operations
+# so far:
+
+$ jj op log
+@ fa79b3466874jjfan@jujubenow, lasted 1 millisecond
+│ check out git remote's default branch
+│ args: jj git clone https://github.com/octocat/Hello-World
+◉ b9f3854e4c6bjjfan@jujubenow, lasted 444 milliseconds
+│ fetch from git remote into empty repo
+│ args: jj git clone https://github.com/octocat/Hello-World
+◉ 3eed56af5757jjfan@jujubenow, lasted less than a microsecond
+│ add workspace 'default'
+◉ 6f3495125bc8jjfan@jujubenow, lasted less than a microsecond
+ initialize repo
+
+# We are going to make some changes to show
+# how the operation log works. Let's add a file, set
+# a description, and rebase onto the "test" branch:
+
+$ echo stuff > new-file
+$ jj describe -m stuff
+Working copy now at: xtrplzooeb5aa286 stuff
+Parent commit : orrkosyo7fd1a60bmaster | (empty) Merge pull request #6 fr↓
+om Spaceghost/patch-1
+$ jj rebase -d test
+Rebased 1 commits
+Working copy now at: xtrplzoo8c520228 stuff
+Parent commit : kowxouwzb3cbd5bbtest | Create CONTRIBUTING.md
+Added 1 files, modified 0 files, removed 0 files
+
+# We are now going to make another change off of
+# master:
+
+$ jj co master
+Working copy now at: okqrllkp7ce6d4fb(empty)(no description set)
+Parent commit : orrkosyo7fd1a60bmaster | (empty) Merge pull request #6 fr↓
+om Spaceghost/patch-1
+Added 0 files, modified 0 files, removed 2 files
+$ jj describe -m "other stuff"
+Working copy now at: okqrllkp792d0b92(empty) other stuff
+Parent commit : orrkosyo7fd1a60bmaster | (empty) Merge pull request #6 fr↓
+om Spaceghost/patch-1
+
+# The repo now looks like this:
+
+$ jj log
+@ okqrllkpjjfan@example.com2023-10-01 22:29:23.000 -07:00792d0b92
+│ (empty) other stuff
+│ ◉ tpstlustsupport+octocat@github.com2018-05-10 12:55:19.000 -05:00
+├─╯ octocat-patch-1b1b3f972
+│ sentence case
+│ ◉ xtrplzoojjfan@example.com2023-10-01 22:29:23.000 -07:008c520228
+│ │ stuff
+│ ◉ kowxouwzoctocat@nowhere.com2014-06-10 15:22:26.000 -07:00testb3cbd5bb
+├─╯ Create CONTRIBUTING.md
+◉ orrkosyooctocat@nowhere.com2012-03-06 15:06:50.000 -08:00master7fd1a60b
+│ (empty) Merge pull request #6 from Spaceghost/patch-1
+~
+
+# The most recent portion of the operation log
+# is:
+
+$ jj op log | head
+@ 5bae9d9b6a8ajjfan@jujubenow, lasted 1 millisecond
+│ describe commit 7ce6d4fb5acb6945fd0301187a03245b49fe6b71
+│ args: jj describe -m 'other stuff'
+◉ 99a3111903ccjjfan@jujubenow, lasted 1 millisecond
+│ check out commit 7fd1a60b01f91b314f59955a4e4d4e80d8edf11d
+│ args: jj co master
+◉ 5cdf49cce8a4jjfan@jujubenow, lasted 1 millisecond
+│ rebase commit eb5aa28675c23f6664c1027aae91f13bf5e3c474 and descendants
+│ args: jj rebase -d test
+◉ 74cd4da2188djjfan@jujubenow, lasted 1 millisecond
+
+# Let's undo that rebase operation:
+
+$ jj undo 5cdf4
+
+# Note that only the rebase was undone, and the
+# subsequent "other stuff" change was not undone:
+
+$ jj log
+@ okqrllkpjjfan@example.com2023-10-01 22:29:23.000 -07:00792d0b92
+│ (empty) other stuff
+│ ◉ xtrplzoojjfan@example.com2023-10-01 22:29:23.000 -07:00eb5aa286
+├─╯ stuff
+│ ◉ tpstlustsupport+octocat@github.com2018-05-10 12:55:19.000 -05:00
+├─╯ octocat-patch-1b1b3f972
+│ sentence case
+│ ◉ kowxouwzoctocat@nowhere.com2014-06-10 15:22:26.000 -07:00testb3cbd5bb
+├─╯ Create CONTRIBUTING.md
+◉ orrkosyooctocat@nowhere.com2012-03-06 15:06:50.000 -08:00master7fd1a60b
+│ (empty) Merge pull request #6 from Spaceghost/patch-1
+~
+
+# We can also see what the repo looked like
+# after the rebase operation:
+
+$ jj --at-op 5cdf4 log
+@ xtrplzoojjfan@example.com2023-10-01 22:29:23.000 -07:008c520228
+│ stuff
+◉ kowxouwzoctocat@nowhere.com2014-06-10 15:22:26.000 -07:00testb3cbd5bb
+│ Create CONTRIBUTING.md
+│ ◉ tpstlustsupport+octocat@github.com2018-05-10 12:55:19.000 -05:00
+├─╯ octocat-patch-1b1b3f972
+│ sentence case
+◉ orrkosyooctocat@nowhere.com2012-03-06 15:06:50.000 -08:00master7fd1a60b
+│ (empty) Merge pull request #6 from Spaceghost/patch-1
+~
+
+# Let's say we instead want to go back to the
+# state of the repo right after the rebase:
+
+$ jj op restore 5cdf4
+Working copy now at: xtrplzoo8c520228 stuff
+Parent commit : kowxouwzb3cbd5bbtest | Create CONTRIBUTING.md
+Added 2 files, modified 0 files, removed 0 files
+
+# We're now back to before the "other stuff"
+# change existed:
+
+$ jj log
+@ xtrplzoojjfan@example.com2023-10-01 22:29:23.000 -07:008c520228
+│ stuff
+◉ kowxouwzoctocat@nowhere.com2014-06-10 15:22:26.000 -07:00testb3cbd5bb
+│ Create CONTRIBUTING.md
+│ ◉ tpstlustsupport+octocat@github.com2018-05-10 12:55:19.000 -05:00
+├─╯ octocat-patch-1b1b3f972
+│ sentence case
+◉ orrkosyooctocat@nowhere.com2012-03-06 15:06:50.000 -08:00master7fd1a60b
+│ (empty) Merge pull request #6 from Spaceghost/patch-1
+~
+
+
+
diff --git a/demos/resolve_conflicts.svg b/demos/resolve_conflicts.svg
new file mode 100644
index 0000000000..50d3b466fb
--- /dev/null
+++ b/demos/resolve_conflicts.svg
@@ -0,0 +1,139 @@
+
+
+
+
+
+
+
+# We are on the master branch of the
+# octocat/Hello-World repo:
+
+$ jj log -r 'all()'
+@ xkmnkqsrjjfan@example.com2023-10-01 22:29:25.000 -07:00b6aec352
+│ (empty)(no description set)
+│ ◉ tpstlustsupport+octocat@github.com2018-05-10 12:55:19.000 -05:00
+├─╯ octocat-patch-1b1b3f972
+│ sentence case
+│ ◉ kowxouwzoctocat@nowhere.com2014-06-10 15:22:26.000 -07:00testb3cbd5bb
+├─╯ Create CONTRIBUTING.md
+◉ orrkosyooctocat@nowhere.com2012-03-06 15:06:50.000 -08:00master7fd1a60b
+├─╮ (empty) Merge pull request #6 from Spaceghost/patch-1
+│ ◉ nznozkvvJohnneylee.rollins@gmail.com2011-09-13 21:42:41.000 -07:00
+├─╯ 76294131
+│ New line at end of file. --Signed off by Spaceghost
+◉ syktoqtscameron@github.com2011-01-26 11:06:08.000 -08:00553c2077
+│ first commit
+◉ zzzzzzzzroot()00000000
+
+# Let's make an edit that will conflict
+# when we rebase it:
+
+$ jj describe -m "README: say which world"
+Working copy now at: xkmnkqsr20110a7f(empty) README: say which world
+Parent commit : orrkosyo7fd1a60bmaster | (empty) Merge pull request #6 fr↓
+om Spaceghost/patch-1
+$ echo "Hello Earth!" > README
+$ jj diff
+Modified regular file README:
+ 1 1: Hello WorldEarth!
+
+# We're going to rebase it onto commit b1.
+# That commit looks like this:
+
+$ jj diff -r b1
+Modified regular file README:
+ 1 1: Hello Worldworld!
+
+# Now rebase:
+
+$ jj rebase -d b1
+Rebased 1 commits
+Working copy now at: xkmnkqsr539b71db(conflict) README: say which world
+Parent commit : tpstlustb1b3f972octocat-patch-1 | sentence case
+Added 0 files, modified 1 files, removed 0 files
+
+# Huh, that seemed to succeed. Let's take a
+# look at the repo:
+
+$ jj log -r 'all()'
+@ xkmnkqsrjjfan@example.com2023-10-01 22:29:25.000 -07:00539b71dbconflict
+│ README: say which world
+◉ tpstlustsupport+octocat@github.com2018-05-10 12:55:19.000 -05:00
+│ octocat-patch-1b1b3f972
+│ sentence case
+│ ◉ kowxouwzoctocat@nowhere.com2014-06-10 15:22:26.000 -07:00testb3cbd5bb
+├─╯ Create CONTRIBUTING.md
+◉ orrkosyooctocat@nowhere.com2012-03-06 15:06:50.000 -08:00master7fd1a60b
+├─╮ (empty) Merge pull request #6 from Spaceghost/patch-1
+│ ◉ nznozkvvJohnneylee.rollins@gmail.com2011-09-13 21:42:41.000 -07:00
+├─╯ 76294131
+│ New line at end of file. --Signed off by Spaceghost
+◉ syktoqtscameron@github.com2011-01-26 11:06:08.000 -08:00553c2077
+│ first commit
+◉ zzzzzzzzroot()00000000
+$ jj status
+Working copy changes:
+M README
+There are unresolved conflicts at these paths:
+README 2-sided conflict
+Working copy : xkmnkqsr539b71db(conflict) README: say which world
+Parent commit: tpstlustb1b3f972octocat-patch-1 | sentence case
+
+# As you can see, the rebased commit has a
+# conflict. The file in the working copy looks
+# like this:
+
+$ cat README
+<<<<<<<
+%%%%%%%
+-Hello World!
++Hello world!
++++++++
+Hello Earth!
+>>>>>>>
+
+# Now we will resolve the conflict:
+
+$ echo "Hello earth!" > README
+
+# The status command no longer reports it:
+
+$ jj status
+Working copy changes:
+M README
+Working copy : xkmnkqsrb1c13c23 README: say which world
+Parent commit: tpstlustb1b3f972octocat-patch-1 | sentence case
+
+
+
diff --git a/demos/run_scripts.sh b/demos/run_scripts.sh
index c70ce9399a..1f5d0926a6 100755
--- a/demos/run_scripts.sh
+++ b/demos/run_scripts.sh
@@ -44,8 +44,12 @@ run_script_through_term_transcript_and_pipe_result_to_stderr() {
tee "$outfile"
term-transcript capture \
--no-inputs --pure-svg --palette powershell \
- --out "$script_base".svg "$script_base" \
- < "$outfile"
+ --font "Fira Code, Liberation Mono, SFMono-Regular, Consolas, Menlo" \
+ --out "$script_base".svg "$script_base" < "$outfile"
+ # The default font choice term-transcript would make is:
+ # SFMono-Regular, Consolas, Liberation Mono, Menlo
+ # We add the fonts that were checked and seem to contain all the relevant
+ # unicode in front.
rm "$outfile"
}
diff --git a/demos/working_copy.svg b/demos/working_copy.svg
new file mode 100644
index 0000000000..9b0d36b3e1
--- /dev/null
+++ b/demos/working_copy.svg
@@ -0,0 +1,166 @@
+
+
+
+
+
+
+
+# We are in the octocat/Hello-World repo.
+# We have an empty working copy on top of master:
+
+$ jj status
+The working copy is clean
+Working copy : mxqlopuw8d0e7e7c(empty)(no description set)
+Parent commit: orrkosyo7fd1a60bmaster | (empty) Merge pull request #6 from Spa↓
+ceghost/patch-1
+$ jj log
+@ mxqlopuwjjfan@example.com2023-10-01 22:29:26.000 -07:008d0e7e7c
+│ (empty)(no description set)
+│ ◉ tpstlustsupport+octocat@github.com2018-05-10 12:55:19.000 -05:00
+├─╯ octocat-patch-1b1b3f972
+│ sentence case
+│ ◉ kowxouwzoctocat@nowhere.com2014-06-10 15:22:26.000 -07:00testb3cbd5bb
+├─╯ Create CONTRIBUTING.md
+◉ orrkosyooctocat@nowhere.com2012-03-06 15:06:50.000 -08:00master7fd1a60b
+│ (empty) Merge pull request #6 from Spaceghost/patch-1
+~
+
+# Now make some changes in the working copy:
+
+$ echo "Goodbye World!" > README
+$ echo stuff > new-file
+
+# Our working copy's commit ID changed
+# because we made changes:
+
+$ jj status
+Working copy changes:
+M README
+A new-file
+Working copy : mxqlopuwb580fc4d(no description set)
+Parent commit: orrkosyo7fd1a60bmaster | (empty) Merge pull request #6 from Spa↓
+ceghost/patch-1
+$ jj log
+@ mxqlopuwjjfan@example.com2023-10-01 22:29:27.000 -07:00b580fc4d
+│ (no description set)
+│ ◉ tpstlustsupport+octocat@github.com2018-05-10 12:55:19.000 -05:00
+├─╯ octocat-patch-1b1b3f972
+│ sentence case
+│ ◉ kowxouwzoctocat@nowhere.com2014-06-10 15:22:26.000 -07:00testb3cbd5bb
+├─╯ Create CONTRIBUTING.md
+◉ orrkosyooctocat@nowhere.com2012-03-06 15:06:50.000 -08:00master7fd1a60b
+│ (empty) Merge pull request #6 from Spaceghost/patch-1
+~
+
+# Add a branch so we can easily refer to this
+# commit:
+
+$ jj branch create goodbye
+$ jj log
+@ mxqlopuwjjfan@example.com2023-10-01 22:29:27.000 -07:00goodbyeb580fc4d
+│ (no description set)
+│ ◉ tpstlustsupport+octocat@github.com2018-05-10 12:55:19.000 -05:00
+├─╯ octocat-patch-1b1b3f972
+│ sentence case
+│ ◉ kowxouwzoctocat@nowhere.com2014-06-10 15:22:26.000 -07:00testb3cbd5bb
+├─╯ Create CONTRIBUTING.md
+◉ orrkosyooctocat@nowhere.com2012-03-06 15:06:50.000 -08:00master7fd1a60b
+│ (empty) Merge pull request #6 from Spaceghost/patch-1
+~
+
+# Start working on a new change off of master:
+
+$ jj co master
+Working copy now at: quqqqrtmcb2e4d75(empty)(no description set)
+Parent commit : orrkosyo7fd1a60bmaster | (empty) Merge pull request #6 fr↓
+om Spaceghost/patch-1
+Added 0 files, modified 1 files, removed 1 files
+$ jj log
+@ quqqqrtmjjfan@example.com2023-10-01 22:29:27.000 -07:00cb2e4d75
+│ (empty)(no description set)
+│ ◉ mxqlopuwjjfan@example.com2023-10-01 22:29:27.000 -07:00goodbyeb580fc4d
+├─╯ (no description set)
+│ ◉ tpstlustsupport+octocat@github.com2018-05-10 12:55:19.000 -05:00
+├─╯ octocat-patch-1b1b3f972
+│ sentence case
+│ ◉ kowxouwzoctocat@nowhere.com2014-06-10 15:22:26.000 -07:00testb3cbd5bb
+├─╯ Create CONTRIBUTING.md
+◉ orrkosyooctocat@nowhere.com2012-03-06 15:06:50.000 -08:00master7fd1a60b
+│ (empty) Merge pull request #6 from Spaceghost/patch-1
+~
+
+# Note that the working copy is now clean; the
+# "goodbye" change stayed in its own commit:
+
+$ jj status
+The working copy is clean
+Working copy : quqqqrtmcb2e4d75(empty)(no description set)
+Parent commit: orrkosyo7fd1a60bmaster | (empty) Merge pull request #6 from Spa↓
+ceghost/patch-1
+
+# Modify a file in this new change:
+
+$ echo "Hello everyone!" > README
+
+# The working copy is not special; we can, for
+# example, set the description of any commit.
+# First, set it on the working copy:
+
+$ jj describe -m everyone
+Working copy now at: quqqqrtm50e8e102 everyone
+Parent commit : orrkosyo7fd1a60bmaster | (empty) Merge pull request #6 fr↓
+om Spaceghost/patch-1
+
+# Now set it on the change we worked on before:
+
+$ jj describe goodbye -m goodbye
+
+# Inspect the result:
+
+$ jj log
+◉ mxqlopuwjjfan@example.com2023-10-01 22:29:27.000 -07:00goodbyeb19dd123
+│ goodbye
+│ @ quqqqrtmjjfan@example.com2023-10-01 22:29:27.000 -07:0050e8e102
+├─╯ everyone
+│ ◉ tpstlustsupport+octocat@github.com2018-05-10 12:55:19.000 -05:00
+├─╯ octocat-patch-1b1b3f972
+│ sentence case
+│ ◉ kowxouwzoctocat@nowhere.com2014-06-10 15:22:26.000 -07:00testb3cbd5bb
+├─╯ Create CONTRIBUTING.md
+◉ orrkosyooctocat@nowhere.com2012-03-06 15:06:50.000 -08:00master7fd1a60b
+│ (empty) Merge pull request #6 from Spaceghost/patch-1
+~
+
+
+