Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/readme-chapter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@variablelab/brand": minor
---

Add the `readme.md` chapter: the rules every README follows, the structure of each kind of README, and the `docs/contributing.md` and `docs/development.md` every repository keeps. `templates/project/` now holds a README and those two docs beside the `brand/` folder. `logo.md` says which Logo a README links, and `project-brand.md` that a README's `<img>` takes a width and no height.
5 changes: 3 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ Variable Lab's brand guideline, design tokens and shared assets, the package `@v
- `skills/vlab-brand/`: the guideline, as an Agent Skill. `SKILL.md` routes each task to one chapter; `glossary.md` holds the terms.
- `tokens/tokens.json`: the only source of colors, fonts and the type scale.
- `assets/`: the Logo and the Class stamps. No Project's Sign lives here.
- `templates/project/brand/`: what a Project copies into its own `brand/` folder.
- `templates/project/`: what a new Project copies: its README, its `docs/` and its `brand/` folder.
- `docs/`: this repository's contributing and development guides, for people.
- `.github/readme/`: the images in the README. Generated.

## Rules
Expand Down Expand Up @@ -35,7 +36,7 @@ mise installs node and pnpm, locally and in CI: run `mise install`, then `pnpm i

## Releasing

- Changes to `skills/`, `tokens/`, `assets/`, `templates/`, `BRAND-USE.md` or the `exports` in `package.json` carry a changeset: run `pnpm changeset`. Changes to the README, LICENSE, this file or CI don't.
- Changes to `skills/`, `tokens/`, `assets/`, `templates/`, `BRAND-USE.md` or the `exports` in `package.json` carry a changeset: run `pnpm changeset`. Changes to the README, LICENSE, `docs/`, this file or CI don't.
- Major: a token, an export path or an asset path is removed or renamed. Minor: one is added, or a chapter. Patch: a value or a text changes.
- Merging a change with a changeset to `main` opens or updates the "chore: update versions" pull request. Merging that pull request publishes to npm through trusted publishing.
- Agents install the skill from `main` on GitHub, not from npm, so a change to `skills/` reaches them when it merges, before any release.
65 changes: 35 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<p align="center">
<img src=".github/readme/logo.svg" width="80" height="80" alt="The Logo: a green hexagon with a V">
<img src="https://raw.githubusercontent.com/withvariablelab/brand/HEAD/.github/readme/logo.svg" width="80" alt="The Logo: a green hexagon with a V">
</p>

<h1 align="center">Brand guideline</h1>
Expand All @@ -9,36 +9,32 @@
## At a glance

- **Dark, warm and flat.** One dark palette, no gradients, no shadows, square corners.
- **One Signature.** The green Logo with "Variable Land" beside it. No Project carries it.
- **One Signature.** The green Logo with "Variable Land" beside it. It signs everything Variable Lab publishes, set apart from a Project's Sign. No Project uses it as its own mark.
- **A Sign per Project.** A Project starts with its Class stamp and earns a Sign: filled rectangles in one ink.
- **Facts, in English.** Short declarative sentences a reader can check in the code.

## Palette

<!-- build:color -->
| | Token | Value | Use |
| --- | --- | --- | --- |
| <img src=".github/readme/color-ground.svg" width="48" height="24" alt=""> | `ground` | `#14120e` | Page background. |
| <img src=".github/readme/color-surface.svg" width="48" height="24" alt=""> | `surface` | `#1b1914` | Code blocks, command boxes and panels. |
| <img src=".github/readme/color-ink.svg" width="48" height="24" alt=""> | `ink` | `#f3f0e8` | Main text, Signs and Class stamps. |
| <img src=".github/readme/color-ink-muted.svg" width="48" height="24" alt=""> | `ink-muted` | `#bdb7ab` | Secondary prose, such as the paragraph under a title. |
| <img src=".github/readme/color-dim.svg" width="48" height="24" alt=""> | `dim` | `#a39e93` | Subtitles, meta, labels and secondary links. |
| <img src=".github/readme/color-rule.svg" width="48" height="24" alt=""> | `rule` | `#2e2a24` | 1px rules and borders. |
| <img src=".github/readme/color-rule-strong.svg" width="48" height="24" alt=""> | `rule-strong` | `#3a362f` | Link underlines, hover borders, selection and scrollbars. |
| <img src=".github/readme/color-logo.svg" width="48" height="24" alt=""> | `logo` | `#36d399` | The Logo, and nothing else. |
- <img src="https://raw.githubusercontent.com/withvariablelab/brand/HEAD/.github/readme/color-ground.svg" width="48" alt="" align="absmiddle">&nbsp;`ground` `#14120e`. Page background.
- <img src="https://raw.githubusercontent.com/withvariablelab/brand/HEAD/.github/readme/color-surface.svg" width="48" alt="" align="absmiddle">&nbsp;`surface` `#1b1914`. Code blocks, command boxes and panels.
- <img src="https://raw.githubusercontent.com/withvariablelab/brand/HEAD/.github/readme/color-ink.svg" width="48" alt="" align="absmiddle">&nbsp;`ink` `#f3f0e8`. Main text, Signs and Class stamps.
- <img src="https://raw.githubusercontent.com/withvariablelab/brand/HEAD/.github/readme/color-ink-muted.svg" width="48" alt="" align="absmiddle">&nbsp;`ink-muted` `#bdb7ab`. Secondary prose, such as the paragraph under a title.
- <img src="https://raw.githubusercontent.com/withvariablelab/brand/HEAD/.github/readme/color-dim.svg" width="48" alt="" align="absmiddle">&nbsp;`dim` `#a39e93`. Subtitles, meta, labels and secondary links.
- <img src="https://raw.githubusercontent.com/withvariablelab/brand/HEAD/.github/readme/color-rule.svg" width="48" alt="" align="absmiddle">&nbsp;`rule` `#2e2a24`. 1px rules and borders.
- <img src="https://raw.githubusercontent.com/withvariablelab/brand/HEAD/.github/readme/color-rule-strong.svg" width="48" alt="" align="absmiddle">&nbsp;`rule-strong` `#3a362f`. Link underlines, hover borders, selection and scrollbars.
- <img src="https://raw.githubusercontent.com/withvariablelab/brand/HEAD/.github/readme/color-logo.svg" width="48" alt="" align="absmiddle">&nbsp;`logo` `#36d399`. The Logo, and nothing else.
<!-- /build:color -->

Code is colored with soft Vesper: the roles and the peach and mint accents of [Vesper](https://github.com/raunofreiberg/vesper), on the palette's own warm neutrals.

<!-- build:syntax -->
| | Token | Value | Use |
| --- | --- | --- | --- |
| <img src=".github/readme/syntax-text.svg" width="48" height="24" alt=""> | `text` | `#f3f0e8` | Identifiers, punctuation and flags. |
| <img src=".github/readme/syntax-keyword.svg" width="48" height="24" alt=""> | `keyword` | `#a39e93` | `import`, `from`, `const`, `export`, `as` and operators; JSX attributes; a code block's file name. |
| <img src=".github/readme/syntax-function.svg" width="48" height="24" alt=""> | `function` | `#e8bf98` | Function calls and declarations; numbers, booleans, types and other `support.*` names; HTML tags and attributes; JSON keys; the first token of a shell command (`pnpm`). |
| <img src=".github/readme/syntax-string.svg" width="48" height="24" alt=""> | `string` | `#a3d9ca` | Strings, symbols and `constant.other.key`; the arguments of a shell command (`init`, package names). |
| <img src=".github/readme/syntax-comment.svg" width="48" height="24" alt=""> | `comment` | `#8a857b` | Comments; a code block's language label. |
| <img src=".github/readme/syntax-gutter.svg" width="48" height="24" alt=""> | `gutter` | `#5f5a52` | Line numbers and the `$` prompt. |
- <img src="https://raw.githubusercontent.com/withvariablelab/brand/HEAD/.github/readme/syntax-text.svg" width="48" alt="" align="absmiddle">&nbsp;`text` `#f3f0e8`. Identifiers, punctuation and flags.
- <img src="https://raw.githubusercontent.com/withvariablelab/brand/HEAD/.github/readme/syntax-keyword.svg" width="48" alt="" align="absmiddle">&nbsp;`keyword` `#a39e93`. `import`, `from`, `const`, `export`, `as` and operators; JSX attributes; a code block's file name.
- <img src="https://raw.githubusercontent.com/withvariablelab/brand/HEAD/.github/readme/syntax-function.svg" width="48" alt="" align="absmiddle">&nbsp;`function` `#e8bf98`. Function calls and declarations; numbers, booleans, types and other `support.*` names; HTML tags and attributes; JSON keys; the first token of a shell command (`pnpm`).
- <img src="https://raw.githubusercontent.com/withvariablelab/brand/HEAD/.github/readme/syntax-string.svg" width="48" alt="" align="absmiddle">&nbsp;`string` `#a3d9ca`. Strings, symbols and `constant.other.key`; the arguments of a shell command (`init`, package names).
- <img src="https://raw.githubusercontent.com/withvariablelab/brand/HEAD/.github/readme/syntax-comment.svg" width="48" alt="" align="absmiddle">&nbsp;`comment` `#8a857b`. Comments; a code block's language label.
- <img src="https://raw.githubusercontent.com/withvariablelab/brand/HEAD/.github/readme/syntax-gutter.svg" width="48" alt="" align="absmiddle">&nbsp;`gutter` `#5f5a52`. Line numbers and the `$` prompt.
<!-- /build:syntax -->

## Type
Expand All @@ -48,9 +44,9 @@ IBM Plex Sans for text and IBM Plex Mono for code, both in 400 and 500. Two weig
## Shapes

<p>
<img src=".github/readme/stamp-app.svg" width="48" height="48" alt="The App Class stamp">
<img src="https://raw.githubusercontent.com/withvariablelab/brand/HEAD/.github/readme/stamp-app.svg" width="48" alt="The App Class stamp">
&nbsp;
<img src=".github/readme/stamp-library.svg" width="48" height="48" alt="The Library Class stamp">
<img src="https://raw.githubusercontent.com/withvariablelab/brand/HEAD/.github/readme/stamp-library.svg" width="48" alt="The Library Class stamp">
</p>

The Class stamps of an App and a Library: a body on a base, and a closed frame. Each Project's Sign is drawn on the same 24×24 grid and lives in that Project's own repository, in `brand/`.
Expand All @@ -59,13 +55,14 @@ The Class stamps of an App and a Library: a body on a base, and a closed frame.

| Chapter | Covers |
| --- | --- |
| [Principles](skills/vlab-brand/principles.md) | The rules every other chapter follows. |
| [Logo](skills/vlab-brand/logo.md) | Color, the Signature, sizes and what to avoid. |
| [Color](skills/vlab-brand/color.md) | The palette, soft Vesper and contrast. |
| [Typography](skills/vlab-brand/typography.md) | Families, scale and text flow. |
| [Voice](skills/vlab-brand/voice.md) | Tone, names and how to say what a Project is. |
| [Iconography](skills/vlab-brand/iconography.md) | UI icons and shapes beside text. |
| [Project brand](skills/vlab-brand/project-brand.md) | Class stamps, how a Sign is drawn and a Project's `brand/` folder. |
| [Principles](https://github.com/withvariablelab/brand/blob/main/skills/vlab-brand/principles.md) | The rules every other chapter follows. |
| [Logo](https://github.com/withvariablelab/brand/blob/main/skills/vlab-brand/logo.md) | Color, the Signature, sizes and what to avoid. |
| [Color](https://github.com/withvariablelab/brand/blob/main/skills/vlab-brand/color.md) | The palette, soft Vesper and contrast. |
| [Typography](https://github.com/withvariablelab/brand/blob/main/skills/vlab-brand/typography.md) | Families, scale and text flow. |
| [Voice](https://github.com/withvariablelab/brand/blob/main/skills/vlab-brand/voice.md) | Tone, names and how to say what a Project is. |
| [Iconography](https://github.com/withvariablelab/brand/blob/main/skills/vlab-brand/iconography.md) | UI icons and shapes beside text. |
| [Project brand](https://github.com/withvariablelab/brand/blob/main/skills/vlab-brand/project-brand.md) | Class stamps, how a Sign is drawn and a Project's `brand/` folder. |
| [README](https://github.com/withvariablelab/brand/blob/main/skills/vlab-brand/readme.md) | The structure of each kind of README and the rules they share. |

The guideline is also an [Agent Skill](https://agentskills.io), `vlab-brand`, so agents read the same text people do.

Expand All @@ -88,6 +85,14 @@ pnpm add @variablelab/brand @fontsource/ibm-plex-sans @fontsource/ibm-plex-mono
@import "@variablelab/brand/tokens.css"; /* plain CSS: var(--vlab-ground)… */
```

## Contributing

The [contributing guide](https://github.com/withvariablelab/brand/blob/main/docs/contributing.md) covers issues, pull requests and releases, and the [development guide](https://github.com/withvariablelab/brand/blob/main/docs/development.md) covers setting up the repo and running its checks.

## License

The code and the tokens are [MIT](LICENSE). The Logo, the Class stamps and the Signs are not: see [BRAND-USE.md](BRAND-USE.md).
The code and the tokens are [MIT](https://github.com/withvariablelab/brand/blob/main/LICENSE). The Logo, the Class stamps and the Signs are not: see [BRAND-USE.md](https://github.com/withvariablelab/brand/blob/main/BRAND-USE.md).

<p align="center">
<a href="https://lab.variable.land"><img src="https://raw.githubusercontent.com/withvariablelab/brand/HEAD/.github/readme/logo.svg" width="24" alt="" align="absmiddle">&nbsp;Variable Land</a>
</p>
32 changes: 32 additions & 0 deletions docs/contributing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Contributing

The brand repository takes fixes to the guideline, the tokens and the templates, and reports of a Variable Lab page or README that breaks a rule. To set up the repo and run its checks, see the [development guide](development.md).

## Issues

- A report names the chapter, the token or the file, and says what is wrong or missing.
- A new rule or token, or a change to the Logo, a Class stamp or the type scale, starts as an issue before any pull request.

## Pull requests

1. Branch from `main` with a prefix: `feat/`, `fix/`, `docs/`, `chore/` or `test/`.
2. Write commits as [Conventional Commits](https://www.conventionalcommits.org), such as `docs: fix a link in logo.md`. The pull request title takes the same form, because it becomes the squash commit.
3. Run `pnpm check` before you push. It fails when a generated file is out of date.

CI has to pass, and a maintainer squash-merges.

## Changesets

A change to `skills/`, `tokens/`, `assets/`, `templates/`, `BRAND-USE.md` or the `exports` in `package.json` needs a changeset: run `pnpm changeset`. A change to the README, the LICENSE, the agent docs, `docs/` or CI needs none.

- Major: a token, an export path or an asset path is removed or renamed.
- Minor: one is added, or a chapter.
- Patch: a value or a text changes.

Nobody edits versions or `CHANGELOG.md` by hand.

## Releases

When changesets land on `main`, `vland-bot` opens or updates a "chore: update versions" pull request. A maintainer merges it, and that publishes `@variablelab/brand` to npm through trusted publishing.

Agents install the skill from `main` on GitHub, not from npm, so a change to `skills/` reaches them when it merges, before any release.
48 changes: 48 additions & 0 deletions docs/development.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Development

How to work on the brand repository in a clone. The [contributing guide](contributing.md) covers how a change gets in.

## Layout

- `skills/vlab-brand/`: the guideline, as an Agent Skill. `SKILL.md` routes each task to a chapter, and `glossary.md` holds the terms.
- `tokens/tokens.json`: the only source of colors, fonts and the type scale.
- `assets/`: the Logo and the Class stamps.
- `templates/project/`: what a new Project copies: its README, its docs and its `brand/` folder.
- `scripts/build.ts`: writes every generated file.
- `.github/readme/`: the images in the README. Generated.

## Setup

[mise](https://mise.jdx.dev) pins Node 24 and pnpm in `mise.toml`, with checksums in `mise.lock`:

```sh
mise install
pnpm install
```

After changing a version in `mise.toml`, run `mise lock` and commit both files.

## Tasks

```sh
pnpm build # write every generated file from its source
pnpm check # exit 1 when a generated file is out of date
```

## Generated files

Edit the source, then run `pnpm build`.

| Source | Generated |
| --- | --- |
| `tokens/tokens.json` | `tokens/tokens.css`, `tokens/theme.css`, the tables in `color.md`, the scale in `typography.md`, the palette in `README.md` with its swatches in `.github/readme/`, and `templates/project/brand/sign-readme.svg` |
| `assets/stamps/*.svg` | The stamp previews in `.github/readme/` |
| `assets/logo.svg` | `.github/readme/logo.svg`, the Logo on `ground` that READMEs link |

Inside Markdown, a generated block sits between `<!-- build:<name> -->` and `<!-- /build:<name> -->`. Write around the markers, never inside them.

## CI

- **On each pull request to `main`:** `pnpm check` (CI), and zizmor on the workflows (Workflow audit).
- **On each push to `main`:** the release job opens or updates the "chore: update versions" pull request, or publishes when that pull request merges.
- **Every Monday:** `pnpm audit`, which keeps an issue labeled `dependency-audit` open while it finds known vulnerabilities (Dependency audit).
15 changes: 12 additions & 3 deletions scripts/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,18 @@ outputs[".github/readme/logo.svg"] =

const table = (head: string[], rows: string[][]) =>
[head, head.map(() => "---"), ...rows].map((cells) => `| ${cells.join(" | ")} |`).join("\n");
const swatch = (group: Group, name: string) => `<img src="${swatchPath(group, name)}" width="48" height="24" alt="">`;
const rows = (group: Group, render: (name: string, token: Token) => string[]) =>
Object.entries(tokens[group]).map(([name, token]) => render(name, token));
// The README is also the npm page, so its images are absolute. They carry a width and no height:
// GitHub rounds an absolute image that has both. A list, not a table, so the swatches never shrink.
const readmeImage = (path: string) => `https://raw.githubusercontent.com/withvariablelab/brand/HEAD/${path}`;
const swatches = (group: Group) =>
Object.entries(tokens[group])
.map(
([name, t]) =>
`- <img src="${readmeImage(swatchPath(group, name))}" width="48" alt="" align="absmiddle">&nbsp;\`${name}\` \`${t.value}\`. ${t.use}`,
)
.join("\n");

const blocks: Record<string, Record<string, string>> = {
"skills/vlab-brand/color.md": {
Expand All @@ -118,8 +127,8 @@ const blocks: Record<string, Record<string, string>> = {
),
},
"README.md": {
color: table(["", "Token", "Value", "Use"], rows("color", (name, t) => [swatch("color", name), `\`${name}\``, `\`${t.value}\``, t.use])),
syntax: table(["", "Token", "Value", "Use"], rows("syntax", (name, t) => [swatch("syntax", name), `\`${name}\``, `\`${t.value}\``, t.use])),
color: swatches("color"),
syntax: swatches("syntax"),
},
};

Expand Down
3 changes: 2 additions & 1 deletion skills/vlab-brand/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,6 @@ Read the chapter the task touches:
| Write any public text | [voice.md](voice.md) |
| Use or draw a UI icon, set a shape beside text | [iconography.md](iconography.md) |
| Give a Project its Sign, set up its `brand/` folder | [project-brand.md](project-brand.md) |
| Write or restructure a README, or a repository's contributing and development docs | [readme.md](readme.md) |

Beyond this folder, the brand repository (`github.com/withvariablelab/brand`, the package `@variablelab/brand`) holds the tokens (`tokens/`), the Logo and the Class stamps (`assets/`), the template for a Project's `brand/` folder (`templates/project/brand/`) and the terms of use for the marks (`BRAND-USE.md`).
Beyond this folder, the brand repository (`github.com/withvariablelab/brand`, the package `@variablelab/brand`) holds the tokens (`tokens/`), the Logo and the Class stamps (`assets/`), what a new Project copies (`templates/project/`: its README, its docs and its `brand/` folder) and the terms of use for the marks (`BRAND-USE.md`).
Loading
Loading