+11
.tangled/workflows/test-api.yaml
+11
.tangled/workflows/test-api.yaml
+13
.tangled/workflows/test-web.yaml
+13
.tangled/workflows/test-web.yaml
+11
LICENSE
+11
LICENSE
···
1
+
Copyright 2025 Naomi Roberts
2
+
3
+
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
4
+
5
+
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
6
+
7
+
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
8
+
9
+
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
10
+
11
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+22
README.md
+22
README.md
···
1
+
# Katari
2
+
3
+
A collection of utilities for using/interfacing with the Daggerheart SRD.
4
+
5
+
## Utilities
6
+
7
+
### [`/api/`](/api)
8
+
9
+
Hostable JSON API for the SRD.
10
+
11
+
### [`/web/`](/web)
12
+
13
+
Hostable website for browsing the SRD and optionally the API documentation.
14
+
15
+
### [`/srd/`](/srd)
16
+
17
+
The Daggerheart SRD in JSON form.
18
+
19
+
## Licencing
20
+
Some content in this repository, under the `srd` directory, is licensed under the Darrington Press Community Gaming License (DPCGL) found [here](https://darringtonpress.com/license/). Modifications to the data's format have been made, but nothing to the content itself.
21
+
22
+
Everything else in this repository is under the 3-Clause BSD License (BSD-3-Clause).
+1
api/.gitignore
+1
api/.gitignore
···
1
+
build/
+13
api/README.md
+13
api/README.md
···
1
+
# API
2
+
3
+
Simple API that serves a copy of Daggerheart's SRD in JSON
4
+
5
+
## Requirements
6
+
- Gleam v1.12.0 or greater
7
+
8
+
## Running
9
+
```bash
10
+
gleam run
11
+
```
12
+
13
+
If using a non-standard location for your SRD directory, this can be specified with the `KATARI_SRD_PATH`. It will default to `../srd` otherwise.
+26
api/gleam.toml
+26
api/gleam.toml
···
1
+
name = "api"
2
+
version = "1.0.0"
3
+
4
+
# Fill out these fields if you intend to generate HTML documentation or publish
5
+
# your project to the Hex package manager.
6
+
#
7
+
# description = ""
8
+
# licences = ["Apache-2.0"]
9
+
# repository = { type = "github", user = "", repo = "" }
10
+
# links = [{ title = "Website", href = "" }]
11
+
#
12
+
# For a full reference of all the available options, you can have a look at
13
+
# https://gleam.run/writing-gleam/gleam-toml/.
14
+
15
+
[dependencies]
16
+
gleam_stdlib = ">= 0.44.0 and < 2.0.0"
17
+
wisp = ">= 1.8.0 and < 2.0.0"
18
+
mist = ">= 5.0.3 and < 6.0.0"
19
+
gleam_erlang = ">= 1.3.0 and < 2.0.0"
20
+
gleam_http = ">= 4.1.1 and < 5.0.0"
21
+
gleam_json = ">= 3.0.2 and < 4.0.0"
22
+
envoy = ">= 1.0.2 and < 2.0.0"
23
+
shared = { path = "../shared" }
24
+
25
+
[dev-dependencies]
26
+
gleeunit = ">= 1.0.0 and < 2.0.0"
+40
api/manifest.toml
+40
api/manifest.toml
···
1
+
# This file was generated by Gleam
2
+
# You typically do not need to edit this file
3
+
4
+
packages = [
5
+
{ name = "directories", version = "1.2.0", build_tools = ["gleam"], requirements = ["envoy", "gleam_stdlib", "platform", "simplifile"], otp_app = "directories", source = "hex", outer_checksum = "D13090CFCDF6759B87217E8DDD73A75903A700148A82C1D33799F333E249BF9E" },
6
+
{ name = "envoy", version = "1.0.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "envoy", source = "hex", outer_checksum = "95FD059345AA982E89A0B6E2A3BF1CF43E17A7048DCD85B5B65D3B9E4E39D359" },
7
+
{ name = "exception", version = "2.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "exception", source = "hex", outer_checksum = "329D269D5C2A314F7364BD2711372B6F2C58FA6F39981572E5CA68624D291F8C" },
8
+
{ name = "filepath", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "B06A9AF0BF10E51401D64B98E4B627F1D2E48C154967DA7AF4D0914780A6D40A" },
9
+
{ name = "gleam_crypto", version = "1.5.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_crypto", source = "hex", outer_checksum = "50774BAFFF1144E7872814C566C5D653D83A3EBF23ACC3156B757A1B6819086E" },
10
+
{ name = "gleam_erlang", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "1124AD3AA21143E5AF0FC5CF3D9529F6DB8CA03E43A55711B60B6B7B3874375C" },
11
+
{ name = "gleam_http", version = "4.1.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_http", source = "hex", outer_checksum = "DD0271B32C356FB684EC7E9F48B1E835D0480168848581F68983C0CC371405D4" },
12
+
{ name = "gleam_json", version = "3.0.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "874FA3C3BB6E22DD2BB111966BD40B3759E9094E05257899A7C08F5DE77EC049" },
13
+
{ name = "gleam_otp", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "7987CBEBC8060B88F14575DEF546253F3116EBE2A5DA6FD82F38243FCE97C54B" },
14
+
{ name = "gleam_stdlib", version = "0.62.1", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "0080706D3A5A9A36C40C68481D1D231D243AF602E6D2A2BE67BA8F8F4DFF45EC" },
15
+
{ name = "gleam_yielder", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_yielder", source = "hex", outer_checksum = "8E4E4ECFA7982859F430C57F549200C7749823C106759F4A19A78AEA6687717A" },
16
+
{ name = "gleeunit", version = "1.6.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "FDC68A8C492B1E9B429249062CD9BAC9B5538C6FBF584817205D0998C42E1DAC" },
17
+
{ name = "glisten", version = "8.0.1", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_otp", "gleam_stdlib", "logging", "telemetry"], otp_app = "glisten", source = "hex", outer_checksum = "534BB27C71FB9E506345A767C0D76B17A9E9199934340C975DC003C710E3692D" },
18
+
{ name = "gramps", version = "6.0.0", build_tools = ["gleam"], requirements = ["gleam_crypto", "gleam_erlang", "gleam_http", "gleam_stdlib"], otp_app = "gramps", source = "hex", outer_checksum = "8B7195978FBFD30B43DF791A8A272041B81E45D245314D7A41FC57237AA882A0" },
19
+
{ name = "houdini", version = "1.2.0", build_tools = ["gleam"], requirements = [], otp_app = "houdini", source = "hex", outer_checksum = "5DB1053F1AF828049C2B206D4403C18970ABEF5C18671CA3C2D2ED0DD64F6385" },
20
+
{ name = "hpack_erl", version = "0.3.0", build_tools = ["rebar3"], requirements = [], otp_app = "hpack", source = "hex", outer_checksum = "D6137D7079169D8C485C6962DFE261AF5B9EF60FBC557344511C1E65E3D95FB0" },
21
+
{ name = "logging", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "logging", source = "hex", outer_checksum = "1098FBF10B54B44C2C7FDF0B01C1253CAFACDACABEFB4B0D027803246753E06D" },
22
+
{ name = "marceau", version = "1.3.0", build_tools = ["gleam"], requirements = [], otp_app = "marceau", source = "hex", outer_checksum = "2D1C27504BEF45005F5DFB18591F8610FB4BFA91744878210BDC464412EC44E9" },
23
+
{ name = "mist", version = "5.0.3", build_tools = ["gleam"], requirements = ["exception", "gleam_erlang", "gleam_http", "gleam_otp", "gleam_stdlib", "gleam_yielder", "glisten", "gramps", "hpack_erl", "logging"], otp_app = "mist", source = "hex", outer_checksum = "7C4BE717A81305323C47C8A591E6B9BA4AC7F56354BF70B4D3DF08CC01192668" },
24
+
{ name = "platform", version = "1.0.0", build_tools = ["gleam"], requirements = [], otp_app = "platform", source = "hex", outer_checksum = "8339420A95AD89AAC0F82F4C3DB8DD401041742D6C3F46132A8739F6AEB75391" },
25
+
{ name = "shared", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib", "simplifile"], source = "local", path = "../shared" },
26
+
{ name = "simplifile", version = "2.3.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "0A868DAC6063D9E983477981839810DC2E553285AB4588B87E3E9C96A7FB4CB4" },
27
+
{ name = "telemetry", version = "1.3.0", build_tools = ["rebar3"], requirements = [], otp_app = "telemetry", source = "hex", outer_checksum = "7015FC8919DBE63764F4B4B87A95B7C0996BD539E0D499BE6EC9D7F3875B79E6" },
28
+
{ name = "wisp", version = "1.8.0", build_tools = ["gleam"], requirements = ["directories", "exception", "gleam_crypto", "gleam_erlang", "gleam_http", "gleam_json", "gleam_stdlib", "houdini", "logging", "marceau", "mist", "simplifile"], otp_app = "wisp", source = "hex", outer_checksum = "0FE9049AFFB7C8D5FC0B154EEE2704806F4D51B97F44925D69349B3F4F192957" },
29
+
]
30
+
31
+
[requirements]
32
+
envoy = { version = ">= 1.0.2 and < 2.0.0" }
33
+
gleam_erlang = { version = ">= 1.3.0 and < 2.0.0" }
34
+
gleam_http = { version = ">= 4.1.1 and < 5.0.0" }
35
+
gleam_json = { version = ">= 3.0.2 and < 4.0.0" }
36
+
gleam_stdlib = { version = ">= 0.44.0 and < 2.0.0" }
37
+
gleeunit = { version = ">= 1.0.0 and < 2.0.0" }
38
+
mist = { version = ">= 5.0.3 and < 6.0.0" }
39
+
shared = { path = "../shared" }
40
+
wisp = { version = ">= 1.8.0 and < 2.0.0" }
+26
api/src/api.gleam
+26
api/src/api.gleam
···
1
+
import api/router
2
+
import envoy
3
+
import gleam/erlang/process
4
+
import gleam/result
5
+
import mist
6
+
import shared/data
7
+
import wisp
8
+
import wisp/wisp_mist
9
+
10
+
pub fn main() {
11
+
wisp.configure_logger()
12
+
let skb = wisp.random_string(64)
13
+
14
+
let data_dir = result.unwrap(envoy.get("KATARI_SRD_PATH"), "../srd/")
15
+
16
+
let assert Ok(data) = data.read_data_dir(data_dir)
17
+
as { "Failed to read data directory " <> data_dir }
18
+
19
+
let assert Ok(_) =
20
+
wisp_mist.handler(router.handle_request(_, data), skb)
21
+
|> mist.new()
22
+
|> mist.port(8000)
23
+
|> mist.start()
24
+
25
+
Ok(process.sleep_forever())
26
+
}
+18
api/src/api/router.gleam
+18
api/src/api/router.gleam
···
1
+
import api/routes/abilities
2
+
import api/routes/classes
3
+
import api/web
4
+
import gleam/http
5
+
import shared/data
6
+
import wisp
7
+
8
+
pub fn handle_request(req: wisp.Request, data: data.Data) -> wisp.Response {
9
+
use req <- web.middleware(req)
10
+
use <- wisp.require_method(req, http.Get)
11
+
case wisp.path_segments(req) {
12
+
["abilities"] -> abilities.all(data)
13
+
["abilities", id] -> abilities.single(data, id)
14
+
["classes"] -> classes.all(data)
15
+
["classes", id] -> classes.single(data, id)
16
+
_ -> wisp.not_found()
17
+
}
18
+
}
+25
api/src/api/routes/abilities.gleam
+25
api/src/api/routes/abilities.gleam
···
1
+
import gleam/json
2
+
import gleam/list
3
+
import shared/ability
4
+
import shared/data
5
+
import wisp
6
+
7
+
pub fn all(data: data.Data) {
8
+
let json = json.array(data.abilities, ability.ability_to_json)
9
+
wisp.json_response(json.to_string_tree(json), 200)
10
+
}
11
+
12
+
pub fn single(data: data.Data, id: String) {
13
+
let single =
14
+
data.abilities
15
+
|> list.find(fn(ability: ability.Ability) { ability.id == id })
16
+
17
+
case single {
18
+
Ok(ability) ->
19
+
wisp.json_response(
20
+
json.to_string_tree(ability.ability_to_json(ability)),
21
+
200,
22
+
)
23
+
_ -> wisp.not_found()
24
+
}
25
+
}
+22
api/src/api/routes/classes.gleam
+22
api/src/api/routes/classes.gleam
···
1
+
import gleam/json
2
+
import gleam/list
3
+
import shared/class
4
+
import shared/data
5
+
import wisp
6
+
7
+
pub fn all(data: data.Data) {
8
+
let json = json.array(data.classes, class.class_to_json)
9
+
wisp.json_response(json.to_string_tree(json), 200)
10
+
}
11
+
12
+
pub fn single(data: data.Data, id: String) {
13
+
let single =
14
+
data.classes
15
+
|> list.find(fn(class: class.Class) { class.id == id })
16
+
17
+
case single {
18
+
Ok(class) ->
19
+
wisp.json_response(json.to_string_tree(class.class_to_json(class)), 200)
20
+
_ -> wisp.not_found()
21
+
}
22
+
}
+12
api/src/api/web.gleam
+12
api/src/api/web.gleam
···
1
+
import wisp
2
+
3
+
pub fn middleware(
4
+
req: wisp.Request,
5
+
handle_request: fn(wisp.Request) -> wisp.Response,
6
+
) {
7
+
let req = wisp.method_override(req)
8
+
use <- wisp.log_request(req)
9
+
use <- wisp.rescue_crashes()
10
+
use req <- wisp.handle_head(req)
11
+
handle_request(req)
12
+
}
+13
api/test/api_test.gleam
+13
api/test/api_test.gleam
+27
flake.lock
+27
flake.lock
···
1
+
{
2
+
"nodes": {
3
+
"nixpkgs": {
4
+
"locked": {
5
+
"lastModified": 1755577059,
6
+
"narHash": "sha256-5hYhxIpco8xR+IpP3uU56+4+Bw7mf7EMyxS/HqUYHQY=",
7
+
"owner": "NixOS",
8
+
"repo": "nixpkgs",
9
+
"rev": "97eb7ee0da337d385ab015a23e15022c865be75c",
10
+
"type": "github"
11
+
},
12
+
"original": {
13
+
"owner": "NixOS",
14
+
"ref": "nixpkgs-unstable",
15
+
"repo": "nixpkgs",
16
+
"type": "github"
17
+
}
18
+
},
19
+
"root": {
20
+
"inputs": {
21
+
"nixpkgs": "nixpkgs"
22
+
}
23
+
}
24
+
},
25
+
"root": "root",
26
+
"version": 7
27
+
}
+26
flake.nix
+26
flake.nix
···
1
+
{
2
+
inputs = {
3
+
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
4
+
};
5
+
6
+
outputs = {nixpkgs, ...} @ inputs: let
7
+
lib = nixpkgs.lib;
8
+
supportedSystems = ["x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin"];
9
+
forEachSupportedSystem = f:
10
+
lib.genAttrs supportedSystems (system:
11
+
f {
12
+
pkgs = import nixpkgs {inherit system;};
13
+
});
14
+
in {
15
+
devShells = forEachSupportedSystem ({pkgs}: {
16
+
default = pkgs.mkShell {
17
+
packages = with pkgs; [
18
+
gleam
19
+
erlang_28
20
+
beam28Packages.rebar3
21
+
jq
22
+
];
23
+
};
24
+
});
25
+
};
26
+
}
+8
srd/abilities/a-soldiers-bond.json
+8
srd/abilities/a-soldiers-bond.json
+8
srd/abilities/adjust-reality.json
+8
srd/abilities/adjust-reality.json
···
1
+
{
2
+
"id": "adjust-reality",
3
+
"name": "Adjust Reality",
4
+
"domain": "arcana",
5
+
"level": 10,
6
+
"recall_cost": 1,
7
+
"description": "After you or a willing ally make any roll, you can spend 5 Hope to change the numerical result of that roll to a result of your choice instead. The result must be plausible within the range of the dice."
8
+
}
+8
srd/abilities/arcana-touched.json
+8
srd/abilities/arcana-touched.json
···
1
+
{
2
+
"id": "arcana-touched",
3
+
"name": "Arcana-Touched",
4
+
"domain": "arcana",
5
+
"level": 7,
6
+
"recall_cost": 2,
7
+
"description": "When 4 or more of the domain cards in your loadout are from the Arcana domain, gain the following benefits:\n- +1 bonus to your Spellcast Rolls\n- Once per rest, you can switch the results of your Hope and Fear Dice."
8
+
}
+8
srd/abilities/arcane-reflection.json
+8
srd/abilities/arcane-reflection.json
···
1
+
{
2
+
"id": "arcane-reflection",
3
+
"name": "Arcane Reflection",
4
+
"domain": "arcana",
5
+
"level": 8,
6
+
"recall_cost": 1,
7
+
"description": "When you would take magic damage, you can spend any number of Hope to roll that many d6s. If any roll a 6, the attack is reflected back to the caster, dealing the damage to them instead."
8
+
}
+8
srd/abilities/armorer.json
+8
srd/abilities/armorer.json
···
1
+
{
2
+
"id": "armorer",
3
+
"name": "Armorer",
4
+
"domain": "valor",
5
+
"level": 5,
6
+
"recall_cost": 1,
7
+
"description": "While you’re wearing armor, gain a +1 bonus to your Armor Score.\nDuring a rest, when you choose to repair your armor as a downtime move, your allies also clear an Armor Slot."
8
+
}
+8
srd/abilities/astral-projection.json
+8
srd/abilities/astral-projection.json
···
1
+
{
2
+
"id": "astral-projection",
3
+
"name": "Astral Projection",
4
+
"domain": "grace",
5
+
"level": 8,
6
+
"recall_cost": 0,
7
+
"description": "Once per long rest, mark a Stress to create a projected copy of yourself that can appear anywhere you’ve been before.\nYou can see and hear through the projection as though it were you and affect the world as though you were there. A creature investigating the projection can tell it’s of magical origin. This effect lasts until your next rest or your projection takes any damage."
8
+
}
+8
srd/abilities/banish.json
+8
srd/abilities/banish.json
···
1
+
{
2
+
"id": "banish",
3
+
"name": "Banish",
4
+
"domain": "codex",
5
+
"level": 6,
6
+
"recall_cost": 0,
7
+
"description": "Make a Spellcast Roll against a target within Close range. On a success, roll a number of d20s equal to your Spellcast trait. The target must make a reaction roll with a Difficulty equal to your highest result. On a success, the target must mark a Stress but isn’t banished. Once per rest on a failure, they are banished from this realm.\nWhen the PCs roll with Fear, the Difficulty gains a -1 penalty and the target makes another reaction roll. On a success, they return from banishment."
8
+
}
+8
srd/abilities/bare-bones.json
+8
srd/abilities/bare-bones.json
···
1
+
{
2
+
"id": "bare-bones",
3
+
"name": "Bare Bones",
4
+
"domain": "valor",
5
+
"level": 1,
6
+
"recall_cost": 0,
7
+
"description": "When you choose not to equip armor, you have a base Armor Score of 3 + your Strength and use the following as your base damage thresholds:\n- Tier 1: 9/19\n- Tier 2: 11/24\n- Tier 3: 13/31\n- Tier 4: 15/35"
8
+
}
+8
srd/abilities/battle-cry.json
+8
srd/abilities/battle-cry.json
···
1
+
{
2
+
"id": "battle-cry",
3
+
"name": "Battle Cry",
4
+
"domain": "blade",
5
+
"level": 8,
6
+
"recall_cost": 1,
7
+
"description": "Once per long rest, while you’re charging into danger, you can muster a rousing call that inspires your allies. All allies who can hear you each clear a Stress and gain a Hope. Additionally, your allies gain advantage on attack rolls until you or an ally rolls a failure with Fear."
8
+
}
+8
srd/abilities/battle-hardened.json
+8
srd/abilities/battle-hardened.json
+8
srd/abilities/battle-monster.json
+8
srd/abilities/battle-monster.json
···
1
+
{
2
+
"id": "battle-monster",
3
+
"name": "Battle Monster",
4
+
"domain": "blade",
5
+
"level": 10,
6
+
"recall_cost": 0,
7
+
"description": "When you make a successful attack against an adversary, you can mark 4 Stress to force the target to mark a number of Hit Points equal to the number of Hit Points you currently have marked instead of rolling for damage."
8
+
}
+8
srd/abilities/blade-touched.json
+8
srd/abilities/blade-touched.json
···
1
+
{
2
+
"id": "blade-touched",
3
+
"name": "Blade-Touched",
4
+
"domain": "blade",
5
+
"level": 7,
6
+
"recall_cost": 1,
7
+
"description": "When 4 or more of the domain cards in your loadout are from the Blade domain, gain the following benefits:\n- +2 bonus to your attack rolls\n- +4 bonus to your Severe damage threshold"
8
+
}
+8
srd/abilities/blink-out.json
+8
srd/abilities/blink-out.json
···
1
+
{
2
+
"id": "blink-out",
3
+
"name": "Blink Out",
4
+
"domain": "arcana",
5
+
"level": 4,
6
+
"recall_cost": 1,
7
+
"description": "Make a Spellcast Roll (12). On a success, spend a Hope to teleport to another point you can see within Far range. If any willing creatures are within Very Close range, spend an additional Hope for each creature to bring them with you."
8
+
}
+8
srd/abilities/body-basher.json
+8
srd/abilities/body-basher.json
···
1
+
{
2
+
"id": "body-basher",
3
+
"name": "Body Basher",
4
+
"domain": "valor",
5
+
"level": 2,
6
+
"recall_cost": 1,
7
+
"description": "You use the full force of your body in a fight. On a successful attack using a weapon with a Melee range, gain a bonus to your damage roll equal to your Strength."
8
+
}
+8
srd/abilities/bold-presence.json
+8
srd/abilities/bold-presence.json
···
1
+
{
2
+
"id": "bold-presence",
3
+
"name": "Bold Presence",
4
+
"domain": "valor",
5
+
"level": 2,
6
+
"recall_cost": 0,
7
+
"description": "When you make a Presence Roll, you can spend a Hope to add your Strength to the roll.\nAdditionally, once per rest when you would gain a condition, you can describe how your bold presence aids you in the situation and avoid gaining the condition."
8
+
}
+8
srd/abilities/bolt-beacon.json
+8
srd/abilities/bolt-beacon.json
···
1
+
{
2
+
"id": "bolt-beacon",
3
+
"name": "Bold Beacon",
4
+
"domain": "splendor",
5
+
"level": 1,
6
+
"recall_cost": 1,
7
+
"description": "Make a Spellcast Roll against a target within Far range. On a success, spend a Hope to send a bolt of shimmering light toward them, dealing 6d8+2 magic damage using your Proficiency. The target becomes temporarily Vulnerable and glows brightly until this condition is cleared."
8
+
}
+8
srd/abilities/bone-touched.json
+8
srd/abilities/bone-touched.json
···
1
+
{
2
+
"id": "bone-touched",
3
+
"name": "Bone-Touched",
4
+
"domain": "bone",
5
+
"level": 7,
6
+
"recall_cost": 2,
7
+
"description": "When 4 or more of the domain cards in your loadout are from the Bone domain, gain the following benefits:\n- +1 bonus to Agility\n- Once per rest, you can spend 3 Hope to cause an attack that succeeded against you to fail instead."
8
+
}
+8
srd/abilities/book-of-ava.json
+8
srd/abilities/book-of-ava.json
···
1
+
{
2
+
"id": "book-of-ava",
3
+
"name": "Book of Ava",
4
+
"domain": "codex",
5
+
"level": 1,
6
+
"recall_cost": 2,
7
+
"description": "**Power Push:** Make a Spellcast Roll against a target within Melee range. On a success, they’re knocked back to Far range and take d10+2 magic damage using your Proficiency.\n**Tova’s Armor:** Spend a Hope to give a target you can touch a +1 bonus to their Armor Score until their next rest or you cast Tova’s Armor again.\n**Ice Spike:** Make a Spellcast Roll (12) to summon a large ice spike within Far range. If you use it as a weapon, make the Spellcast Roll against the target’s Difficulty instead. On a success, deal d6 physical damage using your Proficiency."
8
+
}
+8
srd/abilities/book-of-exota.json
+8
srd/abilities/book-of-exota.json
···
1
+
{
2
+
"id": "book-of-exota",
3
+
"name": "Book of Exota",
4
+
"domain": "codex",
5
+
"level": 4,
6
+
"recall_cost": 3,
7
+
"description": "**Repudiate:** You can interrupt a magical effect taking place. Make a reaction roll using your Spellcast trait. Once per rest on a success, the effect stops and any consequences are avoided.\n**Create Construct:** Spend a Hope to choose a group of objects around you and create an animated construct from them that obeys basic commands. Make a Spellcast Roll to command them to take action. When necessary, they share your Evasion and traits and their attacks deal 2d10+3 physical damage. You can only maintain one construct at a time, and they fall apart when they take any amount of damage."
8
+
}
+8
srd/abilities/book-of-grynn.json
+8
srd/abilities/book-of-grynn.json
···
1
+
{
2
+
"id": "book-of-grynn",
3
+
"name": "Book of Grynn",
4
+
"domain": "codex",
5
+
"level": 4,
6
+
"recall_cost": 2,
7
+
"description": "**Arcane Deflection:** Once per long rest, spend a Hope to negate the damage of an attack targeting you or an ally within Very Close range.\n**Time Lock:** Target an object within Far range. That object stops in time and space exactly where it is until your next rest. If a creature tries to move it, make a Spellcast Roll against them to maintain this spell.\n**Wall of Flame:** Make a Spellcast Roll (15). On a success, create a temporary wall of magical flame between two points within Far range. All creatures in its path must choose a side to be on, and anything that subsequently passes through the wall takes 4d10+3 magic damage."
8
+
}
+8
srd/abilities/book-of-homet.json
+8
srd/abilities/book-of-homet.json
···
1
+
{
2
+
"id": "book-of-homet",
3
+
"name": "Book of Homet",
4
+
"domain": "codex",
5
+
"level": 7,
6
+
"recall_cost": 0,
7
+
"description": "**Pass Through:** Make a Spellcast Roll (13). Once per rest on a success, you and all creatures touching you can pass through a wall or door within Close range. The effect ends once everyone is on the other side.**Plane Gate:** Make a Spellcast Roll (14). Once per long rest on a success, open a gateway to a location in another dimension or plane of existence you’ve been to before. This gateway lasts until your next rest."
8
+
}
+8
srd/abilities/book-of-illiat.json
+8
srd/abilities/book-of-illiat.json
···
1
+
{
2
+
"id": "book-of-illiat",
3
+
"name": "Book of Illiat",
4
+
"domain": "codex",
5
+
"level": 1,
6
+
"recall_cost": 2,
7
+
"description": "**Slumber:** Make a Spellcast Roll against a target within Very Close range. On a success, they’re Asleep until they take damage or the GM spends a Fear on their turn to clear this condition.\n**Arcane Barrage:** Once per rest, spend any number of Hope and shoot magical projectiles that strike a target of your choice within Close range. Roll a number of d6s equal to the Hope spent and deal that much magic damage to the target.\n**Telepathy:** Spend a Hope to open a line of mental communication with one target you can see. This connection lasts until your next rest or you cast Telepathy again."
8
+
}
+8
srd/abilities/book-of-korvax.json
+8
srd/abilities/book-of-korvax.json
···
1
+
{
2
+
"id": "book-of-korvax",
3
+
"name": "Book of Korvax",
4
+
"domain": "codex",
5
+
"level": 3,
6
+
"recall_cost": 2,
7
+
"description": "**Levitation:** Make a Spellcast Roll to temporarily lift a target you can see up into the air and move them within Close range of their original position.\n**Recant:** Spend a Hope to force a target within Melee range to make a Reaction Roll (15). On a failure, they forget the last minute of your conversation.\n**Rune Circle:** Mark a Stress to create a temporary magical circle on the ground where you stand. All adversaries within Melee range, who enter Melee range, take 2d12+4 magic damage and are knocked back to Very Close range."
8
+
}
+8
srd/abilities/book-of-norai.json
+8
srd/abilities/book-of-norai.json
···
1
+
{
2
+
"id": "book-of-norai",
3
+
"name": "Book of Norai",
4
+
"domain": "codex",
5
+
"level": 3,
6
+
"recall_cost": 2,
7
+
"description": "**Mystic Tether:** Make a Spellcast Roll against a target within Far range. On a success, they’re temporarily Restrained and must mark a Stress. If you target a flying creature, this spell grounds and temporarily Restrains them.\n**Fireball:** Make a Spellcast Roll against a target within Very Far range. On a success, hurl a sphere of fire toward them that explodes on impact. The target and all creatures within Very Close range of them must make a Reaction Roll (13). Targets who fail take 4d20+5 magic damage using your Proficiency. Targets who succeed take half damage."
8
+
}
+8
srd/abilities/book-of-ronin.json
+8
srd/abilities/book-of-ronin.json
···
1
+
{
2
+
"id": "book-of-ronin",
3
+
"name": "Book of Ronin",
4
+
"domain": "codex",
5
+
"level": 9,
6
+
"recall_cost": 4,
7
+
"description": "**Transform:** Make a Spellcast Roll (15). On a success, transform into an inanimate object no larger than twice your normal size. You can remain in this shape until you take damage.\n**Eternal Enervation:** Once per long rest, make a Spellcast Roll against a target within Close range. On a success, they become permanently Vulnerable. They can’t clear this condition by any means."
8
+
}
+8
srd/abilities/book-of-sitil.json
+8
srd/abilities/book-of-sitil.json
···
1
+
{
2
+
"id": "book-of-sitil",
3
+
"name": "Book of Sitil",
4
+
"domain": "codex",
5
+
"level": 2,
6
+
"recall_cost": 2,
7
+
"description": "**Adjust Appearance:** You magically shift your appearance and clothing to avoid recognition.\n**Parallecta:** Spend 2 Hope to cast this spell on yourself or an ally within Close range. The next time the target makes an attack, they can roll an additional target within range that their attack roll would succeed against. You can only hold this spell on one creature at a time.\n**Illusion:** Make a Spellcast Roll (14). On a success, create a temporary visual illusion no larger than you within Close range that lasts for as long as you look at it. It holds up to scrutiny until an observer is within Melee range."
8
+
}
+8
srd/abilities/book-of-tyfar.json
+8
srd/abilities/book-of-tyfar.json
···
1
+
{
2
+
"id": "book-of-tyfar",
3
+
"name": "Book of Tyfar",
4
+
"domain": "codex",
5
+
"level": 1,
6
+
"recall_cost": 2,
7
+
"description": "**Wild Flame:** Make a Spellcast Roll against up to three adversaries within Melee range. Targets you succeed against take 2d6 magic damage and must mark a Stress as flames erupt from your hand.\n**Magic Hand:** You conjure a magical hand with the same size and strength as your own within Far range.**Mysterious Mist:** Make a Spellcast Roll (13) to cast a temporary thick fog that gathers in a stationary area within Very Close range. The fog heavily obscures this area and everything in it."
8
+
}
+8
srd/abilities/book-of-vagras.json
+8
srd/abilities/book-of-vagras.json
···
1
+
{
2
+
"id": "book-of-vagras",
3
+
"name": "Book of Vagras",
4
+
"domain": "codex",
5
+
"level": 2,
6
+
"recall_cost": 2,
7
+
"description": "**Runic Lock:** Make a Spellcast Roll (15) on an object you’re touching that can close (such as a lock, chest, or box). Once per rest on a success, you can lock the object so it can only be opened by creatures of your choice. Someone with access to magic and an hour of time to study the spell can break it.\n**Arcane Door:** When you have no adversaries within Melee range, make a Spellcast Roll (13). On a success, spend a Hope to create a portal from where you are to a point within Far range you can see. It closes once a creature has passed through it.\n**Reveal:** Make a Spellcast Roll. If there is anything magically hidden within Close range, it is revealed."
8
+
}
+8
srd/abilities/book-of-vyola.json
+8
srd/abilities/book-of-vyola.json
···
1
+
{
2
+
"id": "book-of-vyola",
3
+
"name": "Book of Vyola",
4
+
"domain": "codex",
5
+
"level": 8,
6
+
"recall_cost": 2,
7
+
"description": "**Memory Delve:** Make a Spellcast Roll against a target within Far range. On a success, peer into the target’s mind and ask the GM a question. The GM describes any memories the target has pertaining to the answer.\n**Shared Clarity:** Once per long rest, spend a Hope to choose two willing creatures. When one of them would mark Stress, they can choose between the two of them who marks it. This spell lasts until their next rest."
8
+
}
+8
srd/abilities/book-of-yarrow.json
+8
srd/abilities/book-of-yarrow.json
···
1
+
{
2
+
"id": "book-of-yarrow",
3
+
"name": "Book of Yarrow",
4
+
"domain": "codex",
5
+
"level": 10,
6
+
"recall_cost": 2,
7
+
"description": "**Timejammer:** Make a Spellcast Roll (18). On a success, time temporarily slows to a halt for everyone within Far range except for you. It resumes the next time you make an action roll that targets another creature.\n**Magic Immunity:** Spend 5 Hope to become immune to magic damage until your next rest."
8
+
}
+8
srd/abilities/boost.json
+8
srd/abilities/boost.json
···
1
+
{
2
+
"id": "boost",
3
+
"name": "Boost",
4
+
"domain": "bone",
5
+
"level": 4,
6
+
"recall_cost": 1,
7
+
"description": "Mark a Stress to boost off a willing ally within Close range, fling yourself into the air, and perform an aerial attack against a target within Far range. You have advantage on the attack, add a d10 to the damage roll, and end your move within Melee range of the target."
8
+
}
+8
srd/abilities/brace.json
+8
srd/abilities/brace.json
+8
srd/abilities/breaking-blow.json
+8
srd/abilities/breaking-blow.json
+8
srd/abilities/chain-lightning.json
+8
srd/abilities/chain-lightning.json
···
1
+
{
2
+
"id": "chain-lightning",
3
+
"name": "Chain Lightning",
4
+
"domain": "arcana",
5
+
"level": 5,
6
+
"recall_cost": 1,
7
+
"description": "Mark 2 Stress to make a Spellcast Roll, unleashing lightning on all targets within Close range. Targets you succeed against must make a reaction roll with a Difficulty equal to the result of your Spellcast Roll. Targets who fail take 2d8+4 magic damage. Additional adversaries not already targeted by Chain Lightning and within Close range of previous targets who took damage must also make the reaction roll. Targets who fail take 2d8+4 magic damage. This chain continues until there are no more adversaries within range."
8
+
}
+8
srd/abilities/champions-edge.json
+8
srd/abilities/champions-edge.json
···
1
+
{
2
+
"id": "champions-edge",
3
+
"name": "Champion's Edge",
4
+
"domain": "blade",
5
+
"level": 5,
6
+
"recall_cost": 1,
7
+
"description": "When you critically succeed on an attack, you can spend up to 3 Hope and choose one of the following options for each Hope spent:\n- You clear a Hit Point.\n- You clear an Armor Slot.\n- The target must mark an additional Hit Point.\nYou can’t choose the same option more than once."
8
+
}
+8
srd/abilities/chokehold.json
+8
srd/abilities/chokehold.json
···
1
+
{
2
+
"id": "chokehold",
3
+
"name": "Chokehold",
4
+
"domain": "midnight",
5
+
"level": 3,
6
+
"recall_cost": 1,
7
+
"description": "When you position yourself behind a creature who’s about your size, you can mark a Stress to pull them into a chokehold, making them temporarily Vulnerable.\nWhen a creature attacks a target who is Vulnerable in this way, they deal an extra 2d6 damage."
8
+
}
+8
srd/abilities/cinder-grasp.json
+8
srd/abilities/cinder-grasp.json
···
1
+
{
2
+
"id": "cinder-grasp",
3
+
"name": "Cinder Grasp",
4
+
"domain": "arcana",
5
+
"level": 2,
6
+
"recall_cost": 1,
7
+
"description": "Make a Spellcast Roll against a target within Melee range. On a success, the target instantly bursts into flames, takes 12d20+3 magic damage, and is temporarily lit On Fire.\nWhen a creature acts while On Fire, they must take an extra 2d6 magic damage if they are still On Fire at the end of their action."
8
+
}
+8
srd/abilities/cloaking-blast.json
+8
srd/abilities/cloaking-blast.json
···
1
+
{
2
+
"id": "cloaking-blast",
3
+
"name": "Cloaking Blast",
4
+
"domain": "arcana",
5
+
"level": 7,
6
+
"recall_cost": 2,
7
+
"description": "When you make a successful Spellcast Roll to cast a different spell, you can spend a Hope to become Cloaked. While Cloaked, you remain unseen if you are stationary when an adversary moves to where they would normally see you. When you move into or within an adversary’s line of sight or make an attack, you are no longer Cloaked."
8
+
}
+8
srd/abilities/codex-touched.json
+8
srd/abilities/codex-touched.json
···
1
+
{
2
+
"id": "codex-touched",
3
+
"name": "Codex Touched",
4
+
"domain": "codex",
5
+
"level": 7,
6
+
"recall_cost": 2,
7
+
"description": "When 4 or more of the domain cards in your loadout are from the Codex domain, gain the following benefits:\n- You can mark a Stress to add your Proficiency to a Spellcast Roll.\n- Once per rest, replace this card with any card from your vault without paying its Recall Cost."
8
+
}
+8
srd/abilities/confusing-aura.json
+8
srd/abilities/confusing-aura.json
···
1
+
{
2
+
"id": "confusing-aura",
3
+
"name": "Confusing Aura",
4
+
"domain": "arcana",
5
+
"level": 8,
6
+
"recall_cost": 2,
7
+
"description": "Make a Spellcast Roll (14). Once per long rest on a success, you create a layer of illusion over your body that makes it hard to tell exactly where you are. Mark any number of Stress to make that many additional layers. When an adversary makes an attack against you, roll a number of d6s equal to the number of layers currently active. If any roll a 5 or higher, one layer of the aura is destroyed and the attack fails. If all the results are 4 or lower, you take the damage and this spell ends."
8
+
}
+8
srd/abilities/conjure-swarm.json
+8
srd/abilities/conjure-swarm.json
···
1
+
{
2
+
"id": "conjure-swarm",
3
+
"name": "Conjure Swarm",
4
+
"domain": "sage",
5
+
"level": 2,
6
+
"recall_cost": 1,
7
+
"description": "**Tekaira Armored Beetles:** Mark a Stress to conjure armored beetles that encircle you. When you next take damage, reduce the severity by one threshold. You can spend a Hope to keep the beetles conjured after taking damage.\n**Fire Flies:** Make a Spellcast Roll against all adversaries within Close range. Spend a Hope to deal 2d8+3 magic damage to targets you succeed against."
8
+
}
+8
srd/abilities/conjured-steeds.json
+8
srd/abilities/conjured-steeds.json
···
1
+
{
2
+
"id": "conjured-steeds",
3
+
"name": "Conjureed Steeds",
4
+
"domain": "sage",
5
+
"level": 6,
6
+
"recall_cost": 0,
7
+
"description": "Spend any number of Hope to conjure that many magical steeds (such as horses, camels, or elephants) that you and your allies can ride until your next long rest or the steeds take any damage. The steeds double your land speed while traveling and, when in danger, allow you to move within Far range without having to roll. Creatures riding a steed gain a –2 penalty to attack rolls and a +2 bonus to damage rolls."
8
+
}
+8
srd/abilities/copycat.json
+8
srd/abilities/copycat.json
···
1
+
{
2
+
"id": "copycat",
3
+
"name": "Copycat",
4
+
"domain": "grace",
5
+
"level": 9,
6
+
"recall_cost": 3,
7
+
"description": "Once per long rest, this card can mimic the features of another domain card of level 8 or lower in another player’s loadout. Spend Hope equal to half the card’s level to gain access to the feature. It lasts until your next rest or they place the card in their vault."
8
+
}
+8
srd/abilities/corrosive-projectile.json
+8
srd/abilities/corrosive-projectile.json
···
1
+
{
2
+
"id": "corrosive-projectile",
3
+
"name": "Corrosive Projectile",
4
+
"domain": "sage",
5
+
"level": 3,
6
+
"recall_cost": 1,
7
+
"description": "Make a Spellcast Roll against a target within Far range. On a success, deal 6d4 magic damage using your Proficiency. Additionally, mark 2 or more Stress to make them permanently Corroded. While a target is Corroded, they gain a –1 penalty to their Difficulty for every 2 Stress you spent. This condition can stack."
8
+
}
+8
srd/abilities/counterspell.json
+8
srd/abilities/counterspell.json
···
1
+
{
2
+
"id": "counterspell",
3
+
"name": "Counterspell",
4
+
"domain": "arcana",
5
+
"level": 3,
6
+
"recall_cost": 2,
7
+
"description": "You can interrupt a magical effect taking place by making a reaction roll using your Spellcast trait. On a success, the effect stops and any consequences are avoided, and this card is placed in your vault."
8
+
}
+8
srd/abilities/critical-inspiration.json
+8
srd/abilities/critical-inspiration.json
+8
srd/abilities/cruel-precision.json
+8
srd/abilities/cruel-precision.json
+8
srd/abilities/dark-whispers.json
+8
srd/abilities/dark-whispers.json
···
1
+
{
2
+
"id": "dark-whispers",
3
+
"name": "Dark Whispers",
4
+
"domain": "midnight",
5
+
"level": 6,
6
+
"recall_cost": 0,
7
+
"description": "You can speak into the mind of any person with whom you’ve made physical contact. Once you’ve opened a channel with them, they can speak back into your mind. Additionally, you can mark a Stress to make a Spellcast Roll against them. On a success, you can ask the GM one of the following questions and receive an answer:\n- Where are they?\n- What are they doing?\n- What are they afraid of?\n- What do they cherish most in the world?"
8
+
}
+8
srd/abilities/deadly-focus.json
+8
srd/abilities/deadly-focus.json
···
1
+
{
2
+
"id": "deadly-focus",
3
+
"name": "Deadly Focus",
4
+
"domain": "blade",
5
+
"level": 4,
6
+
"recall_cost": 2,
7
+
"description": "Once per rest, you can apply all your focus toward a target of your choice. Until you attack another creature, you defeat the target, or the battle ends, gain a +1 bonus to your Proficiency."
8
+
}
+8
srd/abilities/death-grip.json
+8
srd/abilities/death-grip.json
···
1
+
{
2
+
"id": "death-grip",
3
+
"name": "Death Grip",
4
+
"domain": "sage",
5
+
"level": 4,
6
+
"recall_cost": 1,
7
+
"description": "Make a Spellcast Roll against a target within Close range and choose one of the following options:\n- You pull the target into Melee range or pull yourself into Melee range of them.\n- You constrict the target and force them to mark 2 Stress.\n- All adversaries between you and the target must succeed on a Reaction Roll (13) or be hit by vines, taking 3d6+2 physical damage.\nOn a success, vines reach out from your hands, causing the chosen effect and temporarily Restraining the target."
8
+
}
+8
srd/abilities/deathrun.json
+8
srd/abilities/deathrun.json
···
1
+
{
2
+
"id": "deathrun",
3
+
"name": "Deathrun",
4
+
"domain": "bone",
5
+
"level": 10,
6
+
"recall_cost": 1,
7
+
"description": "Spend 3 Hope to run a straight path through the battlefield to a point within Far range, making an attack against all adversaries within your weapon’s range along that path. Choose the order in which you deal damage to the targets you succeeded against. For the first, roll your weapon damage with a +1 bonus to your Proficiency. Then remove a die from your damage roll and deal the remaining damage to the next target. Continue to remove a die for each subsequent target until you have no more damage dice or adversaries.\nYou can’t target the same adversary more than once per attack."
8
+
}
+8
srd/abilities/deft-deceiver.json
+8
srd/abilities/deft-deceiver.json
+8
srd/abilities/deft-maneuvers.json
+8
srd/abilities/deft-maneuvers.json
···
1
+
{
2
+
"id": "deft-maneuvers",
3
+
"name": "Deft Maneuvers",
4
+
"domain": "bone",
5
+
"level": 1,
6
+
"recall_cost": 0,
7
+
"description": "Once per rest, mark a Stress to sprint anywhere within Far range without making an Agility Roll to get there.\nIf you end this movement within Melee range of an adversary and immediately make an attack against them, gain a +1 bonus to the attack roll."
8
+
}
+8
srd/abilities/disintegration-wave.json
+8
srd/abilities/disintegration-wave.json
···
1
+
{
2
+
"id": "disintegration-wave",
3
+
"name": "Disintegration Wave",
4
+
"domain": "codex",
5
+
"level": 9,
6
+
"recall_cost": 4,
7
+
"description": "Make a Spellcast Roll (18). Once per long rest on a success, the GM tells you which adversaries within Far range have a Difficulty of 18 or lower. Mark a Stress for each one you wish to hit with this spell. They are killed and can’t come back to life by any means."
8
+
}
+8
srd/abilities/divination.json
+8
srd/abilities/divination.json
···
1
+
{
2
+
"id": "divination",
3
+
"name": "Divination",
4
+
"domain": "splendor",
5
+
"level": 4,
6
+
"recall_cost": 1,
7
+
"description": "Once per long rest, spend 3 Hope to reach out to the forces beyond and ask one “yes or no” question about an event, person, place, or situation in the near future. For a moment, the present falls away and you see the answer before you."
8
+
}
+8
srd/abilities/earthquake.json
+8
srd/abilities/earthquake.json
···
1
+
{
2
+
"id": "earthquake",
3
+
"name": "Earthquake",
4
+
"domain": "arcana",
5
+
"level": 9,
6
+
"recall_cost": 2,
7
+
"description": "Make a Spellcast Roll (16). Once per rest on a success, all targets within Very Far range who aren’t flying must make a Reaction Roll (18). Targets who fail take 3d10+8 physical damage and are temporarily Vulnerable. Targets who succeed take half damage.\nAdditionally, when you succeed on the Spellcast Roll, all terrain within Very Far range becomes difficult to move through and structures within this range might sustain damage or crumble."
8
+
}
+8
srd/abilities/eclipse.json
+8
srd/abilities/eclipse.json
···
1
+
{
2
+
"id": "eclipse",
3
+
"name": "Eclipse",
4
+
"domain": "midnight",
5
+
"level": 10,
6
+
"recall_cost": 2,
7
+
"description": "Make a Spellcast Roll (16). Once per long rest on a success, plunge the entire area within Far range into complete darkness only you and your allies can see through. Attack rolls have disadvantage when targeting you or an ally within this shadow.\nAdditionally, when you or an ally succeeds with Hope against an adversary within this shadow, the target must mark a Stress.\nThis spell lasts until the GM spends a Fear on their turn to clear this effect or you take Severe damage."
8
+
}
+8
srd/abilities/encore.json
+8
srd/abilities/encore.json
···
1
+
{
2
+
"id": "encore",
3
+
"name": "Encore",
4
+
"domain": "grace",
5
+
"level": 10,
6
+
"recall_cost": 1,
7
+
"description": "When an ally within Close range deals damage to an adversary, you can make a Spellcast Roll against that same target. On a success, you deal the same damage to the target that your ally dealt. If your Spellcast Roll succeeds with Fear, place this card in your vault."
8
+
}
+8
srd/abilities/endless-charisma.json
+8
srd/abilities/endless-charisma.json
+8
srd/abilities/enrapture.json
+8
srd/abilities/enrapture.json
···
1
+
{
2
+
"id": "enrapture",
3
+
"name": "Enrapture",
4
+
"domain": "grace",
5
+
"level": 1,
6
+
"recall_cost": 1,
7
+
"description": "Make a Spellcast Roll against a target within Close range. On a success, they become temporarily Enraptured. While Enraptured, a target’s attention is fixed on you, narrowing their field of view and drowning out any sound but your voice. Once per rest on a success, you can mark a Stress to force the Enraptured target to mark a Stress as well."
8
+
}
+8
srd/abilities/falling_sky.json
+8
srd/abilities/falling_sky.json
···
1
+
{
2
+
"id": "falling-sky",
3
+
"name": "Falling Sky",
4
+
"domain": "arcana",
5
+
"level": 10,
6
+
"recall_cost": 1,
7
+
"description": "Make a Spellcast Roll against all adversaries within Far range. Mark any number of Stress to make shards of arcana rain down from above. Targets you succeed against take 12d20+2 magic damage for each Stress marked."
8
+
}
+8
srd/abilities/fane-of-the-wilds.json
+8
srd/abilities/fane-of-the-wilds.json
···
1
+
{
2
+
"id": "fane-of-the-wilds",
3
+
"name": "Fane of the Wilds",
4
+
"domain": "sage",
5
+
"level": 9,
6
+
"recall_cost": 2,
7
+
"description": "After a long rest, place a number of tokens equal to the number of Sage domain cards in your loadout and vault on this card.\nWhen you would make a Spellcast Roll, you can spend any number of tokens after the roll to gain a +1 bonus for each token spent.\nWhen you critically succeed on a Spellcast Roll for a Sage domain spell, gain a token.\nWhen you take a long rest, clear all unspent tokens."
8
+
}
+8
srd/abilities/ferocity.json
+8
srd/abilities/ferocity.json
···
1
+
{
2
+
"id": "ferocity",
3
+
"name": "Ferocity",
4
+
"domain": "bone",
5
+
"level": 2,
6
+
"recall_cost": 2,
7
+
"description": "When you cause an adversary to mark 1 or more Hit Points, you can spend 2 Hope to increase your Evasion by the number of Hit Points they marked. This bonus lasts until after the next attack made against you."
8
+
}
+8
srd/abilities/final-words.json
+8
srd/abilities/final-words.json
···
1
+
{
2
+
"id": "final-words",
3
+
"name": "Final Words",
4
+
"domain": "splendor",
5
+
"level": 2,
6
+
"recall_cost": 1,
7
+
"description": "You can infuse a corpse with a moment of life to speak with it. Make a Spellcast Roll (13). On a success with Hope, the corpse answers up to three questions. On a success with Fear, the corpse answers one question. The corpse answers truthfully, but it can’t impart information it didn’t know in life. On a failure, or once the corpse has finished answering your questions, the body turns to dust."
8
+
}
+8
srd/abilities/flight.json
+8
srd/abilities/flight.json
···
1
+
{
2
+
"id": "flight",
3
+
"name": "Flight",
4
+
"domain": "arcana",
5
+
"level": 3,
6
+
"recall_cost": 1,
7
+
"description": "Make a Spellcast Roll (15). On a success, place a number of tokens equal to your Agility on this card (minimum 1). When you make an action roll while flying, spend a token from this card. After the action that spends the last token is resolved, you descend to the ground directly below you."
8
+
}
+8
srd/abilities/floating-eye.json
+8
srd/abilities/floating-eye.json
···
1
+
{
2
+
"id": "floating-eye",
3
+
"name": "Floating Eye",
4
+
"domain": "arcana",
5
+
"level": 2,
6
+
"recall_cost": 0,
7
+
"description": "Spend a Hope to create a single, small floating orb that you can move anywhere within Very Far range. While this spell is active, you can see through the orb as though you’re looking out from its position. You can transition between using your own senses and seeing through the orb freely. If the orb takes damage or moves out of range, the spell ends."
8
+
}
+8
srd/abilities/forager.json
+8
srd/abilities/forager.json
···
1
+
{
2
+
"id": "forager",
3
+
"name": "Forager",
4
+
"domain": "sage",
5
+
"level": 6,
6
+
"recall_cost": 1,
7
+
"description": "As an additional downtime move you can choose, roll a d6 to see what you forage. Work with the GM to describe it and add it to your inventory as a consumable. Your party can carry up to five foraged consumables at a time.\n1. An unusual flower (Clear 2 Stress)\n2. A beautiful relic (Gain 2 Hope)\n3. An arcane rune (+2 to a Spellcast Roll)\n4. A healing vial (Clear 2 Hit Points)\n5. A luck charm (Reroll any die)\n6. Choose one of the options above."
8
+
}
+8
srd/abilities/force-of-nature.json
+8
srd/abilities/force-of-nature.json
···
1
+
{
2
+
"id": "force-of-nature",
3
+
"name": "Force of Nature",
4
+
"domain": "sage",
5
+
"level": 10,
6
+
"recall_cost": 2,
7
+
"description": "Mark a Stress to transform into a hulking nature spirit, gaining the following benefits:\n- When you succeed on an attack or Spellcast Roll, gain a +10 bonus to the damage roll.\n- When you deal enough damage to defeat a creature within Close range, you absorb them and clear an Armor Slot.\n- You can’t be Restrained.\nBefore you make an action roll, you must spend a Hope. If you can’t, you revert to your normal form."
8
+
}
+8
srd/abilities/forceful-push.json
+8
srd/abilities/forceful-push.json
···
1
+
{
2
+
"id": "forceful-push",
3
+
"name": "Forceful Push",
4
+
"domain": "valor",
5
+
"level": 1,
6
+
"recall_cost": 0,
7
+
"description": "Make an attack with your primary weapon against a target within Melee range. On a success, you deal damage and knock them back to Close range. On a success with Hope, add a d6 to your damage roll.\nAdditionally, you can spend a Hope to make them temporarily Vulnerable."
8
+
}
+8
srd/abilities/forest-sprites.json
+8
srd/abilities/forest-sprites.json
···
1
+
{
2
+
"id": "forest-sprites",
3
+
"name": "Forest Sprites",
4
+
"domain": "sage",
5
+
"level": 8,
6
+
"recall_cost": 2,
7
+
"description": "Make a Spellcast Roll (13). On a success, spend any number of Hope to create an equal number of small forest sprites who appear at points you choose within Far range, providing the following benefits:\n- Your allies gain a +3 bonus to attack rolls against adversaries within Melee range of a sprite.\n- An ally who marks an Armor Slot while within Melee range of a sprite can mark an additional Armor Slot.\nA sprite vanishes after granting a benefit or taking any damage."
8
+
}
+8
srd/abilities/fortified-armor.json
+8
srd/abilities/fortified-armor.json
+8
srd/abilities/frenzy.json
+8
srd/abilities/frenzy.json
···
1
+
{
2
+
"id": "frenzy",
3
+
"name": "Frenzy",
4
+
"domain": "blade",
5
+
"level": 8,
6
+
"recall_cost": 3,
7
+
"description": "Once per long rest, you can go into a Frenzy until there are no more adversaries within sight.\nWhile Frenzied, you can’t use Armor Slots, and you gain a +10 bonus to your damage rolls and a +8 bonus to your Severe damage threshold."
8
+
}
+8
srd/abilities/full-surge.json
+8
srd/abilities/full-surge.json
+8
srd/abilities/get-back-up.json
+8
srd/abilities/get-back-up.json
+8
srd/abilities/gifted-tracker.json
+8
srd/abilities/gifted-tracker.json
···
1
+
{
2
+
"id": "gifted-tracker",
3
+
"name": "Gifted Tracker",
4
+
"domain": "sgae",
5
+
"level": 1,
6
+
"recall_cost": 0,
7
+
"description": "When you’re tracking a specific creature or group of creatures based on signs of their passage, you can spend any number of Hope and ask the GM that many questions from the following list.\n- What direction did they go?\n- How long ago did they pass through?\n- What were they doing in this location?\n- How many of them were here?\nWhen you encounter creatures you’ve tracked in this way, gain a +1 bonus to your Evasion against them."
8
+
}
+8
srd/abilities/glancing-blow.json
+8
srd/abilities/glancing-blow.json
+8
srd/abilities/glyph-of-nightfall.json
+8
srd/abilities/glyph-of-nightfall.json
···
1
+
{
2
+
"id": "glyph-of-nightfall",
3
+
"name": "Glyph of Nightfall",
4
+
"domain": "midnight",
5
+
"level": 4,
6
+
"recall_cost": 1,
7
+
"description": "Make a Spellcast Roll against a target within Very Close range. On a success, spend a Hope to conjure a dark glyph upon their body that exposes their weak points, temporarily reducing the target’s Difficulty by a value equal to your Knowledge (minimum 1)."
8
+
}
+8
srd/abilities/goad-them-on.json
+8
srd/abilities/goad-them-on.json
···
1
+
{
2
+
"id": "goad-them-on",
3
+
"name": "Goad Them On",
4
+
"domain": "valor",
5
+
"level": 4,
6
+
"recall_cost": 1,
7
+
"description": "Describe how you taunt a target within Close range, then make a Presence Roll against them. On a success, the target must mark a Stress, and the next time the GM spotlights them, they must target you with an attack, which they make with disadvantage."
8
+
}
+8
srd/abilities/gore-and-glory.json
+8
srd/abilities/gore-and-glory.json
···
1
+
{
2
+
"id": "gore-and-glory",
3
+
"name": "Gore and Glory",
4
+
"domain": "blade",
5
+
"level": 9,
6
+
"recall_cost": 2,
7
+
"description": "When you critically succeed on a weapon attack, gain an additional Hope or clear an additional Stress.\nAdditionally, when you deal enough damage to defeat an enemy, gain a Hope or clear a Stress."
8
+
}
+8
srd/abilities/grace-touched.json
+8
srd/abilities/grace-touched.json
···
1
+
{
2
+
"id": "grace-touched",
3
+
"name": "Grace Touched",
4
+
"domain": "grace",
5
+
"level": 7,
6
+
"recall_cost": 2,
7
+
"description": "When 4 or more of the domain cards in your loadout are from the Grace domain, gain the following benefits:\n- You can mark an Armor Slot instead of marking a Stress.\n- When you would force a target to mark a number of Hit Points, you can choose instead to force them to mark that number of Stress."
8
+
}
+8
srd/abilities/ground-pound.json
+8
srd/abilities/ground-pound.json
···
1
+
{
2
+
"id": "ground-pound",
3
+
"name": "Ground Pound",
4
+
"domain": "valor",
5
+
"level": 8,
6
+
"recall_cost": 2,
7
+
"description": "Spend 2 Hope to strike the ground where you stand and make a Strength Roll against all targets within Very Close range. Targets you succeed against are thrown back to Far range and must make a Reaction Roll (17). Targets who fail take 4d10+8 damage. Targets who succeed take half damage."
8
+
}
+8
srd/abilities/healing-field.json
+8
srd/abilities/healing-field.json
···
1
+
{
2
+
"id": "healing-field",
3
+
"name": "Healing Field",
4
+
"domain": "sage",
5
+
"level": 4,
6
+
"recall_cost": 2,
7
+
"description": "Once per long rest, you can conjure a field of healing plants around you. Everywhere within Close range of you bursts to life with vibrant nature, allowing you and all allies in the area to clear a Hit Point.\nSpend 2 Hope to allow you and all allies to clear 2 Hit Points instead."
8
+
}
+8
srd/abilities/healing-hands.json
+8
srd/abilities/healing-hands.json
···
1
+
{
2
+
"id": "healing-hands",
3
+
"name": "Healing Hands",
4
+
"domain": "splendor",
5
+
"level": 2,
6
+
"recall_cost": 1,
7
+
"description": "Make a Spellcast Roll (13) and target a creature other than yourself within Melee range. On a success, mark a Stress to clear 2 Hit Points or 2 Stress on the target. On a failure, mark a Stress to clear a Hit Point or a Stress on the target. You can’t heal the same target again until your next long rest."
8
+
}
+8
srd/abilities/healing-strike.json
+8
srd/abilities/healing-strike.json
+8
srd/abilities/hold-the-line.json
+8
srd/abilities/hold-the-line.json
···
1
+
{
2
+
"id": "hold-the-line",
3
+
"name": "Hold the Line",
4
+
"domain": "valor",
5
+
"level": 9,
6
+
"recall_cost": 1,
7
+
"description": "Describe the defensive stance you take and spend a Hope. If an adversary moves within Very Close range, they’re pulled into Melee range and Restrained.\nThis condition lasts until you move or fail a roll with Fear, or the GM spends 2 Fear on their turn to clear it."
8
+
}
+8
srd/abilities/hush.json
+8
srd/abilities/hush.json
···
1
+
{
2
+
"id": "hush",
3
+
"name": "Hush",
4
+
"domain": "midnight",
5
+
"level": 5,
6
+
"recall_cost": 1,
7
+
"description": "Make a Spellcast Roll against a target within Close range. On a success, spend a Hope to conjure suppressive magic around the target that encompasses everything within Very Close range of them and follows them as they move.\nThe target and anything within the area is Silenced until the GM spends a Fear on their turn to clear this condition, you cast Hush again, or you take Major damage. While Silenced, they can’t make noise and can’t cast spells."
8
+
}
+8
srd/abilities/hypnotic-shimmer.json
+8
srd/abilities/hypnotic-shimmer.json
···
1
+
{
2
+
"id": "hypnotic-shimmer",
3
+
"name": "Hypnotic Shimmer",
4
+
"domain": "grace",
5
+
"level": 3,
6
+
"recall_cost": 1,
7
+
"description": "Make a Spellcast Roll against all adversaries in front of you within Close range. Once per rest on a success, create an illusion of flashing colors and lights that temporarily Stuns targets you succeed against and forces them to mark a Stress. While Stunned, they can’t use reactions and can’t take any other actions until they clear this condition."
8
+
}
+8
srd/abilities/i-am-your-shield.json
+8
srd/abilities/i-am-your-shield.json
···
1
+
{
2
+
"id": "i-am-your-shield",
3
+
"name": "I am Your Shield",
4
+
"domain": "valor",
5
+
"level": 1,
6
+
"recall_cost": 1,
7
+
"description": "When an ally within Very Close range would take damage, you can mark a Stress to stand in the way and make yourself the target of the attack instead. When you take damage from this attack, you can mark any number of Armor Slots."
8
+
}
+8
srd/abilities/i-see-it-coming.json
+8
srd/abilities/i-see-it-coming.json
···
1
+
{
2
+
"id": "i-see-it-coming",
3
+
"name": "I see it Coming",
4
+
"domain": "bone",
5
+
"level": 1,
6
+
"recall_cost": 1,
7
+
"description": "When you’re targeted by an attack made from beyond Melee range, you can mark a Stress to roll a d4 and gain a bonus to your Evasion equal to the result against the attack."
8
+
}
+8
srd/abilities/inevitable.json
+8
srd/abilities/inevitable.json
+8
srd/abilities/inspirational-words.json
+8
srd/abilities/inspirational-words.json
···
1
+
{
2
+
"id": "inspirational-words",
3
+
"name": "Inspirational Words",
4
+
"domain": "grace",
5
+
"level": 1,
6
+
"recall_cost": 1,
7
+
"description": "Your speech is imbued with power. After a long rest, place a number of tokens on this card equal to your Presence. When you speak with an ally, you can spend a token from this card to give them one benefit from the following options:\n- Your ally clears a Stress.\n- Your ally clears a Hit Point.\n- Your ally gains a Hope.\nWhen you take a long rest, clear all unspent tokens."
8
+
}
+8
srd/abilities/invigoration.json
+8
srd/abilities/invigoration.json
···
1
+
{
2
+
"id": "invigoration",
3
+
"name": "Invigoration",
4
+
"domain": "splendor",
5
+
"level": 10,
6
+
"recall_cost": 3,
7
+
"description": "When you or an ally within Close range has used a feature that has an exhaustion limit (such as once per rest or once per session), you can spend any number of Hope and roll that many d6s. If any roll a 6, the feature can be used again."
8
+
}
+8
srd/abilities/invisibility.json
+8
srd/abilities/invisibility.json
···
1
+
{
2
+
"id": "invisibility",
3
+
"name": "Invisibility",
4
+
"domain": "grace",
5
+
"level": 3,
6
+
"recall_cost": 1,
7
+
"description": "Make a Spellcast Roll (10). On a success, mark a Stress and choose yourself or an ally within Melee range to become Invisible. An Invisible creature can’t be seen except through magical means and attack rolls against them are made with disadvantage. Place a number of tokens on this card equal to your Spellcast trait. When the Invisible creature takes an action, spend a token from this card. After the action that spends the last token is resolved, the effect ends.\nYou can only hold Invisibility on one creature at a time."
8
+
}
+8
srd/abilities/know-thy-enemy.json
+8
srd/abilities/know-thy-enemy.json
···
1
+
{
2
+
"id": "know-thy-enemy",
3
+
"name": "Know thy Enemy",
4
+
"domain": "bone",
5
+
"level": 5,
6
+
"recall_cost": 1,
7
+
"description": "When observing a creature, you can make an Instinct Roll against them. On a success, spend a Hope and ask the GM for one set of information about the target from the following options:\n- Their unmarked Hit Points and Stress.\n- Their Difficulty and damage thresholds.\n- Their attacks and standard attack damage dice.\n- Their features and Experiences.\nAdditionally on a success, you can mark a Stress to remove a Stress from the GM’s Fear Pool."
8
+
}
+8
srd/abilities/lead-by-example.json
+8
srd/abilities/lead-by-example.json
···
1
+
{
2
+
"id": "lead-by-example",
3
+
"name": "Lead by Example",
4
+
"domain": "valor",
5
+
"level": 9,
6
+
"recall_cost": 3,
7
+
"description": "When you deal damage to an adversary, you can mark a Stress and describe how you encourage your allies. The next PC to make an attack against that adversary can clear a Stress or gain a Hope."
8
+
}
+8
srd/abilities/lean-on-me.json
+8
srd/abilities/lean-on-me.json
+8
srd/abilities/life-ward.json
+8
srd/abilities/life-ward.json
···
1
+
{
2
+
"id": "life-ward",
3
+
"name": "Life Ward",
4
+
"domain": "splendor",
5
+
"level": 4,
6
+
"recall_cost": 1,
7
+
"description": "Spend 3 Hope and choose an ally within Close range. They are marked with a glowing sigil of protection. When this ally would make a death move, they clear a Hit Point instead.\nThis effect ends when it saves the target from a death move, you cast Life Ward on another target, or you take a long rest."
8
+
}
+8
srd/abilities/manifest-wall.json
+8
srd/abilities/manifest-wall.json
···
1
+
{
2
+
"id": "manifest-wall",
3
+
"name": "Manifest Wall",
4
+
"domain": "codex",
5
+
"level": 5,
6
+
"recall_cost": 2,
7
+
"description": "Make a Spellcast Roll (15). Once per rest on a success, spend a Hope to create a temporary magical wall between two points within Far range. It can be up to 50 feet high and form at any angle. Creatures or objects in its path are shunted to a side of their choice. The wall stays up until your next rest or you cast Manifest Wall again."
8
+
}
+8
srd/abilities/mass-disguise.json
+8
srd/abilities/mass-disguise.json
···
1
+
{
2
+
"id": "mass-disguise",
3
+
"name": "Mass Disguise",
4
+
"domain": "midnight",
5
+
"level": 6,
6
+
"recall_cost": 0,
7
+
"description": "When you have a few minutes of silence to focus, you can mark a Stress to change the appearance of all willing creatures within Close range. Their new forms must share a general body structure and size, and can be somebody or something you’ve seen before or entirely fabricated. A disguised creature has advantage on Presence Rolls to avoid scrutiny.\nActivate a Countdown (8). It ticks down as a consequence the GM chooses. When it triggers, the disguise drops."
8
+
}
+8
srd/abilities/mass-enrapture.json
+8
srd/abilities/mass-enrapture.json
···
1
+
{
2
+
"id": "mass-enrapture",
3
+
"name": "Mass Enrapture",
4
+
"domain": "grace",
5
+
"level": 8,
6
+
"recall_cost": 3,
7
+
"description": "Make a Spellcast Roll against all targets within Far range. Targets you succeed against become temporarily Enraptured. While Enraptured, a target’s attention is fixed on you, narrowing their field of view and drowning out any sound but your voice. Mark a Stress to force all Enraptured targets to mark a Stress, ending this spell."
8
+
}
+8
srd/abilities/master-of-the-craft.json
+8
srd/abilities/master-of-the-craft.json
···
1
+
{
2
+
"id": "master-of-the-craft",
3
+
"name": "Master of the Craft",
4
+
"domain": "grace",
5
+
"level": 9,
6
+
"recall_cost": 0,
7
+
"description": "Gain a permanent +2 bonus to two of your Experiences or a permanent +3 bonus to one of your Experiences. Then place this card in your vault permanently."
8
+
}
+8
srd/abilities/mending-touch.json
+8
srd/abilities/mending-touch.json
···
1
+
{
2
+
"id": "mending-touch",
3
+
"name": "Mending Touch",
4
+
"domain": "splendor",
5
+
"level": 1,
6
+
"recall_cost": 1,
7
+
"description": "You lay your hands upon a creature and channel healing magic to close their wounds. When you can take a few minutes to focus on the target you’re helping, you can spend 2 Hope to clear a Hit Point or a Stress on them.\nOnce per long rest, when you spend this healing time learning something new about them or revealing something about yourself, you can clear 2 Hit Points or 2 Stress on them instead."
8
+
}
+8
srd/abilities/midnight-spirit.json
+8
srd/abilities/midnight-spirit.json
···
1
+
{
2
+
"id": "midnight-spirit",
3
+
"name": "Midnight Spirit",
4
+
"domain": "midnight",
5
+
"level": 2,
6
+
"recall_cost": 1,
7
+
"description": "Spend a Hope to summon a humanoid-sized spirit that can move or carry things for you until your next rest.\nYou can also send it to attack an adversary. When you do, make a Spellcast Roll against a target within Very Far range. On a success, the spirit moves into Melee range with that target. Roll a number of d6s equal to your Spellcast trait and deal that much magic damage to the target. The spirit then dissipates. You can only have one spirit at a time."
8
+
}
+8
srd/abilities/midnight-touched.json
+8
srd/abilities/midnight-touched.json
···
1
+
{
2
+
"id": "midnght-touched",
3
+
"name": "Midnight-Touched",
4
+
"domain": "midnight",
5
+
"level": 7,
6
+
"recall_cost": 2,
7
+
"description": "When you have midnight domain cards in your loadout are from the midnight domain, gain the following benefits:\n- Once per rest, when you have 0 Hope and the GM would gain a Fear, you can gain a Hope instead.\n- When you make a successful attack, you can mark a Stress to add the result of your Fear Die to your damage roll."
8
+
}
+8
srd/abilities/natural-familiar.json
+8
srd/abilities/natural-familiar.json
···
1
+
{
2
+
"id": "natural-familiar",
3
+
"name": "Natural Familiar",
4
+
"domain": "sage",
5
+
"level": 2,
6
+
"recall_cost": 1,
7
+
"description": "Spend a Hope to summon a small nature spirit or forest critter to your side until your next rest, you cast Natural Familiar again, or the familiar is targeted by an attack. If you spend an additional Hope, you can summon a familiar that flies. You can communicate with them, make a Spellcast Roll to command them to perform simple tasks, and mark a Stress to see through their eyes.\nWhen you deal damage to an adversary within Melee range of your familiar, you add a d6 to your damage roll."
8
+
}
+8
srd/abilities/natures-tongue.json
+8
srd/abilities/natures-tongue.json
···
1
+
{
2
+
"id": "natures-tongue",
3
+
"name": "Nature's Tongue",
4
+
"domain": "sage",
5
+
"level": 1,
6
+
"recall_cost": 0,
7
+
"description": "You can speak the language of the natural world. When you want to speak to the plants and animals around you, make an Instinct Roll (12). On a success, they’ll give you the information they know. On a roll with Fear, their knowledge might be limited or come at a cost.\nAdditionally, before you make a Spellcast Roll while within a natural environment, you can spend a Hope to gain a +2 bonus to the roll."
8
+
}
+8
srd/abilities/never-upstaged.json
+8
srd/abilities/never-upstaged.json
···
1
+
{
2
+
"id": "never-upstaged",
3
+
"name": "Never Upstaged",
4
+
"domain": "grace",
5
+
"level": 6,
6
+
"recall_cost": 2,
7
+
"description": "When you mark 1 or more Hit Points from an attack, you can mark a Stress to place a number of tokens equal to the number of Hit Points you marked on this card. On your next successful attack, gain a +5 bonus to your damage roll for each token on this card, then clear all tokens."
8
+
}
+8
srd/abilities/night-terror.json
+8
srd/abilities/night-terror.json
···
1
+
{
2
+
"id": "night-terror",
3
+
"name": "Night Terror",
4
+
"domain": "midnight",
5
+
"level": 9,
6
+
"recall_cost": 2,
7
+
"description": "Once per long rest, choose any targets within Very Close range to perceive you as a nightmarish horror. The targets must succeed on a Reaction Roll (16) or become temporarily Horrified. While Horrified, they’re Vulnerable. Steal a number of Fear from the GM equal to the number of targets that are Horrified (up to the number of Fear in the GM’s pool). Roll a number of d6s equal to the number of stolen Fear and deal the total damage to each Horrified target. Discard the stolen Fear."
8
+
}
+8
srd/abilities/not-good-enough.json
+8
srd/abilities/not-good-enough.json
+8
srd/abilities/notorious.json
+8
srd/abilities/notorious.json
···
1
+
{
2
+
"id": "notorious",
3
+
"name": "Notorious",
4
+
"domain": "grace",
5
+
"level": 10,
6
+
"recall_cost": 0,
7
+
"description": "People know who you are and what you’ve done, and they treat you differently because of it. When you leverage your notoriety to get what you want, you can mark a Stress before you roll to gain a +10 bonus to the result. Your food and drinks are always free wherever you go, and everything else you buy is reduced in price by one bag of gold (to a minimum of one handful).\nThis card doesn’t count against your loadout’s domain card maximum of 5 and can’t be placed in your vault."
8
+
}
+8
srd/abilities/on-the-brink.json
+8
srd/abilities/on-the-brink.json
+8
srd/abilities/onslaught.json
+8
srd/abilities/onslaught.json
···
1
+
{
2
+
"id": "onlaught",
3
+
"name": "Onlaught",
4
+
"domain": "blade",
5
+
"level": 10,
6
+
"recall_cost": 3,
7
+
"description": "When you successfully make an attack with your weapon, you never deal damage beneath a target’s Major damage threshold (the target always marks a minimum of 2 Hit Points).\nAdditionally, when a creature within your weapon’s range deals damage to an ally with an attack that doesn’t include you, you can mark a Stress to force them to make a Reaction Roll (15). On a failure, the target must mark a Hit Point."
8
+
}
+8
srd/abilities/overwhelming-aura.json
+8
srd/abilities/overwhelming-aura.json
···
1
+
{
2
+
"id": "overwhelming-aura",
3
+
"name": "Overwhelming Aura",
4
+
"domain": "splendor",
5
+
"level": 9,
6
+
"recall_cost": 2,
7
+
"description": "Make a Spellcast Roll (15) to magically empower your aura. On a success, spend 2 Hope to make your Presence equal to your Spellcast trait until your next long rest.\nWhile this spell is active, an adversary must mark a Stress when they target you with an attack."
8
+
}
+8
srd/abilities/phantom-retreat.json
+8
srd/abilities/phantom-retreat.json
···
1
+
{
2
+
"id": "phantom-retreat",
3
+
"name": "Phantom Retreat",
4
+
"domain": "midnight",
5
+
"level": 5,
6
+
"recall_cost": 2,
7
+
"description": "Spend a Hope to activate Phantom Retreat where you’re currently standing. Spend another Hope at any time before your next rest to disappear from where you are and reappear where you were standing when you activated Phantom Retreat. This spell ends after you reappear."
8
+
}
+8
srd/abilities/pick-and-pull.json
+8
srd/abilities/pick-and-pull.json
···
1
+
{
2
+
"id": "pick-and-pull",
3
+
"name": "Pick and Pull",
4
+
"domain": "midnight",
5
+
"level": 1,
6
+
"recall_cost": 0,
7
+
"description": "You have advantage on action rolls to pick nonmagical locks, disarm nonmagical traps, or steal items from a target (either through stealth or by force)."
8
+
}
+8
srd/abilities/plant-dominion.json
+8
srd/abilities/plant-dominion.json
···
1
+
{
2
+
"id": "plant-dominion",
3
+
"name": "Plant Dominion",
4
+
"domain": "sage",
5
+
"level": 9,
6
+
"recall_cost": 1,
7
+
"description": "Make a Spellcast Roll (18). Once per long rest on a success, you reshape the natural world, changing the surrounding plant life anywhere within Far range of you. For example, you can grow trees instantly, clear a path through dense vines, or create a wall of roots."
8
+
}
+8
srd/abilities/premonition.json
+8
srd/abilities/premonition.json
···
1
+
{
2
+
"id": "premonition",
3
+
"name": "Premonition",
4
+
"domain": "arcana",
5
+
"level": 5,
6
+
"recall_cost": 2,
7
+
"description": "You can channel arcane energy to have visions of the future. Once per long rest, immediately after the GM conveys the consequences of a roll you made, you can rescind the move and consequences like they never happened and make another move instead."
8
+
}
+8
srd/abilities/preservation-blast.json
+8
srd/abilities/preservation-blast.json
···
1
+
{
2
+
"id": "preservation-blast",
3
+
"name": "Preservation Blast",
4
+
"domain": "arcana",
5
+
"level": 4,
6
+
"recall_cost": 2,
7
+
"description": "Make a Spellcast Roll against all targets within Melee range. Targets you succeed against are forced back to Far range and take 8d8+3 magic damage using your Spellcast trait."
8
+
}
+8
srd/abilities/rage-up.json
+8
srd/abilities/rage-up.json
+8
srd/abilities/rain-of-blades.json
+8
srd/abilities/rain-of-blades.json
···
1
+
{
2
+
"id": "rain-of-blades",
3
+
"name": "Rain of Blades",
4
+
"domain": "midnight",
5
+
"level": 1,
6
+
"recall_cost": 1,
7
+
"description": "Spend a Hope to make a Spellcast Roll and conjure throwing blades that strike out at all targets within Very Close range. Targets you succeed against take 1d8+2 magic damage using your Proficiency.\nIf a target you hit is Vulnerable, they take an extra 1d8 damage."
8
+
}
+8
srd/abilities/rapid-riposte.json
+8
srd/abilities/rapid-riposte.json
···
1
+
{
2
+
"id": "rapid-riposte",
3
+
"name": "Rapid Riposte",
4
+
"domain": "bone",
5
+
"level": 6,
6
+
"recall_cost": 0,
7
+
"description": "When an attack made against you from within Melee range fails, you can mark a Stress and seize the opportunity to deal the weapon damage of one of your active weapons to the attacker."
8
+
}
+8
srd/abilities/reapers-strike.json
+8
srd/abilities/reapers-strike.json
···
1
+
{
2
+
"id": "reapers-strike",
3
+
"name": "Reaper's Strike",
4
+
"domain": "blade",
5
+
"level": 9,
6
+
"recall_cost": 3,
7
+
"description": "Once per long rest, spend a Hope to make an attack roll. The GM tells you which targets within range it would succeed against. Choose one of these targets and force them to mark 5 Hit Points."
8
+
}
+8
srd/abilities/reassurance.json
+8
srd/abilities/reassurance.json
···
1
+
{
2
+
"id": "reassurance",
3
+
"name": "Reassurance",
4
+
"domain": "splendor",
5
+
"level": 1,
6
+
"recall_cost": 0,
7
+
"description": "Once per rest, after any ill attempts an action roll but before the consequences take place, you can offer assistance or words of support. When you do, your ally can reroll their dice."
8
+
}
+8
srd/abilities/reckless.json
+8
srd/abilities/reckless.json
+8
srd/abilities/recovery.json
+8
srd/abilities/recovery.json
+8
srd/abilities/redirect.json
+8
srd/abilities/redirect.json
···
1
+
{
2
+
"id": "redirect",
3
+
"name": "Redirect",
4
+
"domain": "bone",
5
+
"level": 4,
6
+
"recall_cost": 1,
7
+
"description": "When an attack made against you from beyond Melee range fails, roll a number of d6s equal to your Proficiency. If any roll a 6, you can mark a Stress to redirect the attack to damage an adversary within Very Close range instead."
8
+
}
+8
srd/abilities/rejuvenation-barrier.json
+8
srd/abilities/rejuvenation-barrier.json
···
1
+
{
2
+
"id": "rejuvenation-barrier",
3
+
"name": "Rejuvenation Barrier",
4
+
"domain": "sage",
5
+
"level": 8,
6
+
"recall_cost": 1,
7
+
"description": "Make a Spellcast Roll (15). Once per rest on a success, create a temporary barrier of protective energy around you at Very Close range. You and all allies within the barrier when this spell is cast clear 1d4 Hit Points. While the barrier is up, you and all allies within have resistance to physical damage from outside the barrier.\nWhen you move, the barrier follows you."
8
+
}
+8
srd/abilities/restoration.json
+8
srd/abilities/restoration.json
···
1
+
{
2
+
"id": "restoration",
3
+
"name": "Restoration",
4
+
"domain": "splendor",
5
+
"level": 6,
6
+
"recall_cost": 2,
7
+
"description": "After a long rest, place a number of tokens equal to your Spellcast trait on this card. Touch a creature and spend any number of tokens to clear 2 Hit Points or 2 Stress for each token spent.\nYou can also spend a token from this card when touching a creature to clear the Vulnerable condition or heal a physical or magical ailment (the GM might require additional tokens depending on the strength of the ailment).\nWhen you take a long rest, clear all unspent tokens."
8
+
}
+8
srd/abilities/resurrection.json
+8
srd/abilities/resurrection.json
···
1
+
{
2
+
"id": "resurrection",
3
+
"name": "Resurrection",
4
+
"domain": "splendor",
5
+
"level": 10,
6
+
"recall_cost": 2,
7
+
"description": "Make a Spellcast Roll (20). On a success, restore one creature who has been dead no longer than 100 years to full strength. Then roll a d6. On a result of 5 or lower, place this card in your vault permanently.\nOn a failure, you can’t cast Resurrection again for a week."
8
+
}
+8
srd/abilities/rift-walker.json
+8
srd/abilities/rift-walker.json
···
1
+
{
2
+
"id": "rift-walker",
3
+
"name": "Rift Walker",
4
+
"domain": "arcana",
5
+
"level": 6,
6
+
"recall_cost": 2,
7
+
"description": "Make a Spellcast Roll (15). On a success, you place an arcane marking on the ground where you currently stand. The next time you successfully cast Rift Walker, a rift in space opens up, providing safe passage back to the exact spot where the marking was placed. This rift stays open until you choose to close it or you cast another spell.\nYou can drop the spell at any time to cast Rift Walker again and place the marking somewhere new."
8
+
}
+8
srd/abilities/rise-up.json
+8
srd/abilities/rise-up.json
+8
srd/abilities/rousing-strike.json
+8
srd/abilities/rousing-strike.json
+8
srd/abilities/rune-ward.json
+8
srd/abilities/rune-ward.json
···
1
+
{
2
+
"id": "rune-ward",
3
+
"name": "Rune Ward",
4
+
"domain": "arcana",
5
+
"level": 1,
6
+
"recall_cost": 0,
7
+
"description": "You have a deeply personal trinket that can be infused with protective magic and held as a ward by you or an ally. Describe what it is and why it’s important to you. The ward’s holder can spend a Hope to reduce incoming damage by 1d8.\nIf the Ward Die result is 8, the ward’s power ends after it reduces damage this turn. It can be recharged for free on your next rest."
8
+
}
+8
srd/abilities/safe-haven.json
+8
srd/abilities/safe-haven.json
···
1
+
{
2
+
"id": "safe-haven",
3
+
"name": "Safe Haven",
4
+
"domain": "codex",
5
+
"level": 8,
6
+
"recall_cost": 3,
7
+
"description": "When you have a few minutes of calm to focus, you can spend 2 Hope to summon your Safe Haven, a large interdimensional home where you and your allies can take shelter. When you do, a magical door appears somewhere within Close range. Only creatures of your choice can enter. Once inside, you can make the entrance invisible. You and anyone else inside can always exit. Once you leave, the doorway must be summoned again.\nWhen you take a rest within your own Safe Haven, you can choose an additional downtime move."
8
+
}
+8
srd/abilities/sage-touched.json
+8
srd/abilities/sage-touched.json
···
1
+
{
2
+
"id": "sage-touched",
3
+
"name": "Sage Touched",
4
+
"domain": "sage",
5
+
"level": 7,
6
+
"recall_cost": 2,
7
+
"description": "When 4 or more of the domain cards in your loadout are from the Sage domain, gain the following benefits:\n- While you’re in a natural environment, you gain a +2 bonus to your Spellcast Rolls.\n- Once per rest, you can double your Agility or Instinct when making a roll that uses that trait. You must choose to do this before you roll."
8
+
}
+8
srd/abilities/salvation-beam.json
+8
srd/abilities/salvation-beam.json
···
1
+
{
2
+
"id": "salvation-beam",
3
+
"name": "Salvation Beam",
4
+
"domain": "splendor",
5
+
"level": 9,
6
+
"recall_cost": 2,
7
+
"description": "Make a Spellcast Roll (16). On a success, mark any number of Stress to target a line of allies within Far range. You can clear Hit Points on the targets equal to the number of Stress marked, divided among them however you’d like."
8
+
}
+8
srd/abilities/scramble.json
+8
srd/abilities/scramble.json
+8
srd/abilities/second-wind.json
+8
srd/abilities/second-wind.json
···
1
+
{
2
+
"id": "second-wind",
3
+
"name": "Second Wind",
4
+
"domain": "splendor",
5
+
"level": 3,
6
+
"recall_cost": 2,
7
+
"description": "Once per rest, when you succeed on an attack against an adversary, you can clear 3 Stress or a Hit Point. On a success with Hope, you also clear 3 Stress or a Hit Point on an ally within Close range of you."
8
+
}
+8
srd/abilities/sensory-projection.json
+8
srd/abilities/sensory-projection.json
···
1
+
{
2
+
"id": "sensory-projection",
3
+
"name": "Sensory Projection",
4
+
"domain": "arcana",
5
+
"level": 9,
6
+
"recall_cost": 0,
7
+
"description": "Once per rest, make a Spellcast Roll (15). On a success, drop into a vision that lets you clearly see and hear any place you have been before as though you are standing there in this moment. You can move freely in this vision and are not constrained by the physics or impediments of a physical body. This spell cannot be detected by mundane or magical means. You drop out of this vision upon taking damage or casting another spell."
8
+
}
+8
srd/abilities/shadowbind.json
+8
srd/abilities/shadowbind.json
···
1
+
{
2
+
"id": "shadowbind",
3
+
"name": "Shadowbind",
4
+
"domain": "midnight",
5
+
"level": 2,
6
+
"recall_cost": 0,
7
+
"description": "Make a Spellcast Roll against all adversaries within Very Close range. Targets you succeed against are temporarily Restrained as their shadow binds them in place."
8
+
}
+8
srd/abilities/shadowhunter.json
+8
srd/abilities/shadowhunter.json
···
1
+
{
2
+
"id": "shadowhunter",
3
+
"name": "Shadowhunter",
4
+
"domain": "midnight",
5
+
"level": 8,
6
+
"recall_cost": 2,
7
+
"description": "Your prowess is enhanced under the cover of shadow. While you’re shrouded in low light or darkness, you gain a +1 bonus to your Evasion and make attack rolls with advantage."
8
+
}
+8
srd/abilities/shape-material.json
+8
srd/abilities/shape-material.json
···
1
+
{
2
+
"id": "shape-material",
3
+
"name": "Shape Material",
4
+
"domain": "splendor",
5
+
"level": 5,
6
+
"recall_cost": 1,
7
+
"description": "Spend a Hope to shape a section of natural material you’re touching (such as stone, ice, or wood) to suit your purpose. The area of the material can be no larger than you. For example, you can form a rudimentary tool or create a door.\nYou can only affect the material within Close range of where you’re touching it."
8
+
}
+8
srd/abilities/shield-aura.json
+8
srd/abilities/shield-aura.json
···
1
+
{
2
+
"id": "shield-aura",
3
+
"name": "Shield Aura",
4
+
"domain": "splendor",
5
+
"level": 8,
6
+
"recall_cost": 2,
7
+
"description": "Mark a Stress to cast a protective aura on a target within Very Close range. When the target marks an Armor Slot, they reduce the severity of the attack by an additional threshold. If this spell causes a creature who would be damaged to instead mark no Hit Points, the effect ends.\nYou can only hold Shield Aura on one creature at a time."
8
+
}
+8
srd/abilities/shrug-it-off.json
+8
srd/abilities/shrug-it-off.json
···
1
+
{
2
+
"id": "shrug-it-off",
3
+
"name": "Shrug it Off",
4
+
"domain": "valor",
5
+
"level": 7,
6
+
"recall_cost": 1,
7
+
"description": "When you would take damage, you can mark a Stress to reduce the severity of the damage by one threshold. When you do, roll a d6. On a result of 3 or lower, place this card in your vault."
8
+
}
+8
srd/abilities/sigil-of-retribution.json
+8
srd/abilities/sigil-of-retribution.json
···
1
+
{
2
+
"id": "sigil-of-retribution",
3
+
"name": "Sigil of Retribution",
4
+
"domain": "codex",
5
+
"level": 6,
6
+
"recall_cost": 2,
7
+
"description": "Mark an adversary within Close range with a sigil of retribution. The GM gains a Fear. When the marked adversary deals damage to you or your allies, place a d8 on this card. You can hold a number of d8s equal to your level. When you successfully attack the marked adversary, roll the dice on this card and add the total to your damage roll, then clear the dice. This effect ends when the marked adversary is defeated or you cast Sigil of Retribution again."
8
+
}
+8
srd/abilities/signature-move.json
+8
srd/abilities/signature-move.json
···
1
+
{
2
+
"id": "signature-move",
3
+
"name": "Signature Move",
4
+
"domain": "bone",
5
+
"level": 5,
6
+
"recall_cost": 1,
7
+
"description": "Name and describe your signature combat move. Once per rest, when you perform this signature move as part of an action you’re taking, you can roll a d20 as your Hope Die. On a success, clear a Stress."
8
+
}
+8
srd/abilities/smite.json
+8
srd/abilities/smite.json
···
1
+
{
2
+
"id": "smite",
3
+
"name": "Smite",
4
+
"domain": "splendor",
5
+
"level": 5,
6
+
"recall_cost": 2,
7
+
"description": "Once per rest, spend 3 Hope to charge your powerful smite. When you next successfully attack with a weapon, double the result of your damage roll. This attack deals magic damage regardless of the weapon's damage type."
8
+
}
+8
srd/abilities/soothing-speech.json
+8
srd/abilities/soothing-speech.json
···
1
+
{
2
+
"id": "soothing-speech",
3
+
"name": "Soothing Speech",
4
+
"domain": "grace",
5
+
"level": 4,
6
+
"recall_cost": 1,
7
+
"description": "During a short rest, when you take the time to comfort another character while using the Tend to Wounds downtime move on them, clear an additional Hit Point on that character. When you do, you also clear 2 Hit Points."
8
+
}
+8
srd/abilities/specter-of-the-dark.json
+8
srd/abilities/specter-of-the-dark.json
···
1
+
{
2
+
"id": "specter-of-the-dark",
3
+
"name": "Specter of the Dark",
4
+
"domain": "midnight",
5
+
"level": 10,
6
+
"recall_cost": 1,
7
+
"description": "Mark a Stress to become Spectral until you make an action roll targeting another creature. While Spectral, you’re immune to physical damage and can float and pass through solid objects. Other creatures can still see you while you’re in this form."
8
+
}
+8
srd/abilities/spellcharge.json
+8
srd/abilities/spellcharge.json
···
1
+
{
2
+
"id": "spellcharge",
3
+
"name": "Spellcharge",
4
+
"domain": "midnight",
5
+
"level": 8,
6
+
"recall_cost": 1,
7
+
"description": "When you take magic damage, place tokens equal to the number of Hit Points you marked on this card. You can store a number of tokens equal to your Spellcast trait.\nWhen you make a successful attack against a target, you can spend any number of tokens to add a d6 for each token spent to your damage roll."
8
+
}
+8
srd/abilities/splendor-touched.json
+8
srd/abilities/splendor-touched.json
···
1
+
{
2
+
"id": "splendor-touched",
3
+
"name": "Splendor-Touched",
4
+
"domain": "splendor",
5
+
"level": 7,
6
+
"recall_cost": 2,
7
+
"description": "When 4 or more of the domain cards in your loadout are from the Splendor domain, gain the following benefits:\n- +3 bonus to your Severe damage threshold\n- Once per long rest, when incoming damage would require you to mark a number of Hit Points, you can choose to mark that much Stress or spend that much Hope instead."
8
+
}
+8
srd/abilities/splintering-strike.json
+8
srd/abilities/splintering-strike.json
···
1
+
{
2
+
"id": "splintering-strike",
3
+
"name": "Splintering Strike",
4
+
"domain": "bone",
5
+
"level": 9,
6
+
"recall_cost": 3,
7
+
"description": "Spend a Hope and make an attack against all adversaries within your weapon’s range. Once per long rest, on a success against any targets, roll your weapon’s damage and distribute that damage however you wish between the targets you succeeded against. Before you deal damage to each target, roll an additional damage die and add its result to the damage you deal to them."
8
+
}
+8
srd/abilities/stealth-expertise.json
+8
srd/abilities/stealth-expertise.json
···
1
+
{
2
+
"id": "stealth-expertise",
3
+
"name": "Stealth Expertise",
4
+
"domain": "midnight",
5
+
"level": 4,
6
+
"recall_cost": 0,
7
+
"description": "When you roll with Fear while attempting to move unnoticed through a dangerous area, you can mark a Stress to roll with Hope instead.\nIf an ally within Close range is also attempting to move unnoticed and rolls with Fear, you can mark a Stress to change their result to a roll with Hope."
8
+
}
+8
srd/abilities/strategic-approach.json
+8
srd/abilities/strategic-approach.json
···
1
+
{
2
+
"id": "strategic-approach",
3
+
"name": "Strategic Approach",
4
+
"domain": "bone",
5
+
"level": 2,
6
+
"recall_cost": 1,
7
+
"description": "After a long rest, place a number of tokens equal to your Knowledge on this card (minimum 1). The first time you move within Close range of an adversary and make an attack against them, you can spend one token to choose one of the following options:\n- You make the attack with advantage.\n- You clear a Stress on an ally within Melee range of the adversary.\n- You add a d8 to your damage roll.\nWhen you take a long rest, clear all unspent tokens."
8
+
}
+8
srd/abilities/stunning-sunlight.json
+8
srd/abilities/stunning-sunlight.json
···
1
+
{
2
+
"id": "stunning-sunlight",
3
+
"name": "Stunning Sunlight",
4
+
"domain": "splendor",
5
+
"level": 8,
6
+
"recall_cost": 2,
7
+
"description": "Make a Spellcast Roll to unleash powerful rays of burning sunlight against all adversaries in front of you within Far range. On a success, spend any number of Hope and force that many targets you succeeded against to make a Reaction Roll (14).\nTargets who succeed take 3d20+3 magic damage. Targets who fail take 4d20+5 magic damage and are temporarily Stunned. While Stunned, they can’t use reactions and can’t take any other actions until they clear this condition."
8
+
}
+8
srd/abilities/support-tank.json
+8
srd/abilities/support-tank.json
+8
srd/abilities/swift-step.json
+8
srd/abilities/swift-step.json
+8
srd/abilities/tactician.json
+8
srd/abilities/tactician.json
···
1
+
{
2
+
"id": "tactician",
3
+
"name": "Tactician",
4
+
"domain": "bone",
5
+
"level": 3,
6
+
"recall_cost": 1,
7
+
"description": "When you Help an Ally, they can spend a Hope to add one of your Experiences to their roll alongside your advantage die.\nWhen making a Tag Team Roll, you can roll a d20 as your Hope Die."
8
+
}
+8
srd/abilities/telekinesis.json
+8
srd/abilities/telekinesis.json
···
1
+
{
2
+
"id": "telekinesis",
3
+
"name": "Telekinesis",
4
+
"domain": "arcana",
5
+
"level": 6,
6
+
"recall_cost": 0,
7
+
"description": "Make a Spellcast Roll against a target within Far range. On a success, you can use your mind to move them anywhere within Far range of their original position. You can throw the lifted target as an attack by making an additional Spellcast Roll against the second target you’re trying to attack. On a success, deal 12d4 physical damage to the second target using your Proficiency Die."
8
+
}
+8
srd/abilities/teleport.json
+8
srd/abilities/teleport.json
···
1
+
{
2
+
"id": "teleport",
3
+
"name": "Teleport",
4
+
"domain": "codex",
5
+
"level": 5,
6
+
"recall_cost": 2,
7
+
"description": "Once per long rest, you can instantly teleport yourself and any number of willing targets within Close range to a place you’ve been before. Choose one of the following options, then make a Spellcast Roll (16):\n- If you know the place very well, gain a +3 bonus.\n- If you’ve visited the place frequently, gain a +1 bonus.\n- If you’ve visited the place infrequently, gain no modifier.\n- If you’ve only been there once, gain a -2 penalty.\nOn a success, you appear where you were intending to go. On a failure, you appear off course, with the range of failure determining how far off course."
8
+
}
+8
srd/abilities/tell-no-lies.json
+8
srd/abilities/tell-no-lies.json
···
1
+
{
2
+
"id": "tell-no-lies",
3
+
"name": "Tell No Lies",
4
+
"domain": "grace",
5
+
"level": 2,
6
+
"recall_cost": 1,
7
+
"description": "Make a Spellcast Roll against a target within Very Close range. On a success, they can’t lie to you while they remain within Close range, but they are not compelled to speak. If you ask them a question and they refuse to answer, they must mark a Stress and the effect ends. The target is typically unaware this spell has been cast on them until it causes them to utter the truth."
8
+
}
+8
srd/abilities/tempest.json
+8
srd/abilities/tempest.json
···
1
+
{
2
+
"id": "tempest",
3
+
"name": "Tempest",
4
+
"domain": "sage",
5
+
"level": 10,
6
+
"recall_cost": 2,
7
+
"description": "Choose one of the following tempests and make a Spellcast Roll against all targets within Far range. Targets you succeed against experience its effects until the GM spends a Fear on their turn to end this spell.\n- **Blizzard:** Deal 2d20+8 magic damage and targets are temporarily Vulnerable.\n- **Hurricane:** Deal 3d10+10 magic damage and choose a direction the wind is blowing. Targets can’t move against the wind.\n- **Sandstorm:** Deal 5d6+9 magic damage. Attacks made from beyond Melee range have disadvantage."
8
+
}
+8
srd/abilities/thorn-skin.json
+8
srd/abilities/thorn-skin.json
···
1
+
{
2
+
"id": "thorn-skin",
3
+
"name": "Thorn Skin",
4
+
"domain": "sage",
5
+
"level": 5,
6
+
"recall_cost": 1,
7
+
"description": "Once per rest, spend a Hope to sprout thorns all over your body. When you do, place a number of tokens equal to your Spellcast trait on this card. When you take damage, you can spend any number of tokens to roll that number of d6s. Add the results together and reduce the incoming damage by that amount. If you’re within Melee range of the attacker, deal that amount of damage back to them.\nWhen you take a rest, clear all unspent tokens."
8
+
}
+8
srd/abilities/thought-deliver.json
+8
srd/abilities/thought-deliver.json
···
1
+
{
2
+
"id": "thought-deliver",
3
+
"name": "Thought Deliver",
4
+
"domain": "grace",
5
+
"level": 5,
6
+
"recall_cost": 2,
7
+
"description": "You can peek into the minds of others. Spend a Hope to read the vague surface thoughts of a target within Far range. Make a Spellcast Roll against the target to delve for deeper, more hidden thoughts.\nOn a roll with Fear, the target might, at the GM’s discretion, become aware that you’re reading their thoughts."
8
+
}
+8
srd/abilities/through-your-eyes.json
+8
srd/abilities/through-your-eyes.json
···
1
+
{
2
+
"id": "through-your-eyes",
3
+
"name": "Through Your Eyes",
4
+
"domain": "grace",
5
+
"level": 4,
6
+
"recall_cost": 1,
7
+
"description": "Choose a target within Very Far range. You can see through their eyes and hear through their ears. You can transition between using your own senses or the target’s freely until you cast another spell or until your next rest."
8
+
}
+8
srd/abilities/towering-stalk.json
+8
srd/abilities/towering-stalk.json
···
1
+
{
2
+
"id": "towering-stalk",
3
+
"name": "Towering Stalk",
4
+
"domain": "sage",
5
+
"level": 3,
6
+
"recall_cost": 1,
7
+
"description": "Once per rest, you can conjure a thick, twisting stalk within Close range that can be easily climbed. Its height can grow up to Far range.\nMark a Stress to use this spell as an attack. Make a Spellcast Roll against an adversary or group of adversaries within Close range. The erupting stalk lifts targets you succeed against into the air and drops them, dealing d8 physical damage using your Proficiency."
8
+
}
+8
srd/abilities/transcendent-union.json
+8
srd/abilities/transcendent-union.json
···
1
+
{
2
+
"id": "transcendent-union",
3
+
"name": "Transcendent Union",
4
+
"domain": "codex",
5
+
"level": 10,
6
+
"recall_cost": 1,
7
+
"description": "Once per long rest, spend 5 Hope to cast this spell on two or more willing creatures. Until your next rest, when a creature connected by this union would mark Stress or Hit Points, the connected creatures can choose who marks it."
8
+
}
+8
srd/abilities/troublemaker.json
+8
srd/abilities/troublemaker.json
···
1
+
{
2
+
"id": "troublemaker",
3
+
"name": "Troublemaker",
4
+
"domain": "grace",
5
+
"level": 2,
6
+
"recall_cost": 2,
7
+
"description": "When you taunt or provoke a target within Far range, make a Presence Roll against them. Once per rest on a success, roll a number of d4s equal to your Proficiency. The target must mark Stress equal to the highest result rolled."
8
+
}
+8
srd/abilities/twilight-toll.json
+8
srd/abilities/twilight-toll.json
···
1
+
{
2
+
"id": "twilight-toll",
3
+
"name": "Twilight Toll",
4
+
"domain": "midnight",
5
+
"level": 9,
6
+
"recall_cost": 1,
7
+
"description": "Choose a target within Far range. When you succeed on an action roll against them that doesn’t result in making a damage roll, place a token on this card. When you deal damage to this target, spend any number of tokens to add a d12 for each token spent to your damage roll. You can only hold Twilight Toll on one creature at a time.\nWhen you choose a new target or take a rest, clear all unspent tokens."
8
+
}
+8
srd/abilities/unbreakable.json
+8
srd/abilities/unbreakable.json
···
1
+
{
2
+
"id": "unbreakable",
3
+
"name": "Unbreakable",
4
+
"domain": "valor",
5
+
"level": 10,
6
+
"recall_cost": 4,
7
+
"description": "When you mark your last Hit Point, instead of making a death move, you can roll a d6 and clear a number of Hit Points equal to the result. Then place this card in your vault."
8
+
}
+8
srd/abilities/uncanny-disguise.json
+8
srd/abilities/uncanny-disguise.json
···
1
+
{
2
+
"id": "uncanny-disguise",
3
+
"name": "Uncanny Disguise",
4
+
"domain": "midnight",
5
+
"level": 1,
6
+
"recall_cost": 0,
7
+
"description": "When you have a few minutes to prepare, you can mark a Stress to don the facade of any humanoid you can picture clearly in your mind. While disguised, you have advantage on Presence Rolls to avoid scrutiny.\nPlace a number of tokens equal to your Spellcast trait on this card. When you take an action while disguised, spend a token from this card. After the action that spends the last token is resolved, the disguise drops."
8
+
}
+8
srd/abilities/unleash-chaos.json
+8
srd/abilities/unleash-chaos.json
···
1
+
{
2
+
"id": "unleash-chaos",
3
+
"name": "Unleash Chaos",
4
+
"domain": "arcana",
5
+
"level": 1,
6
+
"recall_cost": 1,
7
+
"description": "At the beginning of a session, place a number of tokens equal to your Spellcast trait on this card.\nMake a Spellcast Roll against a target within Far range and spend any number of tokens to channel raw energy from within yourself to unleash against them. On a success, roll a number of d10s equal to the tokens you spent and deal that much magic damage to the target. Mark a Stress to replenish this card with tokens (up to your Spellcast trait).\nAt the end of each session, clear all unspent tokens."
8
+
}
+8
srd/abilities/untouchable.json
+8
srd/abilities/untouchable.json
+8
srd/abilities/unyeilding-armor.json
+8
srd/abilities/unyeilding-armor.json
···
1
+
{
2
+
"id": "unyeilding-armor",
3
+
"name": "Unyeilding Armor",
4
+
"domain": "valor",
5
+
"level": 10,
6
+
"recall_cost": 1,
7
+
"description": "When you would mark an Armor Slot, roll a number of d6s equal to your Proficiency. If any roll a 6, reduce the severity by one threshold without marking an Armor Slot."
8
+
}
+8
srd/abilities/valor-touched.json
+8
srd/abilities/valor-touched.json
···
1
+
{
2
+
"id": "valor-touched",
3
+
"name": "Valor-Touched",
4
+
"domain": "valor",
5
+
"level": 7,
6
+
"recall_cost": 1,
7
+
"description": "When 4 or more of the domain cards in your loadout are from the Valor domain, gain the following benefits:\n- +1 bonus to your Armor Score\n- When you mark 1 or more Hit Points without marking an Armor Slot, clear an Armor Slot."
8
+
}
+8
srd/abilities/vanishing-dodge.json
+8
srd/abilities/vanishing-dodge.json
···
1
+
{
2
+
"id": "vanishing-dodge",
3
+
"name": "Vanishing Dodge",
4
+
"domain": "midnight",
5
+
"level": 7,
6
+
"recall_cost": 1,
7
+
"description": "When an attack made against you that would deal physical damage fails, you can spend a Hope to envelop yourself in shadow, becoming Hidden and teleporting to a point within Close range of the attacker. You remain Hidden until the next time you make an action roll."
8
+
}
+8
srd/abilities/veil-of-night.json
+8
srd/abilities/veil-of-night.json
···
1
+
{
2
+
"id": "veil-of-night",
3
+
"name": "Veil of Night",
4
+
"domain": "midnight",
5
+
"level": 3,
6
+
"recall_cost": 1,
7
+
"description": "Make a Spellcast Roll (13). On a success, you can create a temporary curtain of darkness between two points within Far range. Only you can see through this darkness. You’re considered Hidden to adversaries on the other side of the veil, and you have advantage on attacks you make through the darkness. The veil remains until you cast another spell."
8
+
}
+8
srd/abilities/versatile-fighter.json
+8
srd/abilities/versatile-fighter.json
···
1
+
{
2
+
"id": "versatile-fighter",
3
+
"name": "Versatile Fighter",
4
+
"domain": "blade",
5
+
"level": 3,
6
+
"recall_cost": 1,
7
+
"description": "You can use a different character trait for an equipped weapon, rather than the trait the weapon calls for.\nWhen you deal damage, you can mark a Stress to use the maximum result of one of your damage dice instead of rolling it."
8
+
}
+8
srd/abilities/vicious-entangle.json
+8
srd/abilities/vicious-entangle.json
···
1
+
{
2
+
"id": "vicious-entangle",
3
+
"name": "Vicious Entangle",
4
+
"domain": "sage",
5
+
"level": 1,
6
+
"recall_cost": 1,
7
+
"description": "Make a Spellcast Roll against a target within Far range. On a success, roots and vines reach out from the ground, dealing 1d8+1 physical damage and temporarily Restraining the target.\nAdditionally on a success, you can spend a Hope to temporarily Restrain another adversary within Very Close range of your target."
8
+
}
+8
srd/abilities/vitality.json
+8
srd/abilities/vitality.json
···
1
+
{
2
+
"id": "vitality",
3
+
"name": "Vitality",
4
+
"domain": "blade",
5
+
"level": 5,
6
+
"recall_cost": 0,
7
+
"description": "When you choose this card, permanently gain two of the following benefits:\n- One Stress slot\n- One Hit Point slot\n- +2 bonus to your damage thresholds\nThen place this card in your vault permanently."
8
+
}
+8
srd/abilities/voice-of-reason.json
+8
srd/abilities/voice-of-reason.json
···
1
+
{
2
+
"id": "voice-of-reason",
3
+
"name": "Voice of Reason",
4
+
"domain": "splendor",
5
+
"level": 3,
6
+
"recall_cost": 1,
7
+
"description": "You speak with an unmatched power and authority. You have advantage on action rolls to de-escalate violent situations or convince someone to follow your lead.\nAdditionally, you’re emboldened in moments of duress. When all of your Stress slots are marked, you gain a +1 bonus to your Proficiency for damage rolls."
8
+
}
+8
srd/abilities/wall-walk.json
+8
srd/abilities/wall-walk.json
···
1
+
{
2
+
"id": "wall-walk",
3
+
"name": "Wall Walk",
4
+
"domain": "arcana",
5
+
"level": 1,
6
+
"recall_cost": 1,
7
+
"description": "Spend a Hope to allow a creature you can touch to climb on walls and ceilings as easily as walking on the ground. This lasts until the end of the scene or you cast Wall Walk again."
8
+
}
+8
srd/abilities/whirlwind.json
+8
srd/abilities/whirlwind.json
···
1
+
{
2
+
"id": "whirlwind",
3
+
"name": "Whirlwind",
4
+
"domain": "blade",
5
+
"level": 1,
6
+
"recall_cost": 0,
7
+
"description": "When you make a successful attack against a target within Very Close range, you can spend a Hope to use the attack against all other targets within Very Close range. All additional adversaries you succeed against with this ability take half damage."
8
+
}
+8
srd/abilities/wild-fortress.json
+8
srd/abilities/wild-fortress.json
···
1
+
{
2
+
"id": "wild-fortress",
3
+
"name": "Wild Fortress",
4
+
"domain": "sage",
5
+
"level": 5,
6
+
"recall_cost": 1,
7
+
"description": "Make a Spellcast Roll (13). On a success, spend 2 Hope to grow a natural barricade in the shape of a dome that you and one ally can take cover within. While inside the dome, a creature can’t be targeted by attacks and can’t make attacks. Attacks made against the dome automatically succeed. The dome has the following damage thresholds and lasts until it marks 3 Hit Points. Place tokens on this card to represent marking Hit Points.\n**Thresholds:** 15/30"
8
+
}
+8
srd/abilities/wild-surge.json
+8
srd/abilities/wild-surge.json
···
1
+
{
2
+
"id": "wild-surge",
3
+
"name": "Wild Surge",
4
+
"domain": "sage",
5
+
"level": 7,
6
+
"recall_cost": 2,
7
+
"description": "Once per long rest, mark a Stress to channel the natural world around you and enhance yourself. Describe how your appearance changes, then place a d6 on this card with the 1 value facing up.\nWhile the Wild Surge Die is active, you add its value to every action roll you make. After you add its value to a roll, increase the Wild Surge Die’s value by one. When the die’s value would exceed 6 or you take a rest, this form drops and you must mark an additional Stress."
8
+
}
+8
srd/abilities/words-of-discord.json
+8
srd/abilities/words-of-discord.json
···
1
+
{
2
+
"id": "words-of-discord",
3
+
"name": "Words of Discord",
4
+
"domain": "grace",
5
+
"level": 5,
6
+
"recall_cost": 1,
7
+
"description": "Whisper words of discord to an adversary within Melee range and make a Spellcast Roll (13). On a success, the target must mark a Stress and make an attack against another adversary instead of against you or your allies.\nOnce this attack is over, the target realizes what happened. The next time you cast Words of Discord on them, gain a –5 penalty to the Spellcast Roll."
8
+
}
+8
srd/abilities/wrangle.json
+8
srd/abilities/wrangle.json
···
1
+
{
2
+
"id": "wrangle",
3
+
"name": "Wrangle",
4
+
"domain": "bone",
5
+
"level": 8,
6
+
"recall_cost": 1,
7
+
"description": "Make an Agility Roll against all targets within Close range. Spend a Hope to move targets you succeed against, and any willing allies within Close range, to another point within Close range."
8
+
}
+8
srd/abilities/zone-of-protection.json
+8
srd/abilities/zone-of-protection.json
···
1
+
{
2
+
"id": "zone-of-protection",
3
+
"name": "Zone of Protection",
4
+
"domain": "splendor",
5
+
"level": 6,
6
+
"recall_cost": 2,
7
+
"description": "Make a Spellcast Roll (16). Once per long rest on a success, choose a point within Far range and create a visible zone of protection there for all allies within Very Close range of that point. When you do, place a d6 on this card with the 1 value facing up. When an ally in this zone takes damage, they reduce it by the die’s value. You then increase the die’s value by one. When the die’s value would exceed 6, this effect ends."
8
+
}
+22
srd/classes/guardian.json
+22
srd/classes/guardian.json
···
1
+
{
2
+
"id": "guardian",
3
+
"name": "Guardian",
4
+
"description": "The title of guardian represents an array of martial professions, speaking more to their moral compass and unshakeable fortitude than the means by which they fight. While many guardians join groups of militants for either a country or cause, they’re more likely to follow those few they truly care for, majority be damned. Guardians are known for fighting with remarkable ferocity even against overwhelming odds, defending their cohort above all else. Woe betide those who harm the ally of a guardian, as the guardian will answer this injury in kind.",
5
+
"domains": ["valor", "blade"],
6
+
"starting_evasion": 9,
7
+
"starting_hp": 7,
8
+
"class_items": ["a totem from your mentor", "a secret key"],
9
+
"hope_feature": "**Frontline Tank:** Spend 3 Hope to clear 2 Armor Slots.",
10
+
"class_feature": "Unstoppable: Once per long rest, you can become Unstoppable. You gain an Unstoppable Die. At level 1, your Unstoppable Die is a d4. Place it on your character sheet in the space provided, starting with the 1 value facing up. After you make a damage roll that deals 1 or more Hit Points to a target, increase the Unstoppable Die value by one. When the die’s value would exceed its maximum value or when the scene ends, remove the die and drop out of Unstoppable. At level 5, your Unstoppable Die increases to a d6.\nWhile Unstoppable, you gain the following benefits:\n- You reduce the severity of physical damage by one threshold (Severe to Major, Major to Minor, Minor to None).\n- You add the current value of the Unstoppable Die to your damage roll.\n- You can’t be Restrained or Vulnerable.\n> Tip: If your Unstoppable Die is a d4 and the 4 is currently facing up, you remove the die the next time you would increase it. However, if your Unstoppable Die has increased to a d6 and the 4 is currently facing up, you’ll turn it to 5 the next time you would increase it. In this case, you’ll remove the die after you would need to increase it higher than 6.",
11
+
"subclasses": ["stalwart", "vengeance"],
12
+
"background_questions": [
13
+
"Who from your community did you fail to protect, and why do you still think of them?",
14
+
"You’ve been tasked with protecting something important and delivering it somewhere dangerous. What is it, and where does it need to go?",
15
+
"You consider an aspect of yourself to be a weakness. What is it, and how has it affected you?"
16
+
],
17
+
"connections": [
18
+
"How did I save your life the first time we met?",
19
+
"What small gift did you give me that you notice I always carry with me?",
20
+
"What lie have you told me about yourself that I absolutely believe?"
21
+
]
22
+
}
+1
web/.gitignore
+1
web/.gitignore
···
1
+
build/
+15
web/README.md
+15
web/README.md
···
1
+
# Web
2
+
3
+
Easy browsable version of the SRD as a website, optionally contains documentation for the API as well.
4
+
5
+
## Requirements
6
+
- Gleam v1.12.0 or greater
7
+
8
+
## Running
9
+
```bash
10
+
gleam run
11
+
```
12
+
13
+
Set the `KATARI_API_DOCS` environment variable to `true` to enable them.
14
+
15
+
If using a non-standard location for your SRD directory, this can be specified with the `KATARI_SRD_PATH`. It will default to `../srd` otherwise.
+26
web/gleam.toml
+26
web/gleam.toml
···
1
+
name = "web"
2
+
version = "1.0.0"
3
+
4
+
# Fill out these fields if you intend to generate HTML documentation or publish
5
+
# your project to the Hex package manager.
6
+
#
7
+
# description = ""
8
+
# licences = ["Apache-2.0"]
9
+
# repository = { type = "github", user = "", repo = "" }
10
+
# links = [{ title = "Website", href = "" }]
11
+
#
12
+
# For a full reference of all the available options, you can have a look at
13
+
# https://gleam.run/writing-gleam/gleam-toml/.
14
+
15
+
[dependencies]
16
+
gleam_stdlib = ">= 0.44.0 and < 2.0.0"
17
+
lustre = ">= 5.3.3 and < 6.0.0"
18
+
wisp = ">= 1.8.0 and < 2.0.0"
19
+
gleam_erlang = ">= 1.3.0 and < 2.0.0"
20
+
envoy = ">= 1.0.2 and < 2.0.0"
21
+
mist = ">= 5.0.3 and < 6.0.0"
22
+
shared = { path = "../shared" }
23
+
gleam_http = ">= 4.1.1 and < 5.0.0"
24
+
25
+
[dev-dependencies]
26
+
gleeunit = ">= 1.0.0 and < 2.0.0"
+41
web/manifest.toml
+41
web/manifest.toml
···
1
+
# This file was generated by Gleam
2
+
# You typically do not need to edit this file
3
+
4
+
packages = [
5
+
{ name = "directories", version = "1.2.0", build_tools = ["gleam"], requirements = ["envoy", "gleam_stdlib", "platform", "simplifile"], otp_app = "directories", source = "hex", outer_checksum = "D13090CFCDF6759B87217E8DDD73A75903A700148A82C1D33799F333E249BF9E" },
6
+
{ name = "envoy", version = "1.0.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "envoy", source = "hex", outer_checksum = "95FD059345AA982E89A0B6E2A3BF1CF43E17A7048DCD85B5B65D3B9E4E39D359" },
7
+
{ name = "exception", version = "2.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "exception", source = "hex", outer_checksum = "329D269D5C2A314F7364BD2711372B6F2C58FA6F39981572E5CA68624D291F8C" },
8
+
{ name = "filepath", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "B06A9AF0BF10E51401D64B98E4B627F1D2E48C154967DA7AF4D0914780A6D40A" },
9
+
{ name = "gleam_crypto", version = "1.5.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_crypto", source = "hex", outer_checksum = "50774BAFFF1144E7872814C566C5D653D83A3EBF23ACC3156B757A1B6819086E" },
10
+
{ name = "gleam_erlang", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "1124AD3AA21143E5AF0FC5CF3D9529F6DB8CA03E43A55711B60B6B7B3874375C" },
11
+
{ name = "gleam_http", version = "4.1.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_http", source = "hex", outer_checksum = "DD0271B32C356FB684EC7E9F48B1E835D0480168848581F68983C0CC371405D4" },
12
+
{ name = "gleam_json", version = "3.0.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "874FA3C3BB6E22DD2BB111966BD40B3759E9094E05257899A7C08F5DE77EC049" },
13
+
{ name = "gleam_otp", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "7987CBEBC8060B88F14575DEF546253F3116EBE2A5DA6FD82F38243FCE97C54B" },
14
+
{ name = "gleam_stdlib", version = "0.62.1", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "0080706D3A5A9A36C40C68481D1D231D243AF602E6D2A2BE67BA8F8F4DFF45EC" },
15
+
{ name = "gleam_yielder", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_yielder", source = "hex", outer_checksum = "8E4E4ECFA7982859F430C57F549200C7749823C106759F4A19A78AEA6687717A" },
16
+
{ name = "gleeunit", version = "1.6.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "FDC68A8C492B1E9B429249062CD9BAC9B5538C6FBF584817205D0998C42E1DAC" },
17
+
{ name = "glisten", version = "8.0.1", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_otp", "gleam_stdlib", "logging", "telemetry"], otp_app = "glisten", source = "hex", outer_checksum = "534BB27C71FB9E506345A767C0D76B17A9E9199934340C975DC003C710E3692D" },
18
+
{ name = "gramps", version = "6.0.0", build_tools = ["gleam"], requirements = ["gleam_crypto", "gleam_erlang", "gleam_http", "gleam_stdlib"], otp_app = "gramps", source = "hex", outer_checksum = "8B7195978FBFD30B43DF791A8A272041B81E45D245314D7A41FC57237AA882A0" },
19
+
{ name = "houdini", version = "1.2.0", build_tools = ["gleam"], requirements = [], otp_app = "houdini", source = "hex", outer_checksum = "5DB1053F1AF828049C2B206D4403C18970ABEF5C18671CA3C2D2ED0DD64F6385" },
20
+
{ name = "hpack_erl", version = "0.3.0", build_tools = ["rebar3"], requirements = [], otp_app = "hpack", source = "hex", outer_checksum = "D6137D7079169D8C485C6962DFE261AF5B9EF60FBC557344511C1E65E3D95FB0" },
21
+
{ name = "logging", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "logging", source = "hex", outer_checksum = "1098FBF10B54B44C2C7FDF0B01C1253CAFACDACABEFB4B0D027803246753E06D" },
22
+
{ name = "lustre", version = "5.3.3", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_json", "gleam_otp", "gleam_stdlib", "houdini"], otp_app = "lustre", source = "hex", outer_checksum = "AB9203869B3F00D288995DF936F0154A4B88C794803C7A0CFCD641B3A80515F1" },
23
+
{ name = "marceau", version = "1.3.0", build_tools = ["gleam"], requirements = [], otp_app = "marceau", source = "hex", outer_checksum = "2D1C27504BEF45005F5DFB18591F8610FB4BFA91744878210BDC464412EC44E9" },
24
+
{ name = "mist", version = "5.0.3", build_tools = ["gleam"], requirements = ["exception", "gleam_erlang", "gleam_http", "gleam_otp", "gleam_stdlib", "gleam_yielder", "glisten", "gramps", "hpack_erl", "logging"], otp_app = "mist", source = "hex", outer_checksum = "7C4BE717A81305323C47C8A591E6B9BA4AC7F56354BF70B4D3DF08CC01192668" },
25
+
{ name = "platform", version = "1.0.0", build_tools = ["gleam"], requirements = [], otp_app = "platform", source = "hex", outer_checksum = "8339420A95AD89AAC0F82F4C3DB8DD401041742D6C3F46132A8739F6AEB75391" },
26
+
{ name = "shared", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib", "simplifile"], source = "local", path = "../shared" },
27
+
{ name = "simplifile", version = "2.3.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "0A868DAC6063D9E983477981839810DC2E553285AB4588B87E3E9C96A7FB4CB4" },
28
+
{ name = "telemetry", version = "1.3.0", build_tools = ["rebar3"], requirements = [], otp_app = "telemetry", source = "hex", outer_checksum = "7015FC8919DBE63764F4B4B87A95B7C0996BD539E0D499BE6EC9D7F3875B79E6" },
29
+
{ name = "wisp", version = "1.8.0", build_tools = ["gleam"], requirements = ["directories", "exception", "gleam_crypto", "gleam_erlang", "gleam_http", "gleam_json", "gleam_stdlib", "houdini", "logging", "marceau", "mist", "simplifile"], otp_app = "wisp", source = "hex", outer_checksum = "0FE9049AFFB7C8D5FC0B154EEE2704806F4D51B97F44925D69349B3F4F192957" },
30
+
]
31
+
32
+
[requirements]
33
+
envoy = { version = ">= 1.0.2 and < 2.0.0" }
34
+
gleam_erlang = { version = ">= 1.3.0 and < 2.0.0" }
35
+
gleam_http = { version = ">= 4.1.1 and < 5.0.0" }
36
+
gleam_stdlib = { version = ">= 0.44.0 and < 2.0.0" }
37
+
gleeunit = { version = ">= 1.0.0 and < 2.0.0" }
38
+
lustre = { version = ">= 5.3.3 and < 6.0.0" }
39
+
mist = { version = ">= 5.0.3 and < 6.0.0" }
40
+
shared = { path = "../shared" }
41
+
wisp = { version = ">= 1.8.0 and < 2.0.0" }
+38
web/src/web.gleam
+38
web/src/web.gleam
···
1
+
import envoy
2
+
import gleam/erlang/process
3
+
import gleam/result
4
+
import gleam/string
5
+
import mist
6
+
import shared/data
7
+
import web/router
8
+
import wisp
9
+
import wisp/wisp_mist
10
+
11
+
pub fn main() {
12
+
wisp.configure_logger()
13
+
let skb = wisp.random_string(64)
14
+
15
+
let api_docs = result.unwrap(envoy.get("KATARI_API_DOCS"), "False")
16
+
17
+
use api_docs <- result.try(string_to_bool(api_docs))
18
+
19
+
let data_dir = result.unwrap(envoy.get("KATARI_SRD_PATH"), "../srd/")
20
+
let assert Ok(data) = data.read_data_dir(data_dir)
21
+
as { "Failed to read data directory " <> data_dir }
22
+
23
+
let assert Ok(_) =
24
+
wisp_mist.handler(router.handle_request(_, data, api_docs), skb)
25
+
|> mist.new()
26
+
|> mist.port(8080)
27
+
|> mist.start()
28
+
29
+
Ok(process.sleep_forever())
30
+
}
31
+
32
+
fn string_to_bool(string string: String) -> Result(Bool, Nil) {
33
+
case string |> string.lowercase() {
34
+
"true" -> Ok(True)
35
+
"false" -> Ok(False)
36
+
_ -> Error(Nil)
37
+
}
38
+
}
+48
web/src/web/pages/abilities.gleam
+48
web/src/web/pages/abilities.gleam
···
1
+
import gleam/int
2
+
import gleam/list
3
+
import lustre/attribute as attr
4
+
import lustre/element/html
5
+
import shared/data
6
+
import web/pages/not_found
7
+
8
+
pub fn all(data: data.Data) {
9
+
html.div([], [
10
+
html.h1([], [html.text("all abilities")]),
11
+
html.ul(
12
+
[],
13
+
list.map(data.abilities, fn(ability) {
14
+
html.li([], [
15
+
html.a([attr.href("/abilities/" <> ability.id)], [
16
+
html.text(ability.name),
17
+
]),
18
+
])
19
+
}),
20
+
),
21
+
])
22
+
}
23
+
24
+
pub fn single(id: String, data: data.Data) {
25
+
let ability =
26
+
data.abilities
27
+
|> list.find(fn(ability) { ability.id == id })
28
+
29
+
case ability {
30
+
Error(_) -> not_found.not_found(data)
31
+
Ok(ability) ->
32
+
html.div([], [
33
+
html.h1([], [html.text(ability.name)]),
34
+
html.h2([], [html.text("Level: " <> int.to_string(ability.level))]),
35
+
html.h2([], [
36
+
html.text("Recall Cost: " <> int.to_string(ability.recall_cost)),
37
+
]),
38
+
// TODO: Resolve if given domain exists from data and then
39
+
// use the name instead of the ID if it does
40
+
html.h2([], [
41
+
html.a([attr.href("/domains/" <> ability.domain)], [
42
+
html.text(ability.domain),
43
+
]),
44
+
]),
45
+
html.p([], [html.text(ability.description)]),
46
+
])
47
+
}
48
+
}
+36
web/src/web/pages/classes.gleam
+36
web/src/web/pages/classes.gleam
···
1
+
import gleam/list
2
+
import lustre/attribute as attr
3
+
import lustre/element/html
4
+
import shared/data
5
+
import web/pages/not_found
6
+
7
+
pub fn all(data: data.Data) {
8
+
html.div([], [
9
+
html.h1([], [html.text("all classes")]),
10
+
html.ul(
11
+
[],
12
+
list.map(data.classes, fn(class) {
13
+
html.li([], [
14
+
html.a([attr.href("/classes/" <> class.id)], [
15
+
html.text(class.name),
16
+
]),
17
+
])
18
+
}),
19
+
),
20
+
])
21
+
}
22
+
23
+
pub fn single(id: String, data: data.Data) {
24
+
let class =
25
+
data.classes
26
+
|> list.find(fn(class) { class.id == id })
27
+
28
+
case class {
29
+
Error(_) -> not_found.not_found(data)
30
+
Ok(class) ->
31
+
html.div([], [
32
+
html.h1([], [html.text(class.name)]),
33
+
html.p([], [html.text(class.description)]),
34
+
])
35
+
}
36
+
}
+3
web/src/web/pages/docs/docs.gleam
+3
web/src/web/pages/docs/docs.gleam
+17
web/src/web/pages/home.gleam
+17
web/src/web/pages/home.gleam
···
1
+
import lustre/attribute as attr
2
+
import lustre/element/html
3
+
import shared/data
4
+
5
+
pub fn home(_data: data.Data) {
6
+
html.div([], [
7
+
html.h1([], [html.text("Homepage")]),
8
+
html.ul([], [
9
+
html.li([], [
10
+
html.a([attr.href("/abilities")], [html.text("Abilities")]),
11
+
]),
12
+
html.li([], [
13
+
html.a([attr.href("/classes")], [html.text("Classes")]),
14
+
]),
15
+
]),
16
+
])
17
+
}
+6
web/src/web/pages/not_found.gleam
+6
web/src/web/pages/not_found.gleam
+41
web/src/web/router.gleam
+41
web/src/web/router.gleam
···
1
+
import gleam/http
2
+
import lustre/attribute as attr
3
+
import lustre/element
4
+
import lustre/element/html
5
+
import shared/data
6
+
import web/pages/abilities
7
+
import web/pages/classes
8
+
import web/pages/docs/docs
9
+
import web/pages/home
10
+
import web/pages/not_found
11
+
import web/web
12
+
import wisp
13
+
14
+
pub fn page(data: data.Data, contents: fn(data.Data) -> element.Element(b)) {
15
+
let page =
16
+
html.html([], [
17
+
html.body([], [
18
+
html.h1([], [html.a([attr.href("/")], [html.text("Daggerheart SRD")])]),
19
+
contents(data),
20
+
]),
21
+
])
22
+
wisp.html_response(element.to_document_string_tree(page), 200)
23
+
}
24
+
25
+
pub fn handle_request(
26
+
req: wisp.Request,
27
+
data: data.Data,
28
+
api_docs: Bool,
29
+
) -> wisp.Response {
30
+
use req <- web.middleware(req)
31
+
use <- wisp.require_method(req, http.Get)
32
+
case wisp.path_segments(req) {
33
+
[] -> page(data, home.home)
34
+
["abilities"] -> page(data, abilities.all)
35
+
["abilities", query] -> page(data, abilities.single(query, _))
36
+
["classes"] -> page(data, classes.all)
37
+
["classes", query] -> page(data, classes.single(query, _))
38
+
["docs", ..rest] if api_docs -> docs.docs_router(req, rest, data)
39
+
_ -> page(data, not_found.not_found)
40
+
}
41
+
}
+12
web/src/web/web.gleam
+12
web/src/web/web.gleam
···
1
+
import wisp
2
+
3
+
pub fn middleware(
4
+
req: wisp.Request,
5
+
handle_request: fn(wisp.Request) -> wisp.Response,
6
+
) {
7
+
let req = wisp.method_override(req)
8
+
use <- wisp.log_request(req)
9
+
use <- wisp.rescue_crashes()
10
+
use req <- wisp.handle_head(req)
11
+
handle_request(req)
12
+
}
+13
web/test/web_test.gleam
+13
web/test/web_test.gleam