v0.10.0
2026-03-15
Finishing Touches
- [x] For each token container in the Party UI and the Target UI, add an "expand" button. When clicked, this expands the container downward, revealing a scrollable content area 300px in height.
- In the main content area, there are the following sections: Properties, Conditions, Auras, and Actions. The content of this area can be copied from the old Token Subcontext UI. It should be made more compact with smaller fonts and tighter spacing to fit within the smaller container.
- When opened, this expanded container can be closed either by clicking the "expand" button again (which switches to a "collapse" icon), or by clicking anywhere outside the container, or by pressing the Escape key. When the container is open, clicking inside it should not trigger the outside click handler that closes it.
- [x] When changing maps, deselect current token. Also, if a token is impersonated, de-impersonate it unless it happens to be on the new map as well, in which case maintain the impersonation and just ensure the exact token id being impersonated matches the token on the new map.
- [x] Initiative status should be map specific. If I start initiative in map A, then switch to map B, initiative should not be active in map B. If I switch back to map A, initiative should still be active there, and the turn order and current turn should be maintained.
- [x] When changing artwork, add 'load from url' to the options (upload from device, google image search, etc). The load should happen from the server side, to avoid CORS issues and to ensure the image is added to the library for future use.
- [x] In the Edit Token modal, Artwork tab, when the token has one artwork designated as "token", add an option to "copy to portrait", using the same base image but as portrait instead of token. Clicking this switches to the view for the new portrait artwork, where the user can then apply background removal or other edits as desired.
- [x] In the /campaign/:campaignId route, show a list of that campaign's characters below the map list.
- [x] When the user tries to upload an image that's too large (check existing size limits), use a library like Photon or just the canvas to convert the image to high-quality webp on the client before uploading.
- [x] Add an "add to map" option in the character sheet ... button, which prompts for a list of maps in the campaign. Selecting one imports the character as a token onto that map.
- [x] In the CharacterNav component in the character sheet sidebar, switch to the standard list component grouping, sorting, and filtering, with the default grouping of 'campaign' with the current campaign first.
- [x] In the character list page, when grouped by campaign, show 'unlinked' last instead of first.
- [x] The 'open character page' button in CurrentTokenBar goes to the wrong url.
- [x] Add 'open character page' to the PartyCard and TargetCard ... button menus.
- [x] Restore 'switch map' to the Map menu in PlayTopBar, which opens a submenu with a list of maps in the current campaign. Selecting one switches to that map.
- [x] Bug: if I go to /campaigns, then click a campaign, then go back, and click a different campaign, it shows me the maps of the first campaign I clicked on, not the second. Suspect a bug with caching in the useMaps hook, or a failure to invalidate that cache when switching campaigns. Going to a route that doesn't start with /campaign resets it.
- [x] Refine on server still doesn't work ({ "error": "Cannot find package 'onnxruntime-common' imported from /Users/kenjura/repos/purple-cat-games/platform/node_modules/.pnpm/@huggingface+transformers@3.8.1/node_modules/@huggingface/transformers/dist/transformers.node.mjs" })
- [x] Add to Map in the Character page fails with 'no maps available, link to a campaign first ' when the character is already linked to a campaign
- [x] After changing the tokenization parameters (pan/zoom) of a token artwork, the token on the map doesn't always update until you re-select the token art as the current art for the token.
Playtesting Feedback
- [x] Intellisense in the action code editor should understand the 'applyDamage()' function
- [x] When applyDamage() is used in an action, the token owner should be able to see and accept the damage application, not just the GM. (prerequisite: data model change to track token ownership, see below)
- [x] In the chat log, when a die result is rendered, there is a special presentation for natural 20s. This should be augmented so that the die result has cat ears.
- [x] Add a top bar in /play
- Contains the menu (campaign, token, actions, etc)
- On the right side, there is an indicator of how many players are currently connected to the game, which when clicked opens a list of those players with some info about them (name, avatar, what map they're on, etc)
- Use websockets to track connected users in real time, and which map they're on, to populate this list.
- [x] need an easier way to apply damage
- Campaigns and Systems now have Actions. Campaigns inherit System actions and can extend them.
- Actions are standard actions, same editor, same entity, etc. But every token in the campaign automatically has these actions. (Ensure the Import Character feature doesn't delete or duplicate them; if a character has an action with the same name as a campaign action, give the character action a different name)
- Add an "inflict damage" action to 5e and System 8, which prompts the user for how much damage to apply (and an optional field for damage type), and then applies that damage to the selected token. In both systems, HP cannot be negative, so take that into account. There is an existing applyDamage() function which may be reusable for this purpose, and understands logic like damage resistance.
- Similar to 'inflict damage', add a 'heal' action which works the same way but in reverse.
- [x] When the GM runs an action that uses applyDamage(), auto-accept the damage application so the GM doesn't have to click through it.
- [x] when multiple tokens are selected, within the multi-selected-token context, show system and campaign actions. When clicked, these execute for all selected tokens, with only one input prompt (not one per token), then the action is executed for each token with the same input.
- [x] the multi-token-selected context needs its top and height adjusted for the new top bar in /play, which takes up some vertical space.
- [x] The new selected token modal's menus aren't scrolling correctly. It seems their height projects off the screen and the scrolling is scrolling the entire page. The height of the submenus should not exceed the available viewport height, and the submenu itself should be the scroll container, not the entire page.
- [x] When sufficient width exists, expand the /play top bar so the current submenu items of "menu" become top-level menus in this bar, horizontally arranged. When width is constrained, collapse the ones that don't fit into a "more" menu. When all submenus are collapsed, change the label to "menu" instead of "more".
- [x] when the user executes an action, spawn a notification (Mantine) near the element they clicked on to execute the action (or near the target if targeted) with the chat log output of the action. This doesn't replace the chat log output. The notification should auto-expire after a few seconds.
- [x] add a 'description' field to Actions, which is editable in the Edit Actions modal (there may be more than one instance of this; ensure all are updated). When hovering over an action button in the token context, show the description in a tooltip. The Import Character process should query the description of a power action from the system wiki (in system 8) to populate this field.
- [x] right click context menu on map should include edit map
- [x] CurrentTokenBar changes:
- Now mounted flush with the viewport bottom. The status display with world/map coordinates is moved to the top of the map frame.
- Token Art prefers portrait art where present. This art is now larger: 150% the height of the CurrentTokenBar's main area, flowing up out of the bar rather than being contained within it.
- The far right edge panel containing the dice roller and the close button is thinner (minimal width to fit the dice roller), and also contains a ... menu button with additional options such as "view character sheet", "move to map", "copy token", etc.
- The rest of the bar is now a tabbed area with tabs for Actions, Properties, Conditions/Auras, etc. The Actions tab shows the token's actions as buttons, same as the token context today. The Properties tab shows all token properties in a scrollable list with inputs to change them. The Conditions/Auras tab shows the token's conditions and auras with toggles to change them. The tabs are mounted to the top of the bar.
- The art will show the token's bars. If the art is tokenized, show the curved bars that normally are shown on the map. If the art is a portrait, instead show bars as straight rectangles.
- If you are a player (not the owner of the current campaign/map), this panel is open by default if your token is on the map. If it's not, this component is rendered, with a prompt to insert your character into the map. If you have multiple characters on the map, there is a dropdown selector to switch between characters. If you have multiple characters but no tokens, you can insert any of them with the prompt.
- If you are the campaign owner, this panel isn't open by default. However, when initiative is active, and a token's turn starts, and that token is not a character owned by a currently-connected player, the panel automatically appears with that token populated.
- During initiative, there is a special button floating above the top right of this panel to "end turn" if you are impersonating the token whose turn it is.
Data Model
- [x] Enhance the token data model to have an 'owner' field that specifies which user owns the token. This doesn't have to be the owner of the map or campaign. This should not be optional, as every token was created by a user. For tokens in the db before this change, infer the owner from the token's map, which is owned by a campaign, which has an existing owner.
Navigation
- [x] Level 1 nav changes:
- Level 1 nav (which is on the left edge of the viewport) is wider to accomodate labels
- Each nav item has a label in addition to its icon
- New top-level item: Play
- Route: /play/:campaignId/:mapId
- This route is the actual map view where you can play the game (with WebGL, chat, etc)
- Campaign routes changed to /campaigns, /campaign/:campaignId, /campaign/:campaignId/characters, /campaign/:campaignId/maps, /campaign/:campaignId/map/:mapId, etc
- Nav can be expanded to two levels for subroutes:
- Characters has Characters and Parties
- Campaigns has Campaigns and Maps
- UI implementation: 2nd level items are slightly indented, and their parent has a caret that can open/collapse the submenu. Submenu is always visible when you're currently on a route reached through that submenu
- Site identifier is on the top of the left nav. It is a purple cat icon with no label. Existing 'purple cat' label removed.
- Left nav is 100% viewport height, instead of starting below the top bar
- Clerk Profile button moved to the bottom of the left nav
- Settings is the 2nd item from the bottom, which contains the new user settings route, which includes site theme (retro, modern, etc). Site theme button removed from top bar.
- Settings also contains an About page. For now, that page just says the version number, version date/time stamp, copyright line, etc
- Help icon (question mark) is the 3rd from the bottom on the left nav. Help route is a 'TBD' page.
- Notifications icon removed. Notification badges will be applied to the left nav item that the notification is relevant to (e.g. if you get invited to a campaign, the Campaigns nav item gets a badge).
- On the /campaigns route, show a UI about invited campaigns before the normal content of that page
- [x] Made new, more readable icons for level 1 nav
- Play: IconIkosaedr
- Character: IconUser
- Library: IconBook
- Systems: IconMathIntegrals
- Users: IconUsers
- Purple Cat icon: /docs/design/cat-icon.png (also used as favicon)
- [x] Existing top bar is now hidden for all routes.
- [ ] The /play route is the only route that shows the WebGL map and the top bar. The route is /play/:campaignId/:mapId
- [ ] The /campaigns route shows a list of campaigns, and /campaign/:campaignId shows the campaign detail page, which shows a map list. Clicking on a map goes to /play/:campaignId/:mapId
Mobile Nav
- [x] In mobile view, the 2nd level nav is bottom-mounted. It is somewhat out of date. It should have only the following items, from left to right:
- "Me": represents the impersonated token. If none exists, prompt the user to touch a token to select one. This option has two modes: full and partial.
- Partial: in the bottom third of the screen, shows the portrait art, vital stats, and actions of the impersonated token. This is the mobile view of the 'impersonated token' UI.
- Full: shows the character sheet or token modal view of the impersonated token, depending on whether the token is linked to a character.
- Tapping the "Me" nav item toggles between these two modes.
- Chat: has three modes: full, partial, and off.
- Full: shows the chat log as a full screen takeover (current implementation).
- Partial: in the bottom third, shows the chat log in a condensed form. Chat messages are capped at one line (with ellipses), background is transparent.
- Off: chat log is not visible at all. A badge shows how many chat messages have been sent since the user last viewed the chat log in partial or full mode.
- Menu: opens the same menu as the "Menu" button in the desktop Start Menu (see below). This is the mobile access point for all of the same features accessible through that menu, such as opening the library, system sidebar, campaign settings, etc. Pops up instead of down, natch.
- "Me": represents the impersonated token. If none exists, prompt the user to touch a token to select one. This option has two modes: full and partial.
Start Menu
Agent: this project has a prerequisite of all changes in "navigation" except the new icons. Implement this when that is all done.
- [x] Since the top bar is gone, the menu on /play/:campaignId/:mapId needs to be accessible from somewhere else. Create a UI element which, when clicked or touched, opens a menu with the current menu items (campaign, map, library, system, token, combat, dice, actions (for impersonated token)). They each have submenus identical to the current treatment.
- For now, this can be a regular button at the top center of the map view, with the label "menu".
Map
- [x] When initiative is active, keep track of movement for each token.
- If it's not your turn, either you can't move or your invalid movement is noted (based on a newly-created Campaign setting for this behavior)
- If it is your turn, movement is tracked as normal and shown in initiative log
Actions
- [x] The tooltip that appears on action buttons (in all the locations action buttons appear) should be constrained not to overflow the viewport, and should be scrollable if the content exceeds the available space. This is especially relevant for the "Actions" menu in the token context, which can have many actions that exceed typical viewport height.
- [x] Add a custom color (default null) to the Action entity, relevant APIs, and the Edit Action modal (there may be two of these). When set, this color determines how the action button is presented.
- [x] Actions generated by Character Import should have categories (e.g. Assault, Control, etc). When these categories exist, use them as second-level grouping for actions in the CurrentTokenBar. Assign colors to each of these categories and assign it to each action in that category. Actions can have multiple categories; if so, show the action in each relevant category group, with the color of that category. For example, if Assault is red and Healing is green, the Transfusion spell (Assault and Healing) would show up in both the Assault and Healing groups, with a red background in the Assault group and a green background in the Healing group.
Token Modal
- [x] Change to a tabbed interface with the following tabs:
- General: has name, layer, chat color, pronouns, and a selector for which artwork shows on the map and which shows in the token context / impersonated context (not the full artwork UI, just a simple selector with thumbnails)
- Vision and Light: current content in the Vision and Light section
- Properties: all token properties, editable, option to add more
- Actions: list of actions as buttons; same UI treatment as token context today
- Conditions: show all campaign conditions with a toggle for each
- Auras: same UI as token context
- Artwork: dedicated tab for artwork editing.
- Start with existing token artwork UI
- First element is a selector for which artwork is currently being edited. This is a horizontal list of thumbnails with a 'currently selected' indicator (default: leftmost item). To the right of this list is a + button to add a new empty artwork entity to the token.
- Second element is the editor for a piece of token artwork:
- Two panes, left and right, 50% width each
- Left pane has all form fields
- Right pane has the artwork itself, and any contextual controls such as:
- Tokenized art: label indicatign that you can pan and zoom, "ai tokenize" button
- Portrait art: controls for background removal (not currently in this branch, ignore for now)
- Instead of a 'change artwork' menu, the first form field is 'base artwork', which is a form field of type "image". That is:
- Show the base artwork in a small thumbnail
- User can change the base artwork using the established methods: upload image from device, choose from library, google image search, etc
Sidebars
- [x] Selected Token will no longer show in a sidebar context, but instead will be a modal window that appears near the token selected.
- Spawn the window next to the token, smartly based on the camera. For instance, if the token is in the center of the screen, spawn the window to the right of the token. If the token is on the right edge of the screen, spawn the window to the left of the token, etc.
- The window shows the token's portrait art (fall back to token art), its name, and all properties in a scrollable list. - At the bottom edge of the window is a horizontal row of buttons:
- Actions: a menu showing the token's actions, which can be clicked to perform the action (token owner or campaign owner only)
- Conditions: a menu showing all conditions the token could have, with a toggleable checkbox to apply/remove the condition (token owner or campaign owner only)
- "...": has options for Edit (opens token modal), Delete (requires confirmation, already implemented), move/copy to map, view character sheet (if linked to a character), impersonate, change size (small, medium, large, etc)
- [x] Restore the sidebar for Library. It should already exist in the codebase. When the user selects 'open library' through the Start Menu or Command Palette, open the Library subcontext in the left sidebar.
- [x] Restore the sidebar for System. It should already exist in the codebase. When the user selects 'open system sidebar' in the Start Menu or Command Palette, open the System subcontext in the left sidebar.
- Additionally, links in the chat generated by actions which go to the system wiki (check for code that generates these) should open the system wiki in the system subcontext in the sidebar (which is an iframe), rather than a new tab.
- [x] Restore the Character Sheet sidebar. This should already exist in the codebase. When the user clicks "View Character Sheet" on a token context, open the character sheet in the left sidebar rather than a modal.
- [x] All of the above sidebars should be undockable, meaning the user can click a button to undock the sidebar and turn it into a movable, resizable window.
- [ ] Selected Token Modal should have a 'non-owner' context. If you don't own the token, you don't have access to actions, conditions, or edit options. However, you have options unique to this context, including:
- An 'attack' button, which spawns a list of actions you could use to attack this target. This also pre-selects the token as the target of the action, if the action has a target parameter.
Misc
- [x] In the 'connected users' popup in PlayTopBar, add a button to force all users to the current map (if you're the campaign owner).
- [x] Move undo/redo and the layer selector to be inline with the menu instead of pinned to the right
- [x] In retro theme, make CurrentTokenBar's bg color --mantine-color-dark-6 and use appropriate border color matching the retro theme
- [x] Add token decorations to indicate whose turn it is (a rotating circle around the token, similar to the selected token indicator).
- [x] Make the height of CurrentTokenBar adjustable by the user (persisting to local storage).
Target UI
- [x] Implement a "target" UI element. This will be in the upper right of the map frame, opposite the party view. It shows your selected token or tokens, using the same UI treatment as the party view.
- For both this view and the party view, add an icon button to each token's container that allows the user to choose one of their impersonated token's actions to perform on that target. I'm thinking this should use tabler icon "bolt".
- [x] In target UI and party UI, add a ... button to each container that spawns a menu with token options like "view character sheet", "edit token", "impersonate", "move to map", etc.
- [x] In target and party UI, prefer the portrait art (if present), and when using portrait art, expand it to touch the edges of the container without padding.
Token Properties
- [x] In all cases, when token properties are shown, they should have a different UI for changing them.
- The main property is shown as an input which can be changed in the normal manner.
-
- and - buttons will remain. But instead of being simple buttons, they are hit areas for popups. When + is hovered over (or touched on mobile):
- A popup appears with three options:
- A +1 button that works as the existing + button, incrementing the property by 1
- A +10 button that increments the property by 10
- A + button followed by an input field, allowing the user to specify any amount to increment by. Clicking the button applies the increment.
- All of the above options also work for the - button, but with decrementing instead of incrementing.
Undo/Redo
- [x] The undo/redo functionality for /play should also track token property updates
- [x] Bug: 'undo token deletion' shows up as an undo option (valid), but doesn't work. May need to be reconciled with recent "soft delete" functionality.
Performance Improvements
- [x] Migrate data-fetching hooks to React Query (
@tanstack/react-query, already installed but unused). This provides automatic request deduplication — if multiple components call the same hook, only one request fires.- [x] Create a shared
authFetchutility to replace the 30+ copy-pasted implementations across hooks - [x]
useConditions(40 calls) — convert touseQuerywith ~5minstaleTime(campaign-scoped, rarely changes mid-session) - [x]
useLightSourceTypes(33 calls) — convert touseQuerywith ~5minstaleTime - [x]
useVisionTypes(28 calls) — convert touseQuerywith ~5minstaleTime - [x]
usePropertyDefinitions(25 calls) — convert touseQuerywith ~5minstaleTime - [x]
useCampaignFunctions(16 calls) — convert touseQuerywith ~5minstaleTime - [x]
useBars(9 calls) — convert touseQuerywith ~5minstaleTime - [x]
useMaps(26 calls) — convert touseQuerywith ~2minstaleTime - [x]
useCampaigns(6 calls) — convert touseQuerywith ~2minstaleTime - [x]
useTokens(52 calls) — convert touseQueryfor initial fetch (keep Socket.io for real-time updates),staleTime: 0 - [x]
useFogOfWarShapes(25 calls) — convert touseQueryfor initial fetch (keep Socket.io),staleTime: 0 - [x]
useVBLShapes(24 calls) — convert touseQueryfor initial fetch (keep Socket.io),staleTime: 0 - [x]
useChatMessages(15 calls) — convert touseQueryfor initial fetch (keep Socket.io),staleTime: 0 - [x]
useCharacters(10 calls) — convert touseQuery(already has module-level cache, but React Query is more robust) - [x]
useDrawings(5 calls) — convert touseQuery - [x]
useMapObjects(3 calls) — convert touseQuery - [x]
useUserSettings(2 calls) — convert touseQuery(already has manual dedup, simplify with React Query)
- [x] Create a shared
- [x] Fix TopNav pending invitations polling: replace direct
useEffect+setIntervalfetch (126 calls with no dedup) with a React Query hook usingrefetchInterval: 30000. AusePendingCharacterInvitationshook already exists but is unused — wire it up or replace it. - [x] Remove
Content-Type: application/jsonheader from GET requests inauthFetchto avoid unnecessary CORS preflight (OPTIONS) requests, which currently double every API call.
Art Processing
- [x] When processing "portrait art" for a token or character, use an AI model to detect the subject of the portrait image.
- The UI for this is in the artwork editor (universal component found in places such as the edit token modal). When the user selects an artwork and designates it as "portrait" (as opposed to "token"), this triggers the background removal process.
- First attempt: MediaPipe Selfie Segmentation model in-browser
- If user wants a more precise cutout, second attempt: @huggingface/transformers with the BRIA RMBG-1.4 ONNX model (Uses the Sharp pipeline already in use on the backend). After the in-browser attempt, show the user the resulting cutout and add a button to further process on the backend.
- Once accepted, the resulting subject-only cutout is saved as a separate piece of artwork alongside the original full image. The user can toggle between these two versions in the UI (dropdown in the artwork editor).
- [x] CurrentTokenBar already uses the portrait art, but it should be updated to use the subject-only version when that option is selected, rather than the full image.
Styling Overhaul (major feature)
- [x] Removed Mantine's theming system in favor of a custom CSS variable-based token system, enabling multiple themeable skins and easier maintenance.
- [x] Created a new "Modern" skin with light/dark mode options, while preserving the existing "Retro" skin as the default. Users can switch skins via a new dropdown in the top nav (just left of the Clerk profile).
Style Changes
- [x] In the Chat Log, chat messages have a "bubble" appearance.
- The current user's bubbles emanate from the right side with no avatar and a distinct background color (customizable in Chat Settings).
- Impersonated tokens' messages emanate from the right side as well (when the user is the one doing the impersonation), using the token's color.
- All other messages emanate from the left side with the speaker's avatar and a different background color (standard, less emphasized, i.e. grey).
- The appearance of bubbles is similar to https://codepen.io/samuelkraft/pen/kYrjwX. To wit:
- Rounded rectangles
- Flat background, no border
- A tail pointing left or right depending on the speaker
- The standard Dice Roll UI (the one that spawns a modal called Dice Roll Details when clicked) will change its visual presentation:
- No border or bg color
- Instead of current display of (die roll) = result, it will show (same die roll graphic) + modifier = result.
- Die roll result graphic should have larger and bolder number (no change to the containing graphic)
API Refactors
- [x] Entity updates should use PATCH instead of PUT, and only send the fields that have changed, rather than the entire entity.
- [x] Server: Add PATCH routes alongside existing PUT routes for all entity types. PATCH handlers should validate partial payloads and merge with existing data. PUT routes can remain for backwards compatibility initially.
- [x]
useTokens.ts—updateToken(): Convert PUT/api/tokens/{id}to PATCH. Already receivesPartial<IToken>. High-frequency (drag, facing, properties). - [x]
TokenModal.tsx— Remove the monolithichandleSubmit()for edit mode. Instead, each field change (name, layer, size, artwork, etc.) should individually callupdateToken()via PATCH on change. The modal footer replaces the Save button with a status indicator ("Saving..." / "Up to date"). Create mode retains the Submit button and POSTs the full token. - [x]
useCharacters.ts—updateCharacter(): Convert PUT/api/characters/{id}to PATCH. Already receivesPartial<Character>. - [x]
useMaps.ts—updateMap(): Convert PUT/api/maps/{id}to PATCH. Already receivesPartial<IMap>. - [x]
useCampaigns.ts—updateCampaign(): Convert PUT/api/campaigns/{id}to PATCH. Already receivesPartial<ICampaign>. - [x]
useMapObjects.ts—updateMapObject(): Convert PUT/api/map-objects/{id}to PATCH. Already receivesPartial<IMapObject>. - [x]
useDrawings.ts—updateDrawing(): Convert PUT/api/drawings/{id}to PATCH. Has geometry merge logic that reconstructs full shape — may need server-side partial geometry merge. - [x]
useFogOfWarShapes.ts—updateShapeApi(): Convert PUT/api/fog-of-war-shapes/{id}to PATCH. Same geometry merge concern as drawings. - [x]
useVBLShapes.ts—updateShapeApi(): Convert PUT/api/vbl-shapes/{id}to PATCH. Same geometry merge concern. - [x]
useConditions.ts—updateCondition(): Convert PUT/api/conditions/{id}to PATCH. Already receivesPartial<ICondition>. - [x]
useUserSettings.ts—updateSettings(): Convert PUT/api/user-settingsto PATCH. Already receivesPartial<UserSettings>. - [x]
usePropertyDefinitions.ts—updatePropertyDefinition(): Convert PUT/api/campaigns/{cid}/property-definitions/{id}to PATCH. Already receivesPartial<IPropertyDefinition>. - [x]
useSystems.ts—updateSystem(): Convert PUT/api/systems/{id}to PATCH. Already receives partial fields. - [x]
useParties.ts—updateParty(): Convert PUT/api/parties/{id}to PATCH. Already receives{ name?, description? }. - [x]
useSystemTraits.ts— genericupdate(): Convert PUT to PATCH for all system trait endpoints (prop-types, property-definitions, conditions, bars, light-source-types, vision-types, functions). Already receivesPartial<T>. - [x]
useLightSourceTypes.ts—updateLightSourceType(): Convert PUT/api/campaigns/{cid}/light-source-types/{id}to PATCH. Already receivesPartial<ILightSourceType>. - [x]
useVisionTypes.ts—updateVisionType(): Convert PUT/api/campaigns/{cid}/vision-types/{id}to PATCH. Already receivesPartial<IVisionType>. - [x]
useChatMessages.ts—updateMessage(): Convert PUT/api/chat-messages/{id}to PATCH. Already sends only{ messageHtml }. - [x]
useBars.ts—updateBar(): Convert PUT/api/campaigns/{cid}/bars/{id}to PATCH. Already receivesPartial<IBar>. - [x]
usePropTypes.ts—updatePropType(): Convert PUT/api/campaigns/{cid}/prop-types/{id}to PATCH. Already receivesPartial<IPropType>.
- [x] Add (if not present) CRUD for the token artwork, so the entities can be updated independently of the token itself.
Bugs
- [x] Moving a background token doesn't count as an action to be undone; it should. (Ensure only the final move (x1,y1 -> x2,y2) is stored, not the individual mouse actions).
- [x] The sidebar contexts (e.g. ChatLog, TokenContext) are no longer scrollable. This may have been caused by the styling overhaul.