Skip to content

Add Stagehand stages, fix viewport capture, extend the Chronicle - #9

Merged
ShaalaXIV merged 1 commit into
mainfrom
claude/stagehand-stages-and-chronicle
Sep 22, 2026
Merged

ShaalaXIV merged 1 commit into
mainfrom
claude/stagehand-stages-and-chronicle

Conversation

@ShaalaXIV

Copy link
Copy Markdown
Owner

Four changes. All additive to the wire contract, so ApiRoutes.ProtocolVersion is unchanged.

Stagehand stages on beacons

A keeper attaches the Stagehand stage they dressed a place with; guests who run Stagehand can see the camp as it was built rather than an empty field.

Beacon talks to Stagehand over Dalamud IPC by channel name rather than linking its API library. Every call it needs takes and returns primitives, so this costs nothing in capability — and it keeps a licence boundary between the two projects (both Stagehand packages are AGPL-3.0) instead of pulling one into the other.

The guest decides. Nothing loads silently the first time: the beacon page offers the stage and remembers the answer per beacon. Auto-loading everything is a setting, off by default. Every stage is created as a Stagehand temporary stage, so nothing is written into a guest's own library and refusing later leaves nothing behind.

The server treats a stage as an opaque document — it reads only what a guest needs in order to decide, and refuses the two shapes that cannot work for anybody but their author: over the 2 MB cap, and modpacks that load files from the author's own disk.

Stage definitions live beside the images under the data directory, and deploy/backup.sh now captures them.

Photographs

Capture never worked. ImGuiViewportTextureArgs.ViewportId was left at zero, and the main viewport's id is a hash that can only be read inside a draw callback; Uv0/Uv1 were also unset, which describes an empty rectangle. The id is now recorded once a frame and passed at the point of use.

The game's interface is hidden while the shutter is open and given time to finish fading, so a photograph is of the scene rather than the HUD. Both configurable.

The Chronicle

The part of a card that is true today rather than true in general:

  • Currently — the live IC line, carrying its own timestamp so the card shows its age. Saving a biography no longer makes a month-old line look freshly written.
  • In character / out of character flag.
  • Out of character note — the player speaking as themselves.
  • At first glance — five label-and-line slots for what a stranger notices before a word is exchanged.

The live line has its own route and its own commands: /beacon currently, /beacon ic, /beacon ooc. A field that takes three clicks to change is written once and never again.

Example content

Removed the placeholder names, epithets, quotes and boundaries from the profile and beacon editors. The hints now describe their field instead of filling it.

Migrations

Two, both additive: AddBeaconStages and AddChronicleMoment. They apply on the next server start.

Verification

  • Full solution builds clean in Release; tools/contrast-audit.py passes.
  • Stage upload exercised end to end against a local server with a real 21-object stage: metadata parsed, definition round-tripped byte-identical, and empty / malformed / disk-backed stages each refused with a usable message.
  • Chronicle endpoints exercised end to end: empty glance slots dropped, over-long lines truncated, clearing the live line clears its timestamp, and a full card save leaves the live line's age untouched.
  • Local test database and uploads purged afterwards.

Not verified without the game: whether Stagehand accepts the raw stage JSON as its definition string. ToDefinitionString uses different JsonSerializerOptions than the file format, and there is no base64 or compression wrapper in Stagehand.Definitions.dll — only per-resource compression inside the JSON — so it should parse. If not, the failure surfaces as "Stagehand could not read that stage" rather than anything worse.

🤖 Generated with Claude Code

Four changes, all additive to the wire contract so the protocol version is
unchanged.

Stagehand stages on beacons
---------------------------
A keeper can attach the Stagehand stage they dressed a place with, so guests
see the camp as it was built rather than an empty field.

Beacon talks to Stagehand over Dalamud IPC by channel name rather than linking
its API library. Every call it needs takes and returns primitives, so this costs
nothing in capability and keeps a licence boundary between the two projects
instead of pulling one into the other.

The guest decides. Nothing loads silently the first time: the beacon page offers
the stage, remembers the answer for that beacon, and only skips the question for
beacons already agreed to or when auto-loading has been turned on for everything
(off by default). Every stage is created as a Stagehand *temporary* stage, so
nothing is written into a guest's own library and refusing later leaves nothing
behind.

The server stores a stage as an opaque document. It reads only what a guest
needs in order to decide -- name, weight, intended zone -- and refuses the two
shapes that cannot work for anybody but their author: over the size cap, and
modpacks that load files from the author's own disk. Understanding the format
more deeply than that would tie the server's release cycle to a game plugin's.

Stage definitions live beside the images under the data directory, and the
backup sidecar now captures them.

Photographs
-----------
Capture never worked: ImGuiViewportTextureArgs.ViewportId was left at zero, and
the main viewport's id is a hash that can only be read inside a draw callback.
Uv0/Uv1 were also unset, which describes an empty rectangle. The id is now
recorded once a frame and passed at the point of use.

The game's interface is hidden while the shutter is open and given time to
finish fading, so a photograph is of the scene rather than the HUD. Both are
configurable.

The Chronicle
-------------
The part of a card that is true today rather than true in general:

- "Currently", the live in-character line, carrying its own timestamp so the
  card can show its age. Saving a biography no longer makes a month-old line
  look freshly written.
- An in-character / out-of-character flag.
- An out-of-character note: the player speaking as themselves.
- "At first glance": five label-and-line slots for what a stranger notices
  before a word is exchanged.

The live line has its own route and its own commands, /beacon currently,
/beacon ic and /beacon ooc. A field that takes three clicks to change is written
once and never again, which is worse than not having it.

Example content
---------------
Removed the placeholder names, epithets, quotes and boundaries from the profile
and beacon editors. The hints now describe their field instead of filling it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@ShaalaXIV
ShaalaXIV merged commit b79b782 into main Sep 22, 2026
1 check passed
@ShaalaXIV
ShaalaXIV deleted the claude/stagehand-stages-and-chronicle branch September 22, 2026 23:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant