A configuration-driven character viewer for Pathfinder 2e characters created with Pathbuilder.
This application allows you to import and compare Pathfinder 2e characters exported from Pathbuilder. It uses a fully configuration-driven approach where nearly all logic is defined in YAML configuration files rather than hardcoded JavaScript.
- Import characters from JSON files or clipboard
- Compare characters side-by-side with their key attributes
- Highlight highest values among party members
- Show party composition warnings and suggestions
- Display "tenuous tips" for party abilities
- Fully configurable display through YAML configuration
The application uses a configuration-driven architecture where:
- Data structure and extraction rules are defined in YAML
- UI layout and display options are defined in YAML
- Formulas and calculations are defined in YAML
- JavaScript only provides the core engine that processes the configuration
- Table Structure: Defines sections, columns, and their display properties
- Preprocessing Rules: Define how to extract and compute values from character data
- Template System: Defines how to display and format values
- Extractor Functions: Define reusable calculations for character attributes
The main configuration file is config/table-structure.yaml, which has the following structure:
# Global definitions
globals:
# Common configurations used across the system
# Preprocessing rules
preprocessing:
# Extractors define reusable functions
extractors:
# ...
# Extracted fields define what data to extract from characters
extractedFields:
# ...
# Table structure
sections:
# UI sections definition
- id: section_id
title: "Section Title"
icon: section_icon
columns:
# Column definitions
- id: column_id
title: "Column Title"
# ...The system supports several types of calculations that can be defined in the configuration:
Access values directly from the character data:
jsonPath: build.abilities.strCalculate values with a formula:
formula: "sum"
params:
values: ["build.attributes.speed", "build.attributes.speedBonus"]Apply formatting to values using templates:
template: "{value} ({abilityModifier(value)|modifier})"Extract and transform complex data structures:
formula: "extractArchetypes"
params:
feats: "build.feats"The template system allows you to format values with a powerful syntax:
{variableName|transform1|transform2=param1,param2}
variableName: The variable to display (e.g.,value)transform: Optional transform to apply (can chain multiple)param1,param2: Optional parameters for the transform
These functions can be called within templates:
| Function | Description | Example |
|---|---|---|
abilityModifier |
Calculates ability modifier from score | {abilityModifier(value)} |
formatModifier |
Formats a number as a modifier (+/-) | {value|modifier} |
calculateSpeed |
Calculates total speed | {calculateSpeed(character)} |
These transforms can be applied to values:
| Transform | Description | Example |
|---|---|---|
prefix |
Adds a prefix to a value | {value|prefix=+} |
modifier |
Formats as +/- modifier | {value|modifier} |
units |
Adds units to a value | {value|units=ft} |
format |
Applies a format string | {value|format=%s ft} |
conditional |
Shows different text based on value | {value|conditional=Yes,No} |
These formula types can be used in extractors and computed values:
Adds multiple values together:
formula: "sum"
params:
values: ["path.to.value1", "path.to.value2"]Calculates skill bonuses with level scaling:
formula: "skillCalculation"
params:
profValue: "build.proficiencies.acrobatics"
abilityMod: "abilityModifier(build.abilities.dex)"
level: "build.level"
itemBonus: "build.mods.Acrobatics['Item Bonus']"Define a custom JavaScript formula:
formula: "Math.floor((value - 10) / 2)"The system supports various display types for columns:
| Display Type | Description |
|---|---|
pill |
Displays value in a colored pill |
pill-list |
Displays array values as colored pills |
proficiency-badge |
Shows value with proficiency badge |
proficiency-pill-list |
Shows list with proficiency badges |
lore-proficiency-list |
Special display for lore skills |
action-buttons |
Shows action buttons (e.g., delete) |
- Add a new column definition to the appropriate section in
config/table-structure.yaml:
- id: new_column
title: "New Column"
icon: icon-name
jsonPath: path.to.value
highestValue: true- Add a new extractor in the preprocessing section:
extractors:
newCalculation:
formula: "your calculation logic"
description: "What this calculation does"- Add a new extracted field that uses this extractor:
extractedFields:
newField:
type: "value"
formula: "newCalculation"
params:
param1: "value1"- Create a new helper function in script.js
- Add the display type to your column configuration
- id: str
title: STR
icon: dumbbell
jsonPath: build.abilities.str
template: "{value} ({abilityModifier(value)|modifier})"
highestValue: true- id: speed
title: Speed
icon: person-running
jsonPath: extracted.speed
template: "{value|units=ft}"
highestValue: true- id: acrobatics
title: Acro
icon: person-falling
jsonPath: extracted.skills.acrobatics
proficiencyPath: extracted.skillProficiencies.acrobatics
showProficiency: true
displayType: proficiency-badge
highestValue: trueYou can extend the system by:
- Adding new global configurations
- Creating new extraction methods in JavaScript
- Registering new template functions
- Adding new transform types
Follow the existing patterns in the code to ensure compatibility.
- Use fallback values in paths:
build.abilities.str || 10 - Combine multiple transforms:
{value|modifier|prefix=} - Use conditional displays:
{value|conditional=Has darkvision,No darkvision} - Format complex data:
{value|format=%s feet}
If values aren't displaying correctly:
- Check console for debugging information
- Verify your JSON paths against the actual character data
- Make sure extractors and parameters are correctly defined
- Try adding fallback values to prevent "undefined" issues