Bob Nystrom started this. He wrote his excellent Game Programming Patterns book completely in the open. He showed us that it's possible to offer great content for free and at the same time become a fancy published author. Then he had the audacity of following it up with (possibly an even better book!) Crafting Interpreters. The nerve!
I just took the open source tooling from Bob's upstream project and started my own book, The Self-Improving Developer, which is based on my blog about intermediate software engineering topics.
You can find the site here: selfimproving.dev.
Bob's upstream project is double-licensed. It uses MIT for the tooling and CC BY-NC-ND 4.0 for the "content files" (the text files, the SCSS styling, and so on).
This project stripped all of those content files and left only
the tooling and the scaffold. If you want that, go to the
just tooling branch. That code is fully MIT-licensed.
You can start your own book.
After that commit, I started to add my own content, which is CC BY-NC-SA 4.0.
- POSIX environment
- Dart SDK installed
Run the following once.
$ make get
This downloads all the packages used by the scripts in
The Markdown and snippets of source code are woven together into the final HTML using a hand-written static site generator that started out as a single tiny Python script for my first book and somehow grew into something approximating a real program.
The generated HTML is committed in the repo under
site/. It is built from a combination of Markdown for prose, which lives in
book/, and snippets of code that are weaved in from the Java and C implementations in
c/. (All of those funny looking comments in the source code are how it knows which snippet goes where.)
The script that does all the magic is
tool/bin/build.dart. You can run that directly, or run:
$ make book
That generates the entire site in one batch. If you are incrementally working on it, you'll want to run the development server:
$ make serve
This runs a little HTTP server on localhost rooted at the
site/directory. Any time you request a page, it regenerates any files whose sources have been changed, including Markdown files, interpreter source files, templates, and assets. Just let that keep running, edit files locally, and refresh your browser to see the changes.
You specify which chapters get published and in what order by modifying
asset/– Sass files and mustache templates used to generate the site.
book/- Markdown files for the text of each chapter.
build/- Intermediate files and other build output (except for the site itself) go here. Not committed to Git.
site/– The final generated site. The contents of this directory directly mirror the output of
build.dart. Most content here is generated by this script, but fonts, images, and JS only live here. Everything is committed, even the generated content.
tool/– Dart package containing the build, test, and other scripts.
The site is deployed on Firebase Hosting.
Building web scripts
There are some scripts written in Dart that make the web reading experience a bit better. To build one, do something like this:
dart2js asset/scripts/index.dart -o site/index.dart.js -m -O4 --csp
Converting from HTML to Markdown
To convert from HTML to Markdown using
pandoc, do this:
pandoc -i some_file.html -o book/final-article-name.md
On a Mac and with some HTML in your clipboard:
pbpaste | pandoc -f html -t gfm --shift-heading-level-by=-1 -o book/final-article-name.md