---
name: set-text-flavor
description: Reference for Set's flavor text, the in-world prose the Set World API returns, namely skill flavor, class descriptions and status-effect descriptions, together with the phrases used as names for advantages, disadvantages and item words. Use when showing tooltips, a codex or a character sheet, querying or searching the prose through the API, writing a game's own text in Set's voice, or deciding what the text may and may not be taken to mean.
license: Free to use when obtained from set.world, commercially too (the API, what it returns, the skills and downloaded models). The source code of Set is © Jimmy Lee under CC BY-NC 4.0 and its commercial use needs a paid waiver.
metadata:
  version: "0.8.9"
  title: Text flavor
---

# Text flavor

Flavor text is everything in Set that is written to be read by a player rather than computed: the sentence under a skill, the description of a class, the prose of a status effect, and the phrases that name advantages, disadvantages and items. It is data. The API serves all of it, a game may show any of it, and none of it carries a mechanic.

This skill owns the map of where the text lives and the voice it is written in. Each table's own skill owns its rows.

## Where the text lives

| Text | Field | Rows | Endpoint | Part of `contentVersion` | Owner |
| --- | --- | ---: | --- | --- | --- |
| Skill flavor | `flavor` | 288 | `/api/skills` | Yes | [Skills](https://set.world/skills/character-skills) |
| Class description | `flavor` | 145 | `/api/classes` | Yes | [Classes](https://set.world/skills/character-classes) |
| Effect description | `description` | 48 | `/api/effects` | No | [Effects](https://set.world/skills/status-effects) |
| Advantage names | `name` | 144 | `/api/advantages` | Yes | [Advantages](https://set.world/skills/character-advantages) |
| Disadvantage names | `name` | 144 | `/api/disadvantages` | Yes | [Disadvantages](https://set.world/skills/character-disadvantages) |
| Item words: quality, prefix, material, base type, suffix | `name` | 19 tables | `/api/tables` | Yes | [Item properties](https://set.world/skills/item-properties) |

That is 481 written passages (skills, classes and effects) and the names around them. On a rolled character the same text arrives in place: `class.flavor`, `traits.skills[].flavor`, `traits.advantages[].name`, `traits.disadvantages[].name`, and each item's composed `name`.

## Schema

There is no flavor endpoint of its own; the text is a field of each table's row.

```ts
type SkillRow = { id: number; name: string; flavor: string };
type ClassRow = { name: string; flavor: string; mainhand: string };
type EffectRow = { name: string; description: string };
```

One row of each, as served:

```json
{ "id": 0, "name": "acrobatics", "flavor": "To move as one unbound by weight, for the body becomes an instrument of grace beyond the common measure" }
```

```json
{ "name": "Adventurer", "flavor": "The Adventurer arrived upon these shores seeking a tale; what was found is a story that permits no departure", "mainhand": "sword" }
```

```json
{ "name": "Burn", "description": "Let the afflicted be consumed by fire, and let all who strike the burning know their blows fall upon weakened flesh." }
```

## Query it

```sh
curl 'https://set.world/api/classes?mainhand=sword'      # the description of one class
curl 'https://set.world/api/skills?q=blade'              # search skill names and flavor
curl 'https://set.world/api/effects?q=fire'              # search effect names and descriptions
curl 'https://set.world/api/skills?format=csv'           # every skill's flavor: id,name,flavor
```

`q=` matches text anywhere in the name or the prose, ignoring case; the filters are owned by [API connection](https://set.world/skills/api-connection). To hold all of the prose locally, three calls are enough:

```js
const get = async (path) => (await fetch(`https://set.world${path}`)).json();
const codex = [
  ...(await get('/api/skills')).data.map((row) => ({ kind: 'skill', name: row.name, text: row.flavor })),
  ...(await get('/api/classes')).data.map((row) => ({ kind: 'class', name: row.name, text: row.flavor })),
  ...(await get('/api/effects')).data.map((row) => ({ kind: 'effect', name: row.name, text: row.description })),
];
```

## The voice

Set's world speaks like an old monastic rule: plain, grave and measured. Each passage does three things: it names **a concrete act or object**, **an inward discipline**, and **a measured consequence**. The register is borrowed; no scripture, prayer or rule is quoted.

| Text | Shape | Length in the current table |
| --- | --- | --- |
| Skill flavor | One sentence describing a practice, often opening "To…", "The…" or "A…". No final full stop | 16 to 42 words |
| Class description | The archetype and its vow, most often naming the class and its mainhand weapon. No final full stop | 16 to 32 words |
| Effect description | One or two sentences of condition language. Every one opens "Let…" and ends in a full stop | 16 to 38 words |

Advantages and disadvantages are short phrases in lower case (`nimble and fleet-footed`, `a mind that teeters on the brink of madness`). Item words are single lower-case words; `-` means no word.

### Writing your own text beside it

A game that adds its own skills, classes, effects or lore can match the voice:

- Name a tangible thing or a practised act: a blade, a threshold, ash, counsel, keeping, weighing, bearing witness.
- Hold one small tension: a vow against circumstance, patience against danger, an outward act against an inward duty.
- Keep it to one image. One strong noun beats three adjectives.
- Do not write mock-archaic English ("thee", "doth"), praise ("powerful") or patch notes ("now", "improved").
- Do not put numbers, durations or multipliers in the prose. Rules belong in your rules.

## What the text is not

- **Not a mechanic.** A sentence may read like a rule ("let it not claim the final breath"). Set implements none of it: no endpoint applies a skill, a class ability or an effect. What a passage means in play is your game's design.
- **Not a label you may rename.** Names are data. An advantage's or disadvantage's stat impact is a hash of its exact name, a class is found by its exact `mainhand`, and item names are composed from exact table words. Show them in any case you like in your interface, but store and send them as returned.
- **Not stable across snapshots.** Skill flavor, class descriptions, trait names and item words are part of `contentVersion`: an edit to any of them moves it. Effect descriptions are reference text outside it. Keep the text with the object you rolled if you need it to stay as it was.
- **Not Set's interface copy.** Buttons, errors and these skills are written plainly. Only the world's own text uses the voice.

## A schema for your game's text

Set's text is English only. A codex that mixes Set's passages with a game's own, and leaves room for translation:

```ts
type CodexEntry = {
  id: string;
  kind: 'skill' | 'class' | 'effect' | 'advantage' | 'disadvantage' | 'item-word' | 'lore';
  name: string;                    // exactly as Set returns it, when it is Set's
  text: string | null;             // null for names that have no prose
  source: 'set' | 'custom';
  contentVersion: string | null;   // the snapshot Set's text was read from
  locale: string;                  // "en" for Set's own text
};
```

```json
{ "id": "class:adventurer", "kind": "class", "name": "Adventurer", "text": "…", "source": "set", "contentVersion": "4.swpi78HUCtcrZ1Eoi9dipw", "locale": "en" }
```

Everything the API returns, this text included, is free to use in a game, commercial ones too ([AGENTS.md](https://set.world/AGENTS.md) has the license).
