fuzzyworld

auto-print / files / README.md

README.md

11.7 KB · history · blame

auto-print

Turns markdown manuscripts into books: an epub, a docx, a pdf and a Kindle kpf for each one.

It is made for writers who keep their drafts in markdown, next to their notes. A manuscript file can hold a spelling list, character notes and cut scenes. auto-print publishes only the story, plus the extra pages you name, such as a dedication or a character guide.

Why it exists

auto-print was developed to create books out of Pavel Safronov's upcoming writing.

Requirements

If a tool is missing, only the formats that need it fail. The other files are still written.

Install

Install the auto-print command from GitLab:

npm install --global git+https://gitlab.com/PavelSafronov/auto-print.git

Or run it from a clone, with nothing installed. Node runs the TypeScript source directly:

git clone https://gitlab.com/PavelSafronov/auto-print.git
node auto-print/src/cli.ts --config path/to/books.json

Usage

auto-print                          # build every book in ./books.json
auto-print my-novel                 # build only the named book(s)
auto-print --config books/books.json
auto-print --list                   # list the books, build nothing

The epub, docx and pdf take a few seconds in total. The kpf takes about 20 seconds per book. Each run overwrites the previous output files.

The config file

{
  "outDir": "out",
  "defaults": {
    "author": "Your Name",
    "formats": ["epub", "docx", "pdf", "kpf"]
  },
  "books": [
    {
      "slug": "my-novel",
      "title": "My Novel",
      "source": "drafts/my-novel.md",
      "cover": "covers/my-novel.jpg"
    }
  ]
}

Every path in the config file is relative to the folder of the config file. The files of each book are written to <outDir>/<slug>/, for example out/my-novel/my-novel.epub.

Top-level field Required Meaning
books yes The list of books.
defaults no Settings for every book. A book's own setting wins over the default.
outDir no Output folder. Default "auto-print-out".
Book field Required Meaning
slug yes Name of the output folder and files. Use lowercase words joined by dashes.
title yes Book title, used on the cover, the title page and in the file metadata.
source yes The markdown file. Its story section can link to other files, see "Collections of stories".
author yes In the book or in defaults.
cover no Cover image for the epub and kpf. Without it, a text cover is generated: title, "by", author.
section no Heading that holds the story. Default "Writing". Use null to take the whole file.
language no Default "en-US".
formats no Default ["epub", "docx", "pdf", "kpf"]. List fewer to skip some.
chapterBreaks no epub and kpf only. Default false. See "Chapter breaks in the epub".
front no Headings whose sections become pages before the story. See "Extra pages".
back no Headings whose sections become pages after the story. See "Extra pages".

What happens to a manuscript

  1. auto-print finds the heading named Writing (or the section you set). Any heading level, any letter case. If the name is used at several levels, the shallowest heading wins.
  2. It takes everything under that heading, up to the next heading of the same or a higher level. Everything else in the file, such as notes or removed scenes, is left out.
  3. It removes HTML comments, such as a blog's <!--more--> marker.
  4. It promotes the headings, so the story's top headings become chapters. If the story's chapters are ### headings, they become level 1.
  5. Text before the first chapter heading, such as a content warning, is kept as an opening section.
  6. Images are found relative to the file they are written in, so ![map](./map.jpg) works.

A manuscript might look like this:

# My Novel

## Notes

Things only the author should see.

## Writing

[Content warning: peril.]

### Chapter One

#### The morning

The hero woke up.

## Removed writing

A scene that was cut.

Collections of stories

A book can be a collection of stories that each live in their own file. The book's source is then an index file, and its Writing section holds only links to the story files, one per line:

## Writing

[The first story](./story-1.md)

[The second story](./story-2.md)

<!-- [The third story](./story-3.md) -->

Each story file is handled with the rules in "What happens to a manuscript", with one difference: the text before a story's first heading, such as its content warning, is moved to just below that heading. Without this move, a story's content warning would appear at the end of the previous story.

Extra pages

Pages such as a dedication, a content warnings page, a character guide or a map are sections in the book's source file. The front and back lists name the headings of those sections, in the order they appear in the book.

{
  "slug": "my-collection",
  "title": "My Collection",
  "source": "my-collection.md",
  "front": ["Dedication", "Content Warnings"],
  "back": ["Characters", "Map"]
}
## Dedication

To my city.

## Characters

### The hero

The one the stories are about.

## Map

![Map of the city](./map.jpg)

Only the listed sections are published. Other sections, such as notes, stay private.

Chapter breaks in the epub

The chapterBreaks setting controls how the chapters appear in the epub and the kpf.

In both cases the chapters are listed in the table of contents. The docx and the pdf always flow continuously.

Sentences on separate lines

A manuscript can put each sentence on its own line, or write each paragraph as one long line. Both styles produce the same book.

This works because auto-print reads the files as GitHub-flavored markdown (gfm), where a single line break is not a real line break.

A line can be read as markdown formatting by mistake. Avoid these at the start or end of a line:

In the manuscript What happens
A line that starts with -, *, + or 1. It starts a list and ends the paragraph. Other numbers, such as 2., are safe.
A line of only --- or ===, directly after a text line The line above it becomes a heading.
A line that starts with # and a space It becomes a heading.
A line that starts with > It becomes a block quote.
A line that starts with ::: It starts or ends a styled block.
Two spaces, or a \, at the end of a line A real line break is kept inside the paragraph.
{.word}, {#word} or {key=value} at the end of a heading, or right after an image or link It is read as a setting and not shown. Other braces, like {quietly}, are shown as written.

A dash such as — at the start of a line is safe.

How each format is made

Development

npm install          # TypeScript and Node's type definitions, for the checks below
npm test             # unit tests, plus pandoc tests that are skipped when pandoc is missing
npm run typecheck
npm run build        # compiles src/ to dist/, which the installed command runs

The code has no runtime dependencies. decisions.md records why it works the way it does.

assets/reference.docx is made by scripts/make-reference-docx.sh. Run it again to change the Word styles.

License

MIT

Source
1# auto-print
2
3Turns markdown manuscripts into books: an epub, a docx, a pdf and a Kindle kpf for each one.
4
5It is made for writers who keep their drafts in markdown, next to their notes.
6A manuscript file can hold a spelling list, character notes and cut scenes. auto-print publishes only the story,
7plus the extra pages you name, such as a dedication or a character guide.
8
9- The source files are never changed.
10- One config file lists the books. One command builds all of them.
11- Under the hood, [pandoc](https://pandoc.org) does the conversion. A Chromium-based browser prints the pdf, and Amazon's Kindle Previewer makes the kpf.
12
13## Why it exists
14
15auto-print was developed to create books out of Pavel Safronov's upcoming writing.
16
17- Upcoming writing: [blog.fuzzyworld.net/upcoming](https://blog.fuzzyworld.net/upcoming/)
18- All writing: [blog.fuzzyworld.net](https://blog.fuzzyworld.net)
19
20## Requirements
21
22- **Node 22.18 or newer.**
23- **pandoc 3.** It converts the markdown to epub, docx and html. Tested with pandoc 3.6.1. macOS: `brew install pandoc`.
24- **Google Chrome**, or Chromium, Edge or Brave, for the pdf and for generated covers.
25 Set the `CHROME_PATH` environment variable to use a browser in a non-standard location.
26- **Kindle Previewer 4**, only for the kpf. macOS: `brew install --cask kindle-previewer`.
27 Set the `KINDLE_PREVIEWER_PATH` environment variable to use a copy in a non-standard location.
28
29If a tool is missing, only the formats that need it fail. The other files are still written.
30
31## Install
32
33Install the `auto-print` command from GitLab:
34
35```sh
36npm install --global git+https://gitlab.com/PavelSafronov/auto-print.git
37```
38
39Or run it from a clone, with nothing installed. Node runs the TypeScript source directly:
40
41```sh
42git clone https://gitlab.com/PavelSafronov/auto-print.git
43node auto-print/src/cli.ts --config path/to/books.json
44```
45
46## Usage
47
48```sh
49auto-print # build every book in ./books.json
50auto-print my-novel # build only the named book(s)
51auto-print --config books/books.json
52auto-print --list # list the books, build nothing
53```
54
55The epub, docx and pdf take a few seconds in total. The kpf takes about 20 seconds per book.
56Each run overwrites the previous output files.
57
58## The config file
59
60```json
61{
62 "outDir": "out",
63 "defaults": {
64 "author": "Your Name",
65 "formats": ["epub", "docx", "pdf", "kpf"]
66 },
67 "books": [
68 {
69 "slug": "my-novel",
70 "title": "My Novel",
71 "source": "drafts/my-novel.md",
72 "cover": "covers/my-novel.jpg"
73 }
74 ]
75}
76```
77
78Every path in the config file is relative to the folder of the config file.
79The files of each book are written to `<outDir>/<slug>/`, for example `out/my-novel/my-novel.epub`.
80
81| Top-level field | Required | Meaning |
82| --------------- | -------- | -------------------------------------------------------------------- |
83| `books` | yes | The list of books. |
84| `defaults` | no | Settings for every book. A book's own setting wins over the default. |
85| `outDir` | no | Output folder. Default `"auto-print-out"`. |
86
87| Book field | Required | Meaning |
88| --------------- | -------- | ----------------------------------------------------------------------------------------- |
89| `slug` | yes | Name of the output folder and files. Use lowercase words joined by dashes. |
90| `title` | yes | Book title, used on the cover, the title page and in the file metadata. |
91| `source` | yes | The markdown file. Its story section can link to other files, see "Collections of stories". |
92| `author` | yes | In the book or in `defaults`. |
93| `cover` | no | Cover image for the epub and kpf. Without it, a text cover is generated: title, "by", author. |
94| `section` | no | Heading that holds the story. Default `"Writing"`. Use `null` to take the whole file. |
95| `language` | no | Default `"en-US"`. |
96| `formats` | no | Default `["epub", "docx", "pdf", "kpf"]`. List fewer to skip some. |
97| `chapterBreaks` | no | epub and kpf only. Default `false`. See "Chapter breaks in the epub". |
98| `front` | no | Headings whose sections become pages before the story. See "Extra pages". |
99| `back` | no | Headings whose sections become pages after the story. See "Extra pages". |
100
101## What happens to a manuscript
102
1031. auto-print finds the heading named `Writing` (or the `section` you set). Any heading level, any letter case.
104 If the name is used at several levels, the shallowest heading wins.
1052. It takes everything under that heading, up to the next heading of the same or a higher level.
106 Everything else in the file, such as notes or removed scenes, is left out.
1073. It removes HTML comments, such as a blog's `<!--more-->` marker.
1084. It promotes the headings, so the story's top headings become chapters. If the story's chapters are `###` headings, they become level 1.
1095. Text before the first chapter heading, such as a content warning, is kept as an opening section.
1106. Images are found relative to the file they are written in, so `![map](./map.jpg)` works.
111
112A manuscript might look like this:
113
114```markdown
115# My Novel
116
117## Notes
118
119Things only the author should see.
120
121## Writing
122
123[Content warning: peril.]
124
125### Chapter One
126
127#### The morning
128
129The hero woke up.
130
131## Removed writing
132
133A scene that was cut.
134```
135
136## Collections of stories
137
138A book can be a collection of stories that each live in their own file.
139The book's `source` is then an index file, and its `Writing` section holds only links to the story files, one per line:
140
141```markdown
142## Writing
143
144[The first story](./story-1.md)
145
146[The second story](./story-2.md)
147
148<!-- [The third story](./story-3.md) -->
149```
150
151- auto-print reads the `Writing` section of each linked file, in the order of the links.
152- A link inside an HTML comment (`<!-- -->`) is left out. Use this for a story that is not ready.
153- A `Writing` section that mixes links with other text stops the build with an error.
154
155Each story file is handled with the rules in "What happens to a manuscript", with one difference:
156the text before a story's first heading, such as its content warning, is moved to just below that heading.
157Without this move, a story's content warning would appear at the end of the previous story.
158
159## Extra pages
160
161Pages such as a dedication, a content warnings page, a character guide or a map are sections in the book's source file.
162The `front` and `back` lists name the headings of those sections, in the order they appear in the book.
163
164```json
165{
166 "slug": "my-collection",
167 "title": "My Collection",
168 "source": "my-collection.md",
169 "front": ["Dedication", "Content Warnings"],
170 "back": ["Characters", "Map"]
171}
172```
173
174```markdown
175## Dedication
176
177To my city.
178
179## Characters
180
181### The hero
182
183The one the stories are about.
184
185## Map
186
187![Map of the city](./map.jpg)
188```
189
190Only the listed sections are published. Other sections, such as notes, stay private.
191
192- Headings match ignoring letter case. If a name is used at several heading levels, the shallowest heading wins.
193 So a `## Characters` page is published, and `### Characters` notes inside a `## Notes` section are not.
194- Two headings with the same name at the same level stop the build with an error. So does a listed name that is not in the file.
195- The section heading becomes the page title. Headings inside the section become sub-headings of the page.
196- Every extra page starts on a new page, in every format.
197- A section named `Dedication` has the typical look of a dedication: centered, in italics, about a third of the way down the page.
198 Its heading is not shown, and it is left out of the table of contents.
199- A section named `Copyright` is left out of the table of contents.
200- In the epub and the kpf, front pages are marked as front matter, and back pages as back matter (appendices).
201 E-readers use these marks to know where the story starts.
202
203## Chapter breaks in the epub
204
205The `chapterBreaks` setting controls how the chapters appear in the epub and the kpf.
206
207- `false` (the default): the story flows continuously. A chapter is only a heading in the text.
208- `true`: every chapter starts on a new page.
209
210In both cases the chapters are listed in the table of contents.
211The docx and the pdf always flow continuously.
212
213## Sentences on separate lines
214
215A manuscript can put each sentence on its own line, or write each paragraph as one long line.
216Both styles produce the same book.
217
218- A single line break joins the two lines with a space, inside the same paragraph.
219- A new paragraph starts only at an empty line. A line that holds only spaces also counts as empty.
220
221This works because auto-print reads the files as GitHub-flavored markdown (`gfm`), where a single line break is not a real line break.
222
223A line can be read as markdown formatting by mistake. Avoid these at the start or end of a line:
224
225| In the manuscript | What happens |
226| ---------------------------------------------------------- | ----------------------------------------------- |
227| A line that starts with `- `, `* `, `+ ` or `1. ` | It starts a list and ends the paragraph. Other numbers, such as `2. `, are safe. |
228| A line of only `---` or `===`, directly after a text line | The line above it becomes a heading. |
229| A line that starts with `#` and a space | It becomes a heading. |
230| A line that starts with `>` | It becomes a block quote. |
231| A line that starts with `:::` | It starts or ends a styled block. |
232| Two spaces, or a `\`, at the end of a line | A real line break is kept inside the paragraph. |
233| `{.word}`, `{#word}` or `{key=value}` at the end of a heading, or right after an image or link | It is read as a setting and not shown. Other braces, like `{quietly}`, are shown as written. |
234
235A dash such as `—` at the start of a line is safe.
236
237## How each format is made
238
239- **epub**: pandoc, with a table of contents built from the headings.
240 The stylesheet is pandoc's default one, plus [assets/epub.css](assets/epub.css).
241- **docx**: pandoc, with [assets/reference.docx](assets/reference.docx) as the Word template.
242 It is pandoc's default template plus a `Dedication` paragraph style. Chapters use the `Heading 1` style.
243- **pdf**: pandoc makes a standalone html page with [assets/print.css](assets/print.css), then a headless browser prints it.
244 The browser does not always exit by itself after printing, so auto-print waits for the pdf and then stops the browser.
245- **kpf**: Kindle Previewer's command line tool converts an epub into a kpf.
246 auto-print builds a fresh epub for this, so the kpf works even if `epub` is not in `formats`.
247
248## Development
249
250```sh
251npm install # TypeScript and Node's type definitions, for the checks below
252npm test # unit tests, plus pandoc tests that are skipped when pandoc is missing
253npm run typecheck
254npm run build # compiles src/ to dist/, which the installed command runs
255```
256
257The code has no runtime dependencies. [decisions.md](decisions.md) records why it works the way it does.
258
259`assets/reference.docx` is made by [scripts/make-reference-docx.sh](scripts/make-reference-docx.sh).
260Run it again to change the Word styles.
261
262## License
263
264[MIT](LICENSE)