I typeset a little book :-) (and postmortem thoughts)

I’m getting into typesetting books! I’m starting by taking some shorter ones out of project gutenberg (common domain) for some practice. It also happens that I really enjoyed omats in high school! Here’s my current draft:

omats.pdf (284.8 KB)

Code
#set text(
  font: "EB Garamond",
  number-type: "old-style",
  size: 12pt,
)

#set page(
  width: 4.25in,
  height: 5.5in,
  margin: (top: 0.7in, bottom: 0.7in),
  numbering: "1",
)

#set par(
  first-line-indent: 1em,
  spacing: 0.65em,
  justify: true,
  // justification-limits: (
  //   spacing: (min: 100% * 2 / 3, max: 150%), // default
  //   tracking: (min: -0.01em, max: 0.01em), // recommended
  // ),
)

#show heading: it => {
  pagebreak(weak: true)
  set text(weight: "regular", size: 2em)

  it
  v(0.3in)
}

#set document(
  title: [The Old Man and the Sea],
  author: "Ernest Hemingway"
)

#let title-card() = {
  v(0.5in)
  set text(weight: "regular", size: 1.5em, font: "Castellar")
  set par(justify: false)
  align(title(), center)
}

#{
  // front matter
  set page(numbering: none)

  // {
  //   // half-title page, alt ver
  //   title-card()
  //   pagebreak()
  // }

  {
    // half-title page
    v(0.5in)
    align(smallcaps[the old man\ and the sea], center)
    pagebreak()
  }

  // blank
  pagebreak()

  // title page
  {
    title-card()

    image("white-marlin.gif")
    // alternatively can consider
    // https://etc.usf.edu/clipart/58100/58191/58191_seine-boat.htm
    // https://etc.usf.edu/clipart/4700/4794/fishing_boat_1.htm

    v(0.25in)
    align(center)[Ernest Hemingway]

    pagebreak()
  }

  // copyright page
  {
    set text(size: 0.7em)
    set par(
      first-line-indent: 0em,
      spacing: 2em,
    )

    let section(body) = par(body, hanging-indent: 1.5em)

    [
      _The Old Man and the Sea_\
      Ernest Hemingway\

      A work in the public domain, well, in Canada apparently. 

      // First published 1952\
      #section[
        Edition:\ 
        New York: Charles Scribner's Sons, 1952\ 
        Sourced from Project Gutenberg at\ 
        #link("https://gutenberg.ca/ebooks/hemingwaye-oldmanandthesea/")\
      ]

      #smallcaps[isbn-10]: 0-684-16326-8\
      #smallcaps[isbn-13]: 978-0-684-16326-0\

      Marlin  clipart from #link("https://etc.usf.edu/clipart/188300/188316")

      #section[
        Book design by saffronner\
        Body text in EB Garamond\
        Title in Castellar
      ]

      #pagebreak()
    ]
  }

  // blank
  pagebreak()

  // blank
  pagebreak()

  // dedication page + blank
  // table of contents
  [
    // foreword
    = Foreword
    I read this book in high school. I thought it was really good, so I wanted to typeset and so have it for myself. But what bad luck---I found while looking for clipart such an awe-inspiring marlin that I couldn't not use it.

    Unfortunately, if you somehow happen to read this book, and are not saffronner, you have been spoiled. There is a marlin. There is a sick-as-hell marlin. The first time I read this book, I did not know there would be an outstandingly awesome fish, and my experience was better for it; the rising action was all the more pronounced.

    Oh well. Anyhow, let's get on with it.

    \

    #align(right, [-- saffronner])

    #place(text(size:0.8em, fill: gray)[\ \ P.S. Erm. It appears this book is not actually public domain everywhere. So uh. Alice in Wonderland jumpscare!])
    #pagebreak()
  ]
  // preface
  // acknowledgements
  // introduction
  // abbreviations

  // blank
  pagebreak()
}

#counter(page).update(1)

#v(1in)

#include "alice-jumpscare.typ"
#pagebreak()

#set page(numbering: none)
#pagebreak()
#pagebreak()

#align(center)[
  #smallcaps[books by ernest hemingway]
  #v(0.1in)

  The Old Man and the Sea

  Across the River and into the Trees

  For Whom the Bell Tolls

  The Fifth Column and the First Forty-Nine Stories

  To Have and Have Not

  Green Hills of Africa

  Winner Take Nothing

  Death in the Afternoon

  A Farewell to Arms

  Men without Women

  The Sun Also Rises

  The Torrents of Spring

  In Our Time
]

In no particular order, I’d like to thank and mention the people at the Renegade Bookbinding Guild, memdesign authors, the Typst community, books on my shelves, etc.

process

Not necessarily in order:

  • Take the main matter source document. Regex the hell out of it to mold it into a Typst document. I wrote and use a CLI tool with a DSL at https://github.com/wade-cheng/regexer.
  • Write front and back matter.
  • #include main matter.
  • Write styling.

design notes (nonexhaustive)

The page size is quarter-letter. This is because physical books are best folded along the paper grain, and printer paper (most paper) is manufactured grain-long. That is, by taking a letter sized paper and cutting it in half, folding that half-sheet is along the grain.

Also, there weren’t enough pages to make the book an interesting thickness if it were half-letter.

postmortem

It was interesting setting a book, because it feels like there’s no really good way to wrap much of the styling into a library the way we usually do. That is, via a function that we call with show template.with(...): Such a function would basically need to re-wrap every parameter in par, text, and so on, just in case the author would need to use it. I wonder how Latex’s memoir does it…

On the topic of library API design, I recall a thread somewhere around here about separating styling and content into different functions. Couldn’t find it, but the interesting problem people noted was that the current pattern show template.with(abstract: [...]) leads to difficulty in changing the styling of that abstract.[1] So, show template; set text(size:1.2em); abstract[...] could be easier.

If I were to write a package for making books, or some other content-focused package, I’d probably follow this idiom. There could be functions for “spawning” individual specialized pages at a time or something, maybe… A separate function for the title page, half title page, etc etc.


  1. I believe there is some design work under way regarding this? ↩︎

6 Likes

Nice work!

Could you give a couple of concrete examples to show what the problem is?