Ludus should have a notebook or literate format #99

Open
opened 2025-07-16 22:07:58 +00:00 by scott · 3 comments
Owner

Ultimately, when we're publishing The History of Computing by Example or The History of Generative Art by Example, we'll be wanting to combine prose, code, graphics, and interaction all together.

My fantasy for this would be to have a format, e.g., .ldn, that integrates these meaningfully. A Ludus notebook format.

With djot as textual format, SVG as the graphics format, and with something on the frontend that allows for interacting with code, graphics, and text interaction.

A few different models/touchpoints/inspirations for this:

  • Jupyter notebooks are a standard format with some problems that are fairly widely recognized. Not least of which, in my opinion, is Python as a host language. (Although the fact that Ludus runs in WASM makes it more portable than it otherwise might be.)
  • mdbook is a Rust-based markdown book generation system, with good Rust integration. Perhaps this will play nice with Ludus, since Ludus is now also Rust-based.
  • ObservableHQ is a JS-based online notebook system.
  • Others include the Clojure-based Nextjournal and some additional notebook-type systems, including the open-source and academically-oriented Quarto.
  • And the state of the art in terms of humanities publishing probably includes Aesthetic Programming.
  • Racket's documentation system, Scribble.

So, a few different fantasies and goals here:

  • A single plain-text, source-controllable authoring format in which we can write the book.
  • Multiple output formats which include paginated text (PDF) and interactive systems (presumably HTML).
  • Interactive systems allow for users to write and run code, perhaps with some kind of persistence of their changes.
  • Paginated systems should include SVG graphics and pretty code, probably in colour.
  • That said, the interactive system could also be something more like a development environment, perhaps (ab)using the Language Server Protocol or a LISP-like REPL evaluator to allow using your favourite text editor to run code.

I believe that djot+mdbook gives us a really good place to start, here. There's a Rust parser for mdbook: https://github.com/hellux/jotdown. There's an mdbook plugin for djot now that uses said parser: https://github.com/dcampbell24/mdbook-djot. And, as it turns out, mdbook includes a "Rust playground" feature for runnable code, and people have hacked up other-language REPLs: https://github.com/MR-Addict/mdbook-repl.


One thought I have, in addition, is the fact that djot lets you decorate block-level elements with ids, so that you could easily (perhaps trivially) do something like this:

Here is some prose in djot.
What follows is a code block with the id `foo`:

{# foo}
```` ludus
#{:foo "bar", :baz "quux"}
````

Here's some additional prose in djot.

{# bar}
```` ludus
import "foo" as foo

assoc (foo, :baz, 42) &=> #{:foo "bar", :baz 42}
````

And, finally, more prose.

The idea being that we don't pollute toplevel bindings with bindings from other code blocks. Instead, each one gets an id which can then be referred to in an import form in another code block.

There are perhaps some titchy questions about state (what happens to sketches or boxes when code is re-run?). But this feels like a pretty good start.

My sense is that we may well wish to develop this first with Visual Modelling with Ludus.

Ultimately, when we're publishing _The History of Computing by Example_ or _The History of Generative Art by Example_, we'll be wanting to combine prose, code, graphics, and interaction all together. My fantasy for this would be to have a format, e.g., `.ldn`, that integrates these meaningfully. A Ludus notebook format. With [djot](https://djot.net/) as textual format, SVG as the graphics format, and with something on the frontend that allows for interacting with code, graphics, and text interaction. A few different models/touchpoints/inspirations for this: * Jupyter notebooks are a standard format with some problems that are fairly widely recognized. Not least of which, in my opinion, is Python as a host language. (Although the fact that Ludus runs in WASM makes it more portable than it otherwise might be.) * [mdbook](https://rust-lang.github.io/mdBook/) is a Rust-based markdown book generation system, with good Rust integration. Perhaps this will play nice with Ludus, since Ludus is now also Rust-based. * [ObservableHQ](https://observablehq.com/) is a JS-based online notebook system. * Others include the Clojure-based Nextjournal and some additional notebook-type systems, including the open-source and academically-oriented [Quarto](https://quarto.org/). * And the state of the art in terms of humanities publishing probably includes [Aesthetic Programming](https://aesthetic-programming.net/). * Racket's documentation system, [Scribble](https://download.racket-lang.org/docs/5.0.1/html/scribble/index.html). So, a few different fantasies and goals here: * A single plain-text, source-controllable authoring format in which we can write the book. * Multiple output formats which include paginated text (PDF) and interactive systems (presumably HTML). * Interactive systems allow for users to write and run code, perhaps with some kind of persistence of their changes. * Paginated systems should include SVG graphics and pretty code, probably in colour. * That said, the interactive system could also be something more like a development environment, perhaps (ab)using the Language Server Protocol or a LISP-like REPL evaluator to allow using your favourite text editor to run code. *** I believe that djot+mdbook gives us a really good place to start, here. There's a Rust parser for mdbook: https://github.com/hellux/jotdown. There's an mdbook plugin for djot now that uses said parser: https://github.com/dcampbell24/mdbook-djot. And, as it turns out, mdbook includes a "Rust playground" feature for runnable code, and people have hacked up other-language REPLs: https://github.com/MR-Addict/mdbook-repl. *** One thought I have, in addition, is the fact that djot lets you decorate block-level elements with ids, so that you could easily (perhaps trivially) do something like this: <pre> Here is some prose in djot. What follows is a code block with the id `foo`: {# foo} ```` ludus #{:foo "bar", :baz "quux"} ```` Here's some additional prose in djot. {# bar} ```` ludus import "foo" as foo assoc (foo, :baz, 42) &=> #{:foo "bar", :baz 42} ```` And, finally, more prose. </pre> The idea being that we don't pollute toplevel bindings with bindings from other code blocks. Instead, each one gets an id which can then be referred to in an `import` form in another code block. There are perhaps some titchy questions about state (what happens to sketches or `box`es when code is re-run?). But this feels like a pretty good start. My sense is that we may well wish to develop this first with _Visual Modelling with Ludus_.
scott added the
feature
design
infrastructure
labels 2025-07-16 22:07:58 +00:00
Author
Owner

It occurs to me that the thing is to develop a .ldj format, which is ludus-djot, which can then be more or less moved into anything: pandoc makes that doable. So we have a ldj -> djot -> typst -> pdf pipeline, and an ldj -> djot -> mdbook(+repl) -> website pipeline, we can build from the same text.

That, to me, suggests that what we really need, anticipating later stages in the pipeline, are ways of naming cells and ensuring that their output is in the correct modalities, e.g.:

This is some prose.

```` foo [console turtle]
print! ("hello")
fd! (100)
42
````

More prose.

```` bar [result]
import "foo" as foo

add (2, foo)
````

More prose still.

The first block, foo, would draw turtle graphics and show the stdout from the print! call.
The second block, bar, would only show the result, 44.

This would allow a reasonable pipeline: ldj files would be run, generating relevant output which is then inserted statically into djot files, which can then be inserted into any number of places.

So the first step here is to develop an ldj spec and develop the build process from ldj to djot.

The above, translating to djot, would simply desugar the first code block to:

{# foo}
{.console .turtle}
```` ludus
print! ("hello")
fd! (100)
42
````

Which is a pretty simple transformation!

As for running the code, the idea would be to develop a Rust program that would generate the console, turtle graphics, and results of the relevant programs, using imports as needed.
Each cell would run as its own script.
SVG files would be built and saved, result and console output would be inserted in some way, likely with div headings, like so (for the first example):

::: console
hello
:::

::: result
42
:::

We should probably also allow for captions, but those would probably simply be their own divs, written inline.

It occurs to me that the thing is to develop a `.ldj` format, which is ludus-djot, which can then be more or less moved into anything: pandoc makes that doable. So we have a ldj -> djot -> typst -> pdf pipeline, and an ldj -> djot -> mdbook(+repl) -> website pipeline, we can build from the same text. That, to me, suggests that what we really need, anticipating later stages in the pipeline, are ways of naming cells and ensuring that their output is in the correct modalities, e.g.: <pre> This is some prose. ```` foo [console turtle] print! ("hello") fd! (100) 42 ```` More prose. ```` bar [result] import "foo" as foo add (2, foo) ```` More prose still. </pre> The first block, `foo`, would draw turtle graphics and show the stdout from the `print!` call. The second block, `bar`, would only show the result, `44`. This would allow a reasonable pipeline: `ldj` files would be run, generating relevant output which is then inserted statically into djot files, which can then be inserted into any number of places. So the first step here is to develop an `ldj` spec and develop the build process from ldj to djot. The above, translating to djot, would simply desugar the first code block to: <pre> {# foo} {.console .turtle} ```` ludus print! ("hello") fd! (100) 42 ```` </pre> Which is a pretty simple transformation! As for running the code, the idea would be to develop a Rust program that would generate the console, turtle graphics, and results of the relevant programs, using `import`s as needed. Each cell would run as its own script. SVG files would be built and saved, result and console output would be inserted in some way, likely with div headings, like so (for the first example): ``` ::: console hello ::: ::: result 42 ::: ``` We should probably also allow for captions, but those would probably simply be their own divs, written inline.
Author
Owner
See also: https://sr.ht/~bitfehler/dmos/
Author
Owner

Oh, and pandoc and dmos use sublime text highlighting, so that's another highlighter to have to maintain: https://www.sublimetext.com/docs/syntax.html.

That means: treesitter, lezer, sublime, and highlight.js. ::headdesk::

Oh, and pandoc and dmos use sublime text highlighting, so that's another highlighter to have to maintain: https://www.sublimetext.com/docs/syntax.html. That means: treesitter, lezer, sublime, and highlight.js. ::headdesk::
Sign in to join this conversation.
No Milestone
No project
No Assignees
1 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: twc/ludus#99
No description provided.