Novelr

approved

by william-saxton

Long-form writing with user-defined structure (novel, chapter, scene, or anything you like) and a type-aware compile pipeline. - This plugin has not been manually reviewed by Obsidian staff.

22 downloadsUpdated 2d agoApache-2.0

Novelr

Long-form writing in Obsidian with a structure you define and a compile pipeline that understands it.

Novelr is inspired by Longform and novelWriter. Where Longform gives you a flat list of scenes, Novelr lets you decide the shape of your project: a novel made of chapters made of scenes, a novel with parts, a screenplay with acts and sequences, or anything else. Containers are real folders and content nodes are real notes, so your vault stays plain Markdown that any other tool can read.

Installation

Requires Obsidian 1.13 or newer.

  • Community plugins: search for "Novelr" in Settings › Community plugins once it is listed.
  • Manual: download main.js, manifest.json and styles.css from the latest release into <vault>/.obsidian/plugins/novelr/, then enable the plugin.
  • BRAT: add william-saxton/novlr in the BRAT plugin to follow releases before the directory listing.

Concepts

  • Node type: either a container (a folder with a title, holding other nodes) or content (a note with a title and a body). Each container type can restrict which types it accepts.
  • Schema: the list of node types for a project plus the root type. The default preset is Novel › Chapter › Scene. Presets ship for "Novel with parts" and "Short story", and you can save your own.
  • Project: a folder with an index note (default name novelr.md) whose novelr property holds the title, schema, ordered tree, and compile settings. Order lives in the index, so reordering never renames files.
  • Workflow: a list of compile steps. Workflows are shared across the vault and each project picks one.

Getting started

  1. Enable the plugin and run Novelr: Create new project (or click the plus in the pane).
  2. Pick a title, a location, and a structure preset. Novelr creates the folder and the index note.
  3. Open the structure pane (ribbon icon or Novelr: Open structure pane). Add chapters and scenes, drag to reorder or move between chapters, right-click for more.
  4. Switch to the Compile tab, pick a workflow, and press Compile.

Notes that already exist in the project folder but are not in the index appear under Needs attention; add them with one click or ignore them with a glob pattern.

The index note

---
novelr:
  version: 1
  title: The Hollow Road
  workflow: Manuscript (default)
  ignore:
    - _notes/**
  schema:
    rootType: novel
    types:
      - id: novel
        name: Novel
        kind: container
        allowedChildren: [chapter]
      - id: chapter
        name: Chapter
        kind: container
        allowedChildren: [scene]
      - id: scene
        name: Scene
        kind: content
  tree:
    - chapter: Chapter One
      children:
        - scene: Opening
        - scene: The Call
    - chapter: Chapter Two
      children:
        - scene: Aftermath
---

Each tree entry is <typeId>: <name>, optionally with children. Paths are derived from the tree: Chapter One/Opening.md is a scene inside the Chapter One folder. You can edit this by hand; Novelr tolerates mistakes and reports them in the pane.

Content notes get a novelr-type property when Novelr creates them, so Dataview and friends can query by type. Add novelr-skip: true to a note to leave it out of every compile.

Statuses

Every node can carry a status such as New, In progress or Done. Statuses are defined per project in the Project tab and each one has:

  • a color shown as a dot next to the node,
  • an optional parent status that it pushes onto the node containing it,
  • a default flag for newly created nodes.

Pushing works all the way up. With the defaults, a chapter marked Done that gains a New scene shows In progress (hollow dot, tooltip says why), and so does the novel above it. When the scene is finished, the chapter shows Done again. If several children push different statuses, the one listed first wins, so order the list from "most attention needed" down.

Colors are the eight theme accent colors or any hex value: the plus swatch opens a color picker, and custom colors are kept in a vault-wide palette (right-click a custom swatch to edit or remove it).

Click a node's dot, right-click and choose Set status…, or run Novelr: Set status of current node. Content notes also get a novelr-status property when "Write node type and status to files" is on.

novelr:
  statuses:
    - { id: new, name: New, color: blue, parent: in-progress, default: true }
    - { id: in-progress, name: In progress, color: yellow, parent: in-progress }
    - { id: done, name: Done, color: green }
  tree:
    - chapter: Chapter One
      status: done
      children:
        - scene: Opening
          status: new

Compile

A workflow is a sequence of steps of four kinds:

KindWhat it seesBuilt-in steps
Nodeevery node whose type matches the step's Apply to list (empty = all)Strip frontmatter, Remove links, Remove comments, Remove strikethroughs, Remove headings, Insert before, Insert after, Find and replace, Trim whitespace
Structurethe whole tree, before it is builtFilter by status
Buildthe whole tree, onceBuild manuscript
Manuscriptthe flattened textNormalize blank lines, Find and replace, Add frontmatter, Save as note

Node and structure steps come first, then one build step, then manuscript steps. Filter by status leaves out nodes with chosen statuses (a container's effective status counts, so a whole In progress chapter can be dropped) or keeps only content with chosen statuses, and renumbers what remains. Insert before and Insert after attach text to nodes of a given type, which is how you get chapter headings, part pages or scene separators:

  • Chapter headings: Insert before on chapter with # Chapter {number}: {title}
  • Scene separators: Insert before on scene with * * * and Skip the first on
  • Part pages: Insert before on part with {PB}# Part {number:Roman}{BR}{BR}## {title}

Placeholders

PlaceholderMeaning
{title} {type} {status} {status.id}the node's name, type id, effective status name and id
{number}position among siblings of the same type (1-based)
{count} {index} {absolute} {depth}siblings of this type, 0-based position among all siblings, position of this type across the whole project, nesting depth
{number:word} {number:Word} {number:WORD} {number:roman} {number:Roman} {number:pad2}number formatting (works on any numeric placeholder)
{parent.title} {parent.number}the containing node
{chapter.title} {chapter.number}the nearest ancestor of that type (any type id works)
{project.title} {date}project title, today's date
{BR} {PB}line break, page break (configurable in settings)
----as the whole value, a horizontal rule

Steps from other plugins

Novelr does not load or evaluate script files. Other plugins (including a small personal one) can register compile steps through the public API instead:

// In another plugin, after Novelr has loaded:
const novelr = this.app.plugins.plugins["novelr"];
novelr?.api.registerStep({
  description: {
    canonicalID: "my-plugin:shout",   // prefix with your plugin id
    name: "Shout",
    description: "Uppercases every targeted node.",
    kind: "node",                     // "node" | "tree" | "join" | "manuscript"
    external: true,
    options: [{ id: "suffix", name: "Suffix", description: "", type: "text", default: "!" }],
  },
  compile(node, ctx) {
    if (node.kind === "content") node.text = node.text.toUpperCase() + String(ctx.options.suffix);
  },
});
// and in onunload: novelr?.api.unregisterStep("my-plugin:shout");

Registered steps appear under "From other plugins" in the workflow editor. Node steps receive (node, ctx) and mutate node.text, node.before or node.after. Tree steps receive (root, ctx) and may prune or reorder children. Build steps receive (root, ctx) and return a string. Manuscript steps receive (text, ctx) and return a string. ctx.format(fmt, node) expands placeholders and ctx.app is the Obsidian app.

What Novelr touches

  • On startup it checks the cached frontmatter of every Markdown note once to find index notes (the ones with a novelr property). It does not read file contents to do this.
  • It only reads and writes notes inside project folders: the index note, content nodes, and the manuscript written by a compile step.
  • It never runs code from your vault and never touches the clipboard or the network.

Commands

  • Open structure pane
  • Create new project
  • Compile current project
  • Open project index note
  • Open next / previous content node
  • Reveal active file in structure pane
  • New node in current container
  • Set status of current node

Development

npm install
npm run dev     # rebuilds on change and copies into test-vault/.obsidian/plugins/novelr when that folder exists
npm test
npm run lint
npm run build

License

Apache-2.0

For plugin developers

Search results and similarity scores are powered by semantic analysis of your plugin's README. If your plugin isn't appearing for searches you'd expect, try updating your README to clearly describe your plugin's purpose, features, and use cases.