zenno/doc/spark: spark explorer

This commit is contained in:
2026-07-07 15:51:28 -04:00
parent 5cbb6d7b1d
commit 0c518a9ce2
2 changed files with 171 additions and 6 deletions
+100 -6
View File
@@ -28,22 +28,116 @@ export interface Spark {
* Spark type.
* Roughly the spark color, with extra subdivisions for white sparks.
*/
type: 1 | 2 | 5 | 4 | 6 | 7 | 10 | 8 | 11 | 9 | 3;
type: Type;
/**
* Possible effects applied by the spark during inspiration.
* A random element is selected from this list according to unknown
* distributions, then all effects in that selection are applied.
*/
effects: SparkEffect[][];
effects: Effect[][];
}
/**
* Spark types.
* Roughly the spark color, with extra subdivisions for white sparks.
*/
export enum Type {
Stat = 1,
Aptitude = 2,
Unique = 3,
Skill = 4,
Race = 5,
Scenario = 6,
CarnivalBonus = 7,
Distance = 8,
Hidden = 9,
Surface = 10,
Style = 11,
}
/** Mapping of spark types to their names. */
export const TYPE_NAMES: Readonly<Record<Type, string>> = {
[Type.Stat]: 'Stat (Blue)',
[Type.Aptitude]: 'Aptitude (Pink)',
[Type.Unique]: 'Unique (Green)',
[Type.Skill]: 'Skill',
[Type.Race]: 'Race',
[Type.Scenario]: 'Scenario',
[Type.CarnivalBonus]: 'Carnival Bonus (Scarlet)',
[Type.Distance]: 'Distance (White)',
[Type.Hidden]: 'Hidden (White)',
[Type.Surface] : 'Surface (White)',
[Type.Style] : 'Style (White)',
};
/**
* Spark effect types.
*/
export enum Target {
Speed = 1,
Stamina = 2,
Power = 3,
Guts = 4,
Wit = 5,
SkillPoints = 6,
RandomStat = 7,
Turf = 11,
Dirt = 12,
FrontRunner = 21,
PaceChaser = 22,
LateSurger = 23,
EndCloser = 24,
Sprint = 31,
Mile = 32,
Medium = 33,
Long = 34,
Skill = 41,
CarnivalBonus = 51,
SpeedCap = 61,
StaminaCap = 62,
PowerCap = 63,
GutsCap = 64,
WitCap = 65,
}
/**
* Mapping of spark target types to their names.
* Note that Skill does not include the skill name.
*/
export const TARGET_NAMES: Readonly<Record<Target, string>> = {
[Target.Speed]: 'Speed',
[Target.Stamina]: 'Stamina',
[Target.Power]: 'Power',
[Target.Guts]: 'Guts',
[Target.Wit]: 'Wit',
[Target.SkillPoints]: 'SP',
[Target.RandomStat]: 'Random Stat',
[Target.Turf]: 'Turf aptitude',
[Target.Dirt]: 'Dirt aptitude',
[Target.FrontRunner]: 'Front Runner aptitude',
[Target.PaceChaser]: 'Pace Chaser aptitude',
[Target.LateSurger]: 'Late Surger aptitude',
[Target.EndCloser]: 'End Closer aptitude',
[Target.Sprint]: 'Sprint aptitude',
[Target.Mile]: 'Mile aptitude',
[Target.Medium]: 'Medium aptitude',
[Target.Long]: 'Long aptitude',
[Target.Skill]: 'hint level',
[Target.CarnivalBonus]: 'Carnival Bonus level',
[Target.SpeedCap]: 'Speed cap',
[Target.StaminaCap]: 'Stamina cap',
[Target.PowerCap]: 'Power cap',
[Target.GutsCap]: 'Guts cap',
[Target.WitCap]: 'Wit cap',
}
/**
* Effects that a spark can apply.
*/
export interface SparkEffect {
target: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 21 | 22 | 23 | 24 | 31 | 32 | 33 | 34 | 41 | 51 | 61 | 62 | 63 | 64 | 65;
value1?: number;
value2: number;
export interface Effect {
target: Target;
value1: number;
value2?: number;
}
export async function sparks(): Promise<Spark[]> {
+71
View File
@@ -0,0 +1,71 @@
<script lang="ts">
import * as skill from '$lib/data/skill';
import * as spark from '$lib/data/spark';
import { onMount } from 'svelte';
import { SvelteMap } from 'svelte/reactivity';
let sparks: spark.Spark[] = $state([]);
let skills: SvelteMap<number, skill.Skill> = new SvelteMap();
onMount(async () => {
const [sp, sk] = await Promise.all([spark.sparks(), skill.skills()]);
sparks = sp;
for (const s of sk) {
skills.set(s.skill_id, s);
}
});
let group = $state(1);
const groups = $derived.by(() => {
const m = new Map<number, spark.Spark[]>();
for (const s of sparks) {
const l = m.get(s.spark_group) ?? [];
l.push(s);
m.set(s.spark_group, l);
}
return [...m.entries()];
});
function describe(eff: spark.Effect) {
if (eff.target === spark.Target.Skill) {
const sk = skills.get(eff.value1);
return `${sk?.name} ${spark.TARGET_NAMES[eff.target]} +${eff.value2}`;
}
return `${spark.TARGET_NAMES[eff.target]} +${eff.value1}`;
}
const cur = $derived(sparks.find((s) => s.spark_group === group));
const curEffectGroups = $derived(cur?.effects ?? []);
const curDescriptions = $derived(curEffectGroups.map((g) => g.map((e) => describe(e))));
</script>
<h1 class="text-4xl">Spark Explorer</h1>
<form class="mx-auto mt-8 p-4 rounded-md text-center shadow-md ring md:max-w-2xl">
<select class="w-full" bind:value={group}>
{#each groups as [id, s] (id)}
<option value={id}>{s[0].name}</option>
{/each}
</select>
</form>
<svelte:boundary>
<div class="mx-auto mt-8 max-w-md flex-1 flex-col rounded-md border p-2 text-center shadow-sm transition-shadow hover:shadow-md">
<span class="block text-xl">{cur?.name}</span>
<span class="block">{cur?.description}</span>
</div>
<table class="mx-auto w-full max-w-xl mt-8 table-fixed">
<caption class="text-xl">Possible Effects</caption>
<tbody>
{#each curDescriptions as s (s)}
<tr class="text-center even:bg-mist-300 dark:even:bg-mist-900">
<td>
{#each s as n (n)}
<span class="block">{n}</span>
{/each}
</td>
</tr>
{/each}
</tbody>
</table>
{#snippet pending()}
<div>Loading data...</div>
{/snippet}
</svelte:boundary>