URL Scheme
All TaleSpire URLs start with talespire://
. From there on, we have some number of path segments.
We call the first path segment the "behavior identifier", this tells TaleSpire how to interpret the rest of the segments.
Example: talespire://dice/d12
(behavior identifier: dice
)
This gets TaleSpire to bring the dice rolls specified in the URL into the “tray” ready to be rolled
Note: Currently, we only support basic dice rolls with the "dice" behavior. In the future, we will support more complex dice rolls
Next, let's take a more complex URL and break it down. We'll use this as our example: talespire://dice/Eldritch%20Blast:1d10/4d6-1d4/4d10+2/3d20+1-d6+2
First we'll ignore the scheme and behavior identifier, which leaves us with these path segments: Eldritch%20Blast:1d10/4d6-1d4/4d10+2/3d20+1-d6+2
A dice group is parsed, right-to-left, case insensitively, with the following regex:
(\+|\-|)\d*D\d+(\+\d+|\-\d+|)
The C# code to do this is:
var diceGroup = Regex.Matches(pathSegment, @"(\+|\-|)(\d*)D(\d+)(\+\d+|\-\d+|)", RegexOptions.RightToLeft | RegexOptions.IgnoreCase);
The extra brackets in the C# regex above were added so that the Groups field contains the most useful data already separated. Naturally, you will need to reverse the results to get them in the correct order.
The regex is the most accurate specification, but here is a simpler (though maybe less precise) version with extra details:
[optional name + ":"][optional operator][optional count]D[sides][optional modifier]
where:
name
: a name can be added to a dice group which will name the roll in the chat/dice history, as well as show the name of the roll in the result pop-up after rollingoperator
: currently, the only operators supported are + and -count
: is the number of dice of that kind. Zero is not valid, but if it is not specified at all, then the count defaults to one.D
: is the only uppercase in the regex to clearly distinguish it from the \ds. The regex is always case insensitive.sides
: is the number of sides of the die. Currently we only support the standard TaleSpire dice. We will need to expand to support dice modding.modifier
: here, you can specify an integer to add or subtract. It is always of the form +N or -N where N is a positive integer.Example: talespire://asset/0b9f9061-a6e4-4126-829f-1deb43147f49
(behavior identifier: asset
)
The asset links are fairly straightforward: the path segment after the “asset” behavior identifier is simply the UUID of an asset. Once clicked and parsed by TaleSpire the asset of the corresponding UUID will be put into the hand ready to place.
Possible assets are Tiles, Props and Minis.
The asset UUIDs (as well as some other metadata) can be found in the index.json file inside TaleSpire’s install directory.
Example: talespire://published-board/TGVwaWRzdGFkdA==/c82b15b84b2fbebfb33929922c9f3fbe
(behavior identifier: published-board
)
These are links to board shares. As opposed to slab strings which contain all the necessary tile data within themselves, board shares are simply unique links to representations of a board stored on our servers. Clicking the link will cause TaleSpire to create a (shallow) copy of the board. Editing anything on the board as the one who shared it will not update the shared board state.
The anatomy of the url is as follows:
talespire://published-board/[encoded-name]/[published-board-id]
Example: talespire://goto/bookmark/89d1e76a49688d42b5ce62ae511415d6
(behavior identifier: goto/bookmark
)
Clicking the link causes TaleSpire to move the camera to the bookmark with the linked ID
The anatomy of the URL is as follows:
talespire://goto/bookmark/[bookmark-id]
The bookmark id is a hex representation of a 16 byte ID. The ID refers to a bookmark on the server.
Example: talespire://stat-names/AQAIBENvb2wEU3RhdAVOYW1lcwRUaGF0A0NhbgJCZQZDb3BpZWQDTm93
(behavior identifier: stat-names
)
This tells TaleSpire to update the currently open campaign’s stat name setup. The stat names are base64 encoded into the URL and can be extracted directly.
The anatomy of the URL is as follows:
talespire://stat-names/[stats-data]
the stats-data is a base64 encoded string
Processing the string:
The resulting binary data is laid out as follows:
version :: u16 - This is currently 1 number-of-stats :: u8 names :: utf8-string[number-of-stats] utf8-string is laid out as follows: byte-count :: u8 - value of 255 means string was null utf8-data :: u8[byte-count] > We use the following notation above > u8: 8bit unsigned integer (byte in c#) > u16: 16bit unsigned integer (ushort in c#)
Example: talespire://creature-blueprint/AgD_AQAAACEAOmExMjcxNGQ3MzU1NWE3NGY4MmQ3NGNhMWU3NWVkYmZkAQAAAABh+rL0znE5RrynJkTEzlgPAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIEEAACBBAAAgQQAAIEEAACBBAAAgQQAAIEEAACBBAAAgQQAAIEEAACBBAAAgQQAAIEEAACBBAAAgQQAAIEEAACBBAAAgQQAAAA==
(behavior identifier: creature-blueprint
)
When you copy a creature, TaleSpire saves a blueprint of the creature to the system clipboard in the form of a creature-blueprint URL.
The anatomy of the URL is as follows:
talespire://creature-blueprint/[blueprint-data]
the blueprint-data is a base64 encoded string
Processing the string:
The resulting binary data is laid out as follows:
version :: u16 - 1 alias :: utf8-string - this string MUST be <= 150 in length number-of-morph-ids :: u8 - this number MUST be <= 10 morph-ids :: uuid[number-of-morph-ids] active-morph-index :: u8 morph-scales :: packed-morph-scales RESERVED :: u16 RESERVED :: u16 RESERVED :: u16 RESERVED :: u16 RESERVED :: u16 RESERVED :: u16 RESERVED :: u16 RESERVED :: u16 RESERVED :: u8[3] hp :: stat stat-0 :: stat stat-1 :: stat stat-2 :: stat stat-3 :: stat stat-4 :: stat stat-5 :: stat stat-6 :: stat stat-7 :: stat torch-hide-fly-state :: torch-hide-fly-state number-of-emote-slot-overrides :: u8 - this number MUST be <= 16 slot-overrides :: slot-override[number-of-emote-slot-overrides] number-of-active-emote-ids :: u8 - this number MUST be <= 16 active-emote-ids :: uuid[number-of-active-emote-ids] utf8-string is laid out as follows: byte-count :: u8 utf8-data :: u8[byte-count] packed-morph-scales is a u64 with data bit-packed into it. It stores up to 10 scales, each taking 6 bits: to get the nth scale you: - shift out the 6 bits you are interested in - divide the value by 4 to get the scale stat is laid out as follows: value :: f32 max :: f32 torch-hide-fly-state is a u8 with data bit-packed into it. bit 0: torch enabled bit 1: explicitly hidden bit 2: flying enabled slot-override is laid out as follows: id :: uuid index :: u16 e.g. ((packed-morph-scales >> (6 * n)) & 0b111111) / 4f > We use the following notation above > > u8: 8bit unsigned integer (byte in c#) > u16: 16bit unsigned integer (ushort in c#) > u32: 32bit unsigned integer (uint in c#) > u64: 64bit unsigned integer (ulong in c#) > f32: 32bit ieee754 binary floating point number (float in c#) > uuid: 128bit id
Version 2
version :: u16 - 2 alias :: utf8-small-string - this string must be <= 150 in length number-of-content-packs :: i32 content-pack-uris :: utf8-string[number-of-content-packs] - each string must be <= 65535 in length number-of-morphs :: u8 - this number MUST be <= 10 morphs :: morph[number-of-morphs] active-morph-index :: u8 morph-scales :: packed-morph-scales RESERVED :: u16 RESERVED :: u16 RESERVED :: u16 RESERVED :: u16 RESERVED :: u16 RESERVED :: u16 RESERVED :: u16 RESERVED :: u16 RESERVED :: u8[3] hp :: stat stat-0 :: stat stat-1 :: stat stat-2 :: stat stat-3 :: stat stat-4 :: stat stat-5 :: stat stat-6 :: stat stat-7 :: stat torch-hide-fly-state :: torch-hide-fly-state number-of-emote-slot-overrides :: u8 - this number MUST be <= 16 slot-overrides :: slot-override[number-of-emote-slot-overrides] number-of-active-emote-ids :: u8 - this number MUST be <= 16 active-emote-ids :: uuid[number-of-active-emote-ids] --- utf8-small-string is laid out as follows: byte-count :: u8 - value of 255 means string was null utf8-data :: u8[byte-count] utf8-string is laid out as follows: byte-count :: u16 utf8-data :: u8[byte-count] morph is laid out as follows: content-pack-index :: i32 - index in the previous content-pack-uris array content-id :: uuid packed-morph-scales is a u64 with data bit-packed into it. It stores up to 10 scales, each taking 6 bits: to get the nth scale you: - shift out the 6 bits you are interested in - divide the value by 4 to get the scale e.g. ((packed-morph-scales >> (6 * n)) & 0b111111) / 4f stat is laid out as follows: value :: f32 max :: f32 torch-hide-fly-state is a u8 with data bit-packed into it. bit 0: torch enabled bit 1: explicitly hidden bit 2: flying enabled slot-override is laid out as follows: id :: uuid index :: u16 > We use the following notation above > > u8: 8bit unsigned integer (byte in c#) > u16: 16bit unsigned integer (ushort in c#) > i32: 32bit signed integer (int in c#) > u32: 32bit unsigned integer (uint in c#) > u64: 64bit unsigned integer (ulong in c#) > f32: 32bit ieee754 binary floating point number (float in c#) > uuid: 128bit idData field explanation:
alias
: Is the name of the mini. This refers to the manually assigned name (by the user), not the name of the asset and will be empty (length = "-1" = 255, no content) if no alias was set on the mini.The URLs get passed onto TaleSpire by adding a registry key on install that tells Windows what .exe to run when a talespire://
URL is launched. As we don't want lots of copies of TaleSpire starting we have TaleSpireUrlRelay.exe, which either:
Using the Links from typical browsers is as simple as clicking on it, and telling the browser to allow to open talespire:// links with the TaleSpireUrlRelay.exe (and for convenience possibly also allow to always do that without asking).
Notes: TaleSpire must not be run as administrator for the TaleSpireUrlRelay to work (unless the Relay is also run as administrator)While Linux support isn’t official, TaleSpire does run pretty well using Steam Proton and we are looking into officially supporting Linux (via Proton) in the future. However, the registry keys for Windows obviously don’t work when installing on Linux, so to get the URL relay to work you have to tell your Linux system to forward the talespire://
scheme to the UrlRelay (and open said Relay using Wine).
LividJava from the Discord Community has created a shell script to automatically create the needed desktop entry for getting TaleSpire URLs work - you can get the newest version of it from GitHub: https://github.com/LividJava/talespire-linux-uri
Keep in mind that this is code written by community members so no guarantees for safety and correctness can be given! Check the script yourself, or follow the instructions for setting it up manually:
For manual registration of the link forwarding you need to create a .desktop file at ~/.local/share/applications/xdg-talespire.desktop
:
[Desktop Entry] Type=Application Name=TaleSpire Exec=/bin/bash -c 'env WINEPREFIX="/home/$USER/.steam/steam/steamapps/compatdata/720620/pfx" WINEESYNC=1 "/home/$USER/.steam/steam/steamapps/common/Proton 6.13/dist/bin/wine64" "/home/$USER/.steam/steam/steamapps/common/TaleSpire/TaleSpireUrlRelay.exe" %u' StartupNotify=false MimeType=x-scheme-handler/talespire;
And then add the mime type to xdg:
xdg-mime default xdg-talespire.desktop x-scheme-handler/talespire
Of note:
WINEPREFIX
(= Wine’s working directory) depends on the install location of TaleSpire (which “library folder” in Steam it’s installed to), in the example above shows the default location in ~/.steam/
. The same obviously also applies to the path to the TaleSpireUrlRelay.exe.WINEFSYNC=1
instead of WINEESYNC=1
.