> For the complete documentation index, see [llms.txt](https://ascribed-dev.com/docs/llms.txt). This documentation describes Ascribe 0.4.4. Anything marked in main, not yet released isn't in that release yet.

# Content that varies

> Tutorial · Writing one page for readers on different platforms or products, with alternatives, availability, and a build for each audience.

Some of a page is the same for every reader, and some isn't: the install command differs by platform, and a section applies to some platforms and not others. Ascribe keeps it all in one page, and lets each output decide what its readers get. This guide adds a section that differs by platform to an install page, marks one that doesn't apply everywhere, and builds the page twice: once for the site, with every platform, and once for Windows readers alone.

It takes four parts:

- a **[dimension](https://ascribed-dev.com/docs/glossary.md#dimension)**, in `ascribe.toml`: what content varies by, such as the platform;
- a **variant group**, in the page: the alternatives, one for each value;
- an **[availability](https://ascribed-dev.com/docs/glossary.md#availability) mark**, in the page: where a section applies;
- **builds**, in `ascribe.toml`: what each output keeps.

The example is the project in [`examples/platforms`](https://github.com/ascribed-dev/ascribe/tree/main/examples/platforms), and every example below is taken from it. It's for a reader who has a project already, as [Getting started](https://ascribed-dev.com/docs/getting-started.md) sets one up, and hasn't yet written a page that differs by reader.

## 1\. Declare a dimension

A dimension is an axis your content varies along, with the values it takes. Declare it in `ascribe.toml`:

```toml
[dimensions.platform]
label = "Platform"
values = ["linux", "macos", "windows"]
labels = { linux = "Linux", macos = "macOS", windows = "Windows" }
versionless = ["linux", "macos", "windows"]
```

Tested with ascribe 0.4.4 on Linux.

- `values` are what a page names in its alternatives and availability marks, in the order the site shows them.
- `labels` and `label` are what readers see: a tab reads **macOS**, not `macos`.
- `versionless` says the platforms have no versions of their own, so a mark names a platform and nothing more. A product whose releases matter leaves it out, and marks content with the version it arrived in, such as `self-managed 3.3`. See [availability specs](https://ascribed-dev.com/docs/writing/directives.md#availability-specs).

See [`[dimensions.<name>]`](https://ascribed-dev.com/docs/content-model/variation.md#11-dimensionsname) for every key.

## 2\. Write the page

````markdown
---
title: Install Lantern
---

## Install the CLI

@variant {platform=linux}:
```sh
curl -fsSL https://lantern.example.com/install.sh | sh
```
@variant {platform=macos}:
```sh
brew install lantern
```
@variant {platform=windows}:
```powershell
winget install Lantern.CLI
```
@end

## Start it at login
@available: linux, macos

`lantern service install` starts Lantern when you log in, and keeps it running in the background.

## Sign in

Run `lantern login` and follow the link it prints.
````

Tested with ascribe 0.4.4 on Linux.

**The variant group** is the three `@variant` arms under "Install the CLI". Each arm opens with the value it's for, and its content runs to the next arm; one `@end` closes the group. An arm can hold anything a page can: paragraphs, lists, notes, more code. An arm can be for several values (`{platform=linux|macos}`), and a group doesn't need an arm for every value, though `ascribe check` warns when a build would leave a group with no arm at all. See [`@variant`](https://ascribed-dev.com/docs/writing/directives.md#variant).

**The availability mark** is `@available: linux, macos` under "Start it at login". Directly under a heading, it applies to the whole section; anywhere else, to the block it touches. Unlike a variant, it doesn't choose between alternatives: it says where the content applies, and every reader of a build that keeps it sees the mark. See [`@available`](https://ascribed-dev.com/docs/writing/directives.md#available).

"Sign in" has neither, so it's the same everywhere.

`ascribe check` reports a value the dimension doesn't declare, an arm with neither a value nor a title, and a group that isn't closed, at the line that has it. In VS Code, **Insert content that varies** and **Mark where it's available** write both for you, from the dimensions the project declares; see [Actions](https://ascribed-dev.com/docs/editor/actions.md).

## 3\. Declare the builds

A build is a named set of choices about what the output keeps. Every page goes through every build, so the source stays one page:

```toml
[builds.site]
variants = "switch"
availability = "badge"

[builds.windows]
variants = { platform = "windows" }
availability = { filter = "windows" }
```

Tested with ascribe 0.4.4 on Linux.

- **`site`** keeps every arm of the group, for readers to switch between (`variants = "switch"`), and every section, with its availability shown (`availability = "badge"`). It's what a project without builds gets.
- **`windows`** keeps the arms for Windows (`variants = { platform = "windows" }`), and removes what isn't available on Windows (`availability = { filter = "windows" }`).

A build can do one and not the other: select a platform and still badge, or keep every arm and filter for an older release. See [`[builds.<name>]`](https://ascribed-dev.com/docs/content-model/output.md#16-buildsname).

## 4\. Build it

```sh
npx ascribe build
```

Each build writes its outputs to its own folder: `.ascribe/build/site/` and `.ascribe/build/windows/`, each with the site output, plain Markdown, and JSON. To see what one build keeps of a page, without writing anything, run `ascribe resolve` with the build:

```sh
npx ascribe resolve docs/install.md --build site
```

````markdown
> For the complete documentation index, see [llms.txt](https://docs.example.com/llms.txt).

# Install Lantern

## Install the CLI

A reader sees one of the next 3 sections at a time, chosen by platform.

### Platform: Linux

```sh
curl -fsSL https://lantern.example.com/install.sh | sh
```

### Platform: macOS

```sh
brew install lantern
```

### Platform: Windows

```powershell
winget install Lantern.CLI
```

## Start it at login

Available: Linux (GA); macOS (GA)

`lantern service install` starts Lantern when you log in, and keeps it running in the background.

## Sign in

Run `lantern login` and follow the link it prints.
````

Tested with ascribe 0.4.4 on Linux.

In the Markdown, each arm is a section under a heading that names the platform, after a line saying a reader sees one of them at a time, so an agent reading the page knows they're alternatives. In the site output, the arms are tabs, one for each platform. Groups that vary by the same dimension switch together, and the reader's choice holds on every page they open next. The section's mark is a badge under its heading.

```sh
npx ascribe resolve docs/install.md --build windows
```

````markdown
> For the complete documentation index, see [llms.txt](https://docs.example.com/llms.txt).

# Install Lantern

## Install the CLI

```powershell
winget install Lantern.CLI
```

## Sign in

Run `lantern login` and follow the link it prints.
````

Tested with ascribe 0.4.4 on Linux.

The Windows build has only the Windows command, with no tabs and no label, since there's nothing to choose between. "Start it at login" is gone: it isn't available on Windows. A Windows reader sees a page written for them.

In VS Code, the preview's **Build** picker shows a page as any build has it, and the [build lens](https://ascribed-dev.com/docs/editor/preview.md#the-build-lens) dims what the build you're looking at leaves out, in the source:

![The Lantern install page in VS Code with the build lens on for the windows build: the Linux and macOS install commands and the section "Start it at login" are dimmed, a hover over the macOS command says "Left out of windows. Shows only platform=windows.", the preview beside it shows the page as the windows build has it, with only the Windows command, and the status bar shows an eye and "platforms · windows · problems: site only".](https://ascribed-dev.com/docs/_ascribe/files/images/build-lens-light.png)
![The Lantern install page in VS Code with the build lens on for the windows build: the Linux and macOS install commands and the section "Start it at login" are dimmed, a hover over the macOS command says "Left out of windows. Shows only platform=windows.", the preview beside it shows the page as the windows build has it, with only the Windows command, and the status bar shows an eye and "platforms · windows · problems: site only".](https://ascribed-dev.com/docs/_ascribe/files/images/build-lens-dark.png)

## Publishing more than one build

A site publishes one build: `ascribe({ build: "site" })` in Astro's configuration names it (see [Astro](https://ascribed-dev.com/docs/astro.md)). Another build is for another output: a second site, a PDF, or plain Markdown for a product's help panel, built from the same pages. Run `ascribe build --build windows` to build one alone.

## Summary

You declared a dimension, the platform, and wrote a page with a variant group for its install command and an availability mark on a section one platform doesn't have. Then you declared two builds and built the page for each: the site, with a tab for every platform, and one for Windows readers alone, with only what applies to them.

## Next steps

- **A whole page that differs.** When most of a page is different, write a page for each value, with `variant` in its frontmatter. A build that selects another value leaves the page out. See [whole-page variants](https://ascribed-dev.com/docs/writing/frontmatter.md#whole-page-variants).
- **Alternatives that aren't a dimension.** For a one-off choice, such as two ways to do the same thing, give each arm a title instead of a value. See [`@variant`](https://ascribed-dev.com/docs/writing/directives.md#variant).
- **A word that differs.** `@variant` varies whole blocks. For a name or a version in a sentence, use a [phrase](https://ascribed-dev.com/docs/glossary.md#phrase).
- **Versions and lifecycle.** Availability can say when content arrived and what state it's in, such as `self-managed preview 3.4`, and a feature can be named once in `[features]` so going GA is one edit. See [availability specs](https://ascribed-dev.com/docs/writing/directives.md#availability-specs), [`[lifecycle.<state>]`](https://ascribed-dev.com/docs/content-model/variation.md#13-lifecyclestate), and [`[features.<key>]`](https://ascribed-dev.com/docs/content-model/variation.md#14-featureskey).
- **A table row.** A row takes `{available=...}` at the end of its first cell. See [table rows](https://ascribed-dev.com/docs/writing/directives.md#table-rows).
