Repository navigation
DM Screen: a GM panel that unfolds out of a falling-apart d20 - #989
Merged
Merged
Conversation
A tri-fold icon in the campaign header opens a GM control panel: a d20 rolls in, falls apart into pieces that bounce and settle, and the screen unfolds out of it. Click or Escape skips the whole animation. The panel shows game state (downtime switch and pending requests), the in-world date, time and weather, the next game night with its RSVP tally, Foundry presence, the party's meters, a conditions lookup and a reveal list for hidden NPCs. Party meters and conditions come from the system package through a new optional manifest `dm_screen` block. Part of #973. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011hzkeAmSZQx5cQw5QL3ngM
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011hzkeAmSZQx5cQw5QL3ngM
Reveal now sets the private flag instead of toggling it, so a double-click can't hide the character again, and it refuses entity types the panel doesn't list. The Reveal button drops repeat clicks while a request is in flight, and the Rules tab is skipped when a package has no data provider. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011hzkeAmSZQx5cQw5QL3ngM
Heroes start folded to their name, health bar and the meters that have no maximum (a class resource, an armour class); clicking a hero folds the player's name and the remaining meters open below. With more heroes than fit, the list scrolls inside the panel, fades at the edge and says how many more are below. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011hzkeAmSZQx5cQw5QL3ngM
The system's dm_screen block can now name the sheet fields for a hero's class and current conditions. The folded line shows a count of conditions; the opened hero shows the class and each condition. An opened hero is always shown completely: the list scrolls the others aside and grows when one hero alone wouldn't fit. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011hzkeAmSZQx5cQw5QL3ngM
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Requested by Key Maker · project thread
Fixes #975
Security implication: two new owner/scribe-only routes (GET panel, POST reveal). Reveal can only make an NPC or creature in the same campaign visible; it never hides anything and refuses other entity types and other campaigns. The downtime switch reuses the existing owner-only Armory endpoint.
Consumer-verified: the downtime buttons post
opento the existingPOST /campaigns/:id/armory/downtime; the panel refreshes on that endpoint's existingarmory-movedHX-Trigger.Mockup: signed Sign-offs card
mock-dm-screen(rounds 1–3, round 3 approved "Yes, build it like this"); mockup at https://claude.ai/artifact/HZsaAMnxuW4RvEyR71u9tBWhat this changes
Owners and scribes get a tri-fold icon in the campaign header, just before the avatar. Clicking it rolls a d20 to the middle of the screen. The die falls apart into pieces that drop, bounce off the floor and walls, and settle and fade, and the DM Screen unfolds out of it. Clicking anywhere or pressing Escape skips the whole animation, and reduced-motion users get a plain fade. On the panel:
The party meters and conditions come from the game system package, as Key Maker asked. This PR adds a new optional
dm_screenblock to the system manifest. In it, a package names up to six meters by field key (current/max, warn threshold) and a reference category for the conditions lookup. Until a package ships the block, the panel says "{System} doesn't fill in hero numbers yet" and leaves the Rules tab out.Signed off: the folded heroes (with class and conditions, and the open hero always shown whole) were approved on the Sign-offs card
mock-dm-foldround 2.Why
#973 (parent). Key Maker asked for a GM control panel opened from the top right with a distinctive effect. The plugin follows T-B2:
internal/plugins/dmscreendepends only on source interfaces, and the adapters over armory, calendar, sessions, entities, campaigns and the Foundry presence hub live ininternal/app/dm_screen_adapters.go. Each source is optional; a failing one drops its section with a log line instead of failing the panel.Load-bearing lines:
internal/plugins/dmscreen/routes.go: both routes areRequireAuth+RequireCampaignAccess+RequireRole(RoleScribe), and the service re-checks the role.internal/app/dm_screen_adapters.goReveal: checks the campaign and that the type is an NPC/creature, then calls the new idempotentEntityService.SetPrivateInCampaign(..., false). The toggle isn't used, so a double-click can't re-hide.internal/systems/manifest_dm_screen.go: validation of the new manifest block.internal/plugins/armory/routes.go: newAddonSlugconstant so the adapter doesn't repeat the plugin name (plugin-isolation guard).Honest deviations from the signed mockup, each with its follow-up (on the Sign-offs small-differences card
diff-dm-screen):Package halves: keyxmakerx/Chronicle-Draw-Steel#70 and keyxmakerx/Chronicle-DnD-5.5e#5 add the
dm_screenblock; both validated with this branch'sValidateManifest.Test plan
go build ./...andgo vet ./...: clean.go test ./... -short -v(after merging the latest main): 3,179 passed, 92 skipped, 0 failed.internal/plugins/dmscreen(service roles, downtime toggle rights, meters, conditions, failing sources, reveal; panel render),internal/systems(manifestdm_screenvalidation),internal/app(reveal never hides, never crosses campaigns, refuses non-NPC types; night label),internal/plugins/entities(SetPrivateInCampaignset-not-toggle and campaign guard).make test-js: 361 passed, 0 failed.Tenet self-check
internal/app, with no new plugin-name literals.internal/plugins/dmscreen/.ai.md.Stop-and-flag
If during review you find this PR violates a tenet that the author missed, flag it explicitly in a review comment citing the tenet by number.
🤖 Generated with Claude Code
https://claude.ai/code/session_011hzkeAmSZQx5cQw5QL3ngM
Generated by Claude Code
Generated by Claude Code