Changelog
All notable changes to Tapestry. Dates are ISO. This project follows semantic
versioning once it reaches 1.0.0; before that, minor versions may still move
things around.
0.3.0 — 2026-09-27
Added
- Nothing is typed twice. Every field on the Character page says where it comes from — "from sheet", "from the web", "from sessions", "from rolls", "from the dossier" — and follows it by itself. ✎ sets your own value; "back to source" drops it; if the sheet later changes, a quiet "sheet now says …" appears under yours. On a GURPS world the Identity and Appearance pages read age, height, weight, eyes, hair, skin, gender, handedness, title, faith, tech level, Status, Wealth, Reputation and the sheet's notes straight from GGA (paths checked against GGA 0.18.18). Only what the sheet lacks — nickname, birthplace, accent, social class, what people notice — is asked, as a question in the empty box.
- Pronouns. Each character is "she" unless her player picks He/him or They/them on the Identity page; every line on the page and every prompt follows it.
- Stars. ☆ on every person, goal, belonging, session, rumor, prompt and piece. Starred things lead their card; past six, a card shows only the starred ones and "and N more".
- Goals by horizon: Short-term, Medium-term, Long-term, Completed — and Unsorted, with one click to file each. "+ A goal" asks how far off it is.
- The Chronicle (was Backstory): the story in chapters, one dossier page each, reorderable, with Key facts and Themes beside it. The first time, writing that already exists — journals linked to the character, the old Backstory page, the sheet's notes — is offered as chapters ("Bring these in?"), and never offered twice.
- Roles. What each person is to the character — Ally, Enemy, Mentor, Patron, Rival, Friend, Family, Companion… (a world setting, with colours). They filter the People card and rim each person on the web opened from the Character page.
- Alive, dead, missing — a fact with its own "known by", and what each character believes. A character can believe someone dead who is not.
- Party members on the People card (NPCs / Party). Between two player characters the truth of how the other feels is that player's own feeling, so Belief vs truth works between players too.
- Bonds: a deep page on one relationship — trust, tension, how satisfied each side is, who the other person is and what that person wants, a given/received ledger, a communication log, obligations, open questions, a private theory, and "as agreed" beside "as I understand it" (the GM sees where they differ). In GURPS, Patron, Ally, Enemy, Dependent and Contact on the sheet become Bonds by themselves, showing the trait's points and frequency of appearance from the sheet.
- Sections a character can turn on: World standing, Bonds, Companions, Faith, Writing prompts (on by default).
- Writing prompts as a library of sixty, in six groups: pick at random, star, write a piece (saved on the dossier, titled with the prompt), and read them all under Pieces. Optional "Ask for a personal prompt" when the GM sets up a writing service in the GM's own browser.
- Tour 8 walks through the new pages (Help & tours, in the ⚙ Tools menu). For macro writers:
api.fields. and api.bonds..
- How a reaction was rolled. The
method Roll Tools for GGA 1.21.0 sends (1 each rolled separately · 2 the talker's roll · 3 average of the party · 4 one roll, personal modifiers) is kept on the roll and shown at the end of the "Last reaction roll" line and in the reaction history, with a tooltip explaining all four. The words are a world setting, Reaction roll methods. Tapestry's own Reaction roll records method 1; older rolls show none.
Fixed
- A GM's save could publish a player's private notes, feelings or bond. The GM's view folds in every player's private layer; saving a relationship (and a few other GM actions) started from that view and wrote it all to canon, where other players who know that relationship could read it. GM writes now always start from canon.
Changed
- Identity and Appearance are field pages now, not question pages. Anything already written on those dossier pages is kept and shown under "Also on this page".
- Tapestry now installs and updates from omegavtt.com. Paste
https://omegavtt.com/foundry/tapestry/module.json into Add-on Modules → Install Module. From then on Foundry shows an Update button for each new version, with a Changelog link so you can read what changed first.
0.2.0 — 2026-09-27
Added
- The Character page ("the study"). One page per player character. Players land on it when they open Tapestry (or pick which character, if they play several); the GM reaches it by Viewing as a character — it then becomes the first tab — or from the 📖 Journal button on a character's sheet, or the inspector. Overview cards: People (with their feeling word and, for the GM, the reaction chip), Where they have been, What they are chasing, What they carry (read from the sheet), What they have heard, and Something to write. Side pages: Identity, Appearance and Personality (writing prompts), Goals, and Backstory. "← Back to the web" is always top left, and every card has a way into the web.
- Writing prompts. Each question is the placeholder of an empty box; an answer is saved on the character's dossier journal as a heading and a paragraph, and read back from it — edits made in Foundry's own editor included. The questions are in the language file and the GM can edit them in Settings › Tapestry › Writing prompts. Keep these has a one-click Undo.
- Backstory with Share… — the dossier's Backstory page in Foundry's editor; nobody, the party, or everyone may read it, set as page ownership.
- Illuminated and Plain. A per-user Journal style: Illuminated (the default for players) is the study — a painted room (Gothic library, Campfire, Observatory, Rain-streaked window, or your own picture), grain, gold hairlines, Cinzel and Cormorant Garamond (bundled, OFL; no Google Fonts), an oval glowing portrait, a gentle fade. Plain (the GM's default) is the same page in the cockpit's own style. Same markup; reduced-motion respected; no sound, nothing looping; nothing about it touches the Web tab.
- Feelings, from both sides. Every relationship between two people carries each side's feeling in words (despises … devoted), what each thinks the other feels, a note, and feeling and shared-history chips. "First met" and "Last seen" are worked out from the sessions both were in. The same panel is on the person page, the web inspector and the Edit relationship dialog. A player's feelings go to their own layer: the GM sees them, other players do not.
- Reaction rolls. Rolls are filed on the relationship, newest first, with their modifiers, session and source; the newest is the NPC's current standing. A coloured band bar shows the GM's roll (gold dot) and the character's own guess (hollow ring). The table's bands, names and colours are a world setting. One door records them —
api.reactions.record() — used by: GGA reaction rolls in chat (recognised on the rolling client, verified against GGA 0.18.18; the NPC from the roller's target or selected token, or a one-line "Reaction roll vs whom?"), Roll Tools group checks (the call to paste is in docs/API.md), and Tapestry's own Reaction roll button (3d6 + standing, through Foundry's dice). A roll made in public is known to its character's player at once; otherwise it is the GM's.
- Reveal… on a relationship: the band only (the player's dot appears mid-band and the card says "seems well disposed"), the exact result, or the whole history. The player gets a "<character> learns" card in chat, in their own Journal style. One undoable change.
- Belief vs truth for reactions (Tools › ⚖ Belief vs truth…, and on the Character page): every character whose guess is in a different band from the roll.
- GM view / Player view on the Character page, to check what a player sees without changing Viewing as.
- A world without reaction rolls (setting: Reaction rolls › Off, or Automatic with no system bridge) gets feeling words for "how they feel about her" instead of the table.
- Tour 8 · The Character page. The sample world's Nessa now has feelings, rolls and a goal of her own to show it with.
api.reactions.*, api.character.open(), the hook tapestry.reactionRecorded, the chat button data-tapestry-action="character", and api.debug.measureWebRender().
Changed
- Leads & Clocks marks a lead known only to characters as "<Name>'s goal".
- A player's note (or feelings) on something they cannot edit no longer briefly replaces that entry on screen while it saves.
0.1.1 — 2026-09-10
Fixed
- Every dialog opened with a console error on Foundry v13+ ("root.querySelectorAll is not a function") and its option cards, segmented buttons and Known-by chips did not respond. DialogV2 calls its render option as
render(event, dialog) since v13; the shared dialog wrapper was reading the event as if it were the content element. The wrapper now resolves the element from whatever it is handed (element, jQuery wrapper, dialog, or event) and every dialog in the module goes through it.
- The scene-controls button used
onClick, deprecated in v13 and removed in v15. It now registers onChange only, wrapped in a double-fire guard so a v14 press that reaches us twice opens the window once.
- Import registry silently imported nothing from a prep-format file (
{ meta, relTypes, nodes: [], edges: [], slugs }): the arrays were dropped as "not a collection" and the toast said "Imported 0 entries". The importer now reads all three shapes — our own export, a bare registry, and the prep format — and reports entries, relationships, added types and skipped records.
Added
- Custom relationship types travel with an import. Keys listed under
relTypes (and any key an edge uses that the vocabulary lacks) are added to the world's extra relationship types with a neutral grey line style. Types the world already has are never overwritten. The Import dialog names what it added.
- Imported pages become journal pages. An entry that arrives with
pages[] (title, text, gm, source) gets those pages when its Foundry document is created; pages marked gm stay hidden from players who are granted OBSERVER on the journal, like the dossier's Secrets page.
- Import skips a record it cannot place (no id, unknown endpoint, unknown type) and says so, instead of failing the whole file.
Changed
api.import() now resolves to { nodes, edges, relTypesAdded, warnings, shape } instead of a bare count.
0.1.0 — 2026-09-10
Changed
- Help & tours moved out of the Web rail and into the ⚙ Tools menu, where it is the first item. It was only reachable from one tab, and it took rail space the things you touch every session wanted. The dialog lists the same seven tours with the same descriptions, ticks the ones you have taken, and carries the "show the first-run card again" button. The tours themselves are unchanged. The button is still called ⚙ Tools; its tooltip now names Help first. The rail ends at Faction Play, and the freed space is left empty for now.
- Customize my menus: the "Help & tours" toggle now hides the Tools menu item rather than a rail section, and a new "Show first-time tips again" button brings back the starter card and the first-open notice.
Added
- A one-time notice, per user per world, saying where the guided tours went: "Guided tours and help live under ⚙ Tools › Help & tours (top right)." In a brand-new world it is the starter card's last line rather than a second card.
Fixed
- The window no longer opens titled "Viewing as character" with the GM-only controls hidden. A tour left the viewer on a character it had borrowed,
endTour never put it back, and a character that resolved to nothing was named after its kind. Tours now restore the viewer (including Skip and Escape), an unresolvable viewer falls back instead of half-applying, a GM's first open of a session is always as the GM, and the title, dropdown, role class and viewer all move together through one setter.
- Toolbars no longer stack one control per row. Our inner wrapper was
class="app", which opted the whole module in to Foundry's form styling — full-width buttons, parchment inputs, and a square border around every portrait. It is .tapestry-shell now, with a reset scoped to button alone for the bare element rules core applies regardless.
- Every type filter is on when the window opens, Lead included. The saved filter is an off-list written by whichever build wrote it, so a set saved before Lead existed said nothing about Lead and a View saved then read as "hide it". Filter sets now record which types they were chosen from, and a type a set predates is on. Anything you deliberately turned off stays off.
- "Show these types" in the Web rail is a list of eight labelled rows again, not eight empty boxes. The first version of that reset also matched
input, and a companion rule stretched every input in the rail to full width — which pushed the type glyph and the label out of each row. The rail's GM-only and Faction Play checkboxes were caught by the same rule.
- The New entry Type list always offers Place. Hiding it left players unable to say where they had been; a player's place is forced to "proposed" instead, and the form says so. Type order is now Person · Place · Organization · Item · Event · Adventure · Rumor · Lead everywhere.
- Authoring dialogs read
game.user.isGM, never the "Viewing as" viewer. A GM previewing a character was dropped into player mode while still writing canon.
- The main window no longer assigns
state, which ApplicationV2 reserves; the UI state lives on ui.
0.1.0 — 2026-09-09
The first release. Everything in docs/TAPESTRY_PLAN.md §6–§11.
The knowledge web
- One data model that records who knows what: every entry and every relationship carries a "known by" list.
[] means GM-only; "all" means everybody; and those are deliberately different things.
- Viewing as (GM only) redraws every screen — web, map, board, timeline — as another character, user or group knows it. The window title says whose eyes you are looking through.
- Name-by-knowledge: an entry shows its true name to whoever knows it, otherwise the most specific nickname that viewer has learned, otherwise "Unknown person".
- Orrery layout: what you click becomes the centre, everything else arranges by distance. One to three hops; three is the cap on purpose.
- Tree, Factions (organizations as bubbles with their known members inside, party standing on the rim) and Pinned (a corkboard you arrange by hand, over an optional picture) layouts.
- Places nest, and a collapsed place rolls up the relationships of everything inside it into one line marked with a count. Roll-ups are derived when the graph is drawn and are never stored.
- Path to… finds the shortest chain of relationships between two entries and draws only that, with each link named. "Another route" cycles alternatives. A GM can walk secrets; a player never can.
- Views save a filter, a layout, a reach, positions and a background, and can be shared with the players. Line styles give each kind of relationship its own colour, dash and width.
- Search over names and the aliases a viewer knows, bookmarks, breadcrumb containment trail, and Back.
Reference, rumors, leads, time
- Map tab: any picture or a Scene as the backdrop, with entries pinned on it. A pin is an entry — same relationships, same dossier, same who-knows-it. Layer toggles, connections between pins (the murder board), drill-down into a place's own map, and one-way push of pins to Scene Notes.
- Reference tab: a grid of cards that open sheets, roll tables, play music, run macros, activate scenes and render journal pages inline. Boards are saved sets and can be shared to players read-only.
- Rumors tab: claims with sources — who said it, where, when, about what, and whether it has held up. Confirming offers to promote a rumor to a real relationship; marking one false keeps it, in red.
- Leads & Clocks: things the party can chase, and clocks that tick toward something happening. At the top, a clock posts a chat card and can run a macro.
- Timeline: eras as spanning bars, events and sessions in lanes, the world clock as a marker. Drag to re-date, double-click a lane to make an event there. Dates are always world-time numbers plus a precision, read through Simple Calendar, Foundry's own calendar, or a plain day count.
Players and factions
- Players create entries, relationships and notes in three scopes: private, their group's board, or proposed to the GM. Each has its own colour on every screen.
- Duplicate prevention in three places: while typing a name, in the GM's Queue (by name and by relationship signature), and in the merge itself.
- The Queue: approve, decline, or merge a player's entry into canon as an alias only they see. Nothing is ever lost.
- Faction Play (a world setting): groups with their own boards; assertions — a relationship one group told another, with source, confidence, evidence and turn; ghost nodes for what a group has only heard of; contradiction flags; a share log; belief-vs-truth per group; and a turn counter.
- Players work between sessions with no GM online: their own layers are theirs to write, and anything that needs canon is queued or downgraded with a clear explanation rather than silently lost.
Foundry integration
- Entries create and adopt Foundry documents: a person becomes an Actor with a scaffolded dossier journal (Backstory · Gallery · History · Secrets), anything else a journal with your note as page 1. Lore-only entries are first-class.
- Delete guard: deleting a linked actor, journal, item or scene stops and asks what should happen to the entry — archive, unlink, or delete both.
- Drag and drop from the sidebar onto the web, a map or a board, with the "this looks like something you already have" check.
- Sheet integration: a Dossier button, a Connections button and a Connections section on actor sheets and dossier journals, on both ApplicationV2 and ApplicationV1 sheets. Token HUD and directory context menus too.
- Broken-link detection on load, with a Repair dialog that ranks candidates by compendium source, then by name in the world, then in compendiums.
- Whole-registry export and import as JSON.
- Undo for every change, with a per-entry history in the inspector.
Session tools
- Recorder: one audio track per connected player through the AV client interface, chunked to IndexedDB every minute, exported as a zip with the chat log and a registry snapshot. Consent is a world setting; recording cannot start until every connected player has acknowledged or opted out; a REC pill shows on every client while it runs.
- Session Studio (
tools/session-studio): a dependency-free Node CLI that transcribes each track with whisper.cpp (or any OpenAI-compatible endpoint), merges them by timestamp, and writes recap.json — or prompt.md to paste into any AI chat if you would rather not set an API key.
- Recap review: import
recap.json, walk every proposed change with the duplicate check beside it, edit in place, and Apply. Nothing enters the web until Apply.
GURPS bridge
Loaded only on a GURPS world, and shipping no game data of its own:
- Recap items are created as equipment with
save: true and a [tapestry:<id>] marker, so a GCS re-import matches rather than duplicating; when it does duplicate anyway, the bridge keeps the GCS copy and carries the Foundry copy's notes, image and lore link onto it.
- Standing tiers map to reaction modifiers, with a chat card that rolls 3d6 plus the modifier through Foundry's own
Roll.
Everywhere
- Every button, dropdown, checkbox and chip carries a why and when tooltip.
npm run audit:tips fails the build if one does not.
- Seven guided tours that drive the real interface.
- Customize my menus: untick anything you never use and it leaves your screen only. Nothing is deleted.
- A first-run card that builds the first web in three steps.
- A sample world (Greywater & the Marches) that loads and removes in one click.
- Portraits or type glyphs in circles. Never initials.
← Back to Tapestry