An idea in a rookery is written in Typst. Every idea can be referenced by any other idea or page in the same rookery.
Each idea also gets a standalone page that will show its context—where it was first hatched—and its backlinks—the set of other ideas and pages that reference it—in its footer. Try clicking on this idea’s ID above (the [idea:idea] text), to see its standalone page as an example.
Ideas can be hyperlinked to other ideas, or they can be interpolated as windows onto the original idea. Clicking on the title of a window will unfold the idea within your current context. Clicking on the idea’s ID will take you to the idea’s standalone page.
Try unfolding these windows below by clicking on their title panel to learn more.
Ideas are designed so that you can always hatch new ones without ceremony. The #idea function at its most basic takes the content of an idea.
#import "@rookery/core:0.1.0": idea
#idea[Hatch a new idea.]By default, an idea will inherit its date from the document in which it was hatched, and will not show it explicitly. If you want to keep track of when you updated individual ideas, you can explicitly set it when hatching. You can also give it tags to associate it with other ideas.
#concept(
// if not specified, the ID will be auto-generated
<incremental-thought>,
// Link text when referenced
title: [On rookeries],
// defaults to #document.date
updated: datetime(year: 2026, month: 8, day: 16),
// Whether to show when idea is hatched
show-date: true,
// an arbitrary list of strings
tags: ("in-progress", "phd")
)[
// ...
]You can think of an idea as an evergreen note, an atomic unit of thought, or as a generalization of the Orgmode TODO. Ideas are intentially designed as very generic units of content that can cover both these encapsulations, as well as broader containers of writing such as blog posts or journal entries.
@rookery/todos provides syntactic sugar for an idea carrying a todo tag:
#import "@rookery/todos:0.1.0": todo
#todo[A todo.] // #idea(..., tags: ("todo"))You can add tags to any idea. Tags work as a lateral filter across many ideas that you can use to group windows on them, group outlines, or otherwise organize them.
#idea(
"meeting-notes",
tags: ("draft", "review"),
)[ ... ]When creating new ideas or windows, you can set show-tags: true to demonstrate
#window(
"meeting-notes",
show-tags: true,
)This will render pills next to the idea’s ID, just like you see above. The colors associated with each tag can be configured in your rookery’s theme.
You can also work backwards, getting tags from an idea:
#context tags-of("meeting-notes") // -> ("draft", "review")A footnote belongs to the idea in which you write it in, just as citations do. So that rookery can track them correctly, you need to use the footnote function imported from rookery in ideas, rather than the Typst native function:
#import "@rookery/core:0.1.0": idea, footnote
#idea("etal")[
A claim#footnote[The evidence.] worth qualifying.
]Footnote numbering is idea-local. This means that there may be two footnotes labeled 1 on the same page, if two ideas with footnotes are hatched in that context.1
Footnote listings occur at the end of each idea.2 On a standalone page, footnotes appear before the context and backlinks listings.
A footnote written outside an idea’s context proxies the native Typst function so that it behaves normally.
What you write inside a footnote belongs to the idea as well, and not to the footnote. A citation in a footnote is claimed by the surrounding idea and listed in its References,3 and a window or an @idea: reference in a footnote registers its backlink exactly as it would in the idea’s own prose.
A citation belongs to the idea in which you write it, just as footnotes do. Bibliographies, like footnotes, are produced at the end of an idea.
In contrast to footnotes, however, all citations in a rookery draw from a global bibliography that is configured once like so:
#show: rookery.with(bibliography: arguments(
bytes(read("references.bib")),
style: "chicago-author-date",
))You must use bytes(read(...)) rather than a path to pass a reference file, but rookery bibliographies otherwise work the same as Typst bibliographies.
Once a rookery is configured with a bibliography, you can cite as you naturally would in Typst (Mädje 2022). Bibliographies will appear at the bottom of every idea with a citation under a ‘References’ heading.
Citation numbering is rookery-wide, which means that numeric styles will not be scoped to each idea. (An idea with one citation may show it as [7], for example, if it is the 7th citation in the rookery.) For this reason we recommend using citation styles that don’t employ numbers such as "author-date".
You can reference an existing idea by creating either a hyperlink or a window. Both kinds of references using the idea’s ID, which is unique in a global namespace.
IDs are normal Typst labels, meaning that compilation will fail if there is a duplicate. To ensure that rookery’s labels don’t easily clash with ones you create yourself, the prefix idea: is prepended to all of your idea IDs. You can customize this prefix when you configure rookery.
Hyperlinks are the lowest-touch way to reference an idea in rookery, and are implemented as regular Typst references. Say you have an idea:
#idea("first-idea", title: [My first idea])The following three bullets all produce the same result: a hyperlink that reads ‘My first idea’ to the idea’s standalone page.
#import "@rookery/core:0.1.0": hyperlink
- @idea:first-idea
- @idea:first-idea[My first idea]
- #hyperlink(<first-idea>)[My first idea]Note that you must use the idea: prefix (which you may customize) when you are using references in the Typst namespace. When using the #hyperlink function imported from rookery, you may omit the prefix if you choose.
If you want your references to link to the anchor in the original context in which your idea was hatched, rather than the idea’s standalone page, pass link-to: "anchor" to an individual call:
- #hyperlink(<first-idea>, link-to: "anchor")[My first idea]If you want to redirect all @idea:x-style references to anchors, #hyperlink is also @idea:x’s renderer, installed as a show ref: rule — .with() it instead of the default:
#import "@rookery/core:0.1.0": hyperlink
#show ref: hyperlink.with(link-to: "anchor")
- @idea:first-idea // will link to anchor(#set hyperlink.with(...) does not work here — set rules only apply to Typst’s own built-in element functions, not a plain package function like hyperlink.)
Creating a hyperlink to an idea will add it to that idea’s set of backlinks.
Windows can be used to interpolate the entirety of an idea’s content into a different context. They are useful in home pages or other sections that aggregate content.
Fundamentally, windows are a form of augmented hyperlink. They take their name from Nelson’s notion of the transpointing window as they allow you to see the content either side of the link (like a window).
Say you have an idea:
#idea("first-idea", title: [My first idea])You can produce a window on this idea like so:
#import "@rookery/core:0.1.0": window
#window(<first-idea>)Note that we do not need the idea: prefix. Like #hyperlink,#window is a function imported from rookery that already knows which namespace to look in.
By default, this window will be unfolded, showing the full content of the idea. If we want it to instead be folded, we can configure it with arguments. We can also pass an array of ideas to window on multiple ideas:
#window(
// the ideas to window on
(<first-idea>, <second-idea>, <third-idea>),
// only show each idea's title and ID
folded: true,
// truncate each body to its first 12 blocks
limit: 12,
// how to order the matching ideas in the window
// one of "auto", "date", or "lexicographic"
sort: "date", // "auto" by default, i.e. in order of specification
// show the idea's date in the hat
show-date: true,
// and its tags, as pills
show-tags: true,
// select ideas with one of the following tags
tags: ("concept", "reference"),
// whether tags should ALL be required, or only ANY one of them
match: "all" // "any" by default
)Windows on ideas that are parents in the idea hierarchy can infinitely recurse. In order to prevent this, rookery has a notion of window depth, which is set to 1 by default.
When a window is called at a level of recursion greater than the window depth, rookery renders a call to #window as a link to the idea’s standalone page rather than as transcluded content. It’s best to think of window depth as a multiplier, as the amount of work rookery needs to do multiplies when you raise it.
You can set the window depth per window, or site-wide:
#show: rookery.with(window-depth: 1)
#window(<first-idea>)
#window(<first-idea>, depth: 2)Here is a window on this selfsame idea. Because this documentation uses the default depth of 1, it only recurses as a window once, and then bottoms out as a link: