zenno: use data from api

This commit is contained in:
2026-06-05 14:31:10 -04:00
parent 871fd5fdcc
commit a848c8eb72
15 changed files with 369 additions and 322 deletions

View File

@@ -44,7 +44,7 @@ func main() {
level slog.Level level slog.Level
textfmt string textfmt string
) )
flag.StringVar(&addr, "http", ":80", "`address` to bind HTTP server") flag.StringVar(&addr, "http", ":13669", "`address` to bind HTTP server")
flag.StringVar(&mdbf, "mdb", "", "`path` to master.mdb") flag.StringVar(&mdbf, "mdb", "", "`path` to master.mdb")
flag.StringVar(&public, "public", "", "`dir`ectory containing the website to serve") flag.StringVar(&public, "public", "", "`dir`ectory containing the website to serve")
flag.StringVar(&tokenFile, "token", "", "`file` containing the Discord bot token") flag.StringVar(&tokenFile, "token", "", "`file` containing the Discord bot token")
@@ -154,7 +154,7 @@ func main() {
} }
srv := http.Server{ srv := http.Server{
Addr: addr, Addr: addr,
Handler: mux, Handler: httpmiddle.Logger(mux),
ReadTimeout: 15 * time.Second, ReadTimeout: 15 * time.Second,
WriteTimeout: 15 * time.Second, WriteTimeout: 15 * time.Second,
BaseContext: func(l net.Listener) context.Context { return ctx }, BaseContext: func(l net.Listener) context.Context { return ctx },

View File

@@ -4,7 +4,7 @@
interface Props { interface Props {
id: string; id: string;
characters: Character[]; characters: Character[] | null;
value: number; value: number;
class?: ClassValue | null; class?: ClassValue | null;
optionClass?: ClassValue | null; optionClass?: ClassValue | null;
@@ -18,7 +18,7 @@
{#if !required} {#if !required}
<option value="0" class={optionClass}></option> <option value="0" class={optionClass}></option>
{/if} {/if}
{#each characters as c (c.chara_id)} {#each characters ?? [] as c (c.chara_id)}
<option value={c.chara_id} class={optionClass}>{c.name}</option> <option value={c.chara_id} class={optionClass}>{c.name}</option>
{/each} {/each}
</select> </select>

View File

@@ -3,39 +3,37 @@
ABILITY_SCALE_NAME, ABILITY_SCALE_NAME,
ABILITY_TYPE_FORMAT, ABILITY_TYPE_FORMAT,
DURATION_SCALE_NAME, DURATION_SCALE_NAME,
skills,
Target, Target,
TARGET_FORMAT, TARGET_FORMAT,
tenThousandths, tenThousandths,
ZERO_SKILL,
type Ability, type Ability,
type Skill, type Skill,
} from './data/skill'; } from './data/skill';
interface CommonProps { interface Props {
hint?: string; skill: Skill | null | undefined;
mention?: boolean; mention?: boolean;
} }
type Props = CommonProps & ({ skill: number; name?: never } | { name: string; skill?: never }); const ZERO_SKILL: Skill = {
skill_id: 0,
name: 'Skill data is loading...',
description: 'Skill data is still loading, or else something went wrong.',
group: 0,
rarity: 1,
group_rate: 1,
wit_check: false,
activations: [],
icon_id: 0,
};
let { hint, mention, skill, name }: Props = $props(); let { mention, skill }: Props = $props();
function splitCond(c: string): string[] { function splitCond(c: string): string[] {
return c.replaceAll('&', ' & ').split('@'); return c.replaceAll('&', ' & ').split('@');
} }
const s: Readonly<Skill> = $derived.by(() => { const s = $derived(skill ?? ZERO_SKILL);
const l =
skill != null ? skills.global.filter((s) => s.skill_id === skill) : skills.global.filter((s) => s.name.includes(name!));
if (name != null) {
console.warn(`skills specified as ${name} (${hint}):`, l);
}
if (l.length === 0) {
return ZERO_SKILL;
}
return l[0];
});
const activationClass = $derived(s.activations.length === 1 ? null : 'block my-2 border rounded-md'); const activationClass = $derived(s.activations.length === 1 ? null : 'block my-2 border rounded-md');
const spanClass = $derived(mention ? 'italic' : 'font-bold'); const spanClass = $derived(mention ? 'italic' : 'font-bold');

View File

@@ -1,19 +1,17 @@
<script lang="ts"> <script lang="ts">
import { sparks } from '$lib/data/spark'; import { type Spark } from '$lib/data/spark';
interface Props { interface Props {
spark: number; spark: Spark | null | undefined;
region?: keyof typeof sparks;
} }
const { spark, region = 'global' }: Props = $props(); const { spark }: Props = $props();
const cur = $derived(sparks[region].find((s) => s.spark_id === spark));
const curClass = $derived.by(() => { const curClass = $derived.by(() => {
if (cur == null) { if (spark == null) {
return []; return [];
} }
switch (cur.type) { switch (spark.type) {
case 1: case 1:
return ['stat']; return ['stat'];
case 2: case 2:
@@ -32,17 +30,17 @@
return []; return [];
} }
}); });
const stars = $derived('★'.repeat(cur?.rarity ?? 0)); const stars = $derived('★'.repeat(spark?.rarity ?? 0));
</script> </script>
{#if cur != null} {#if spark != null}
<div <div
class={[ class={[
curClass, curClass,
'spark mx-1 flex items-center rounded-xl px-2 py-1 transition ease-in hover:shadow-md hover:ease-out motion-safe:duration-75 motion-safe:hover:-translate-y-0.5 dark:shadow-neutral-950', 'spark mx-1 flex items-center rounded-xl px-2 py-1 transition ease-in hover:shadow-md hover:ease-out motion-safe:duration-75 motion-safe:hover:-translate-y-0.5 dark:shadow-neutral-950',
]} ]}
> >
<span>{cur.name}</span> <span>{spark.name}</span>
<span class="ml-2 text-xl text-amber-800 text-shadow-md dark:text-amber-300">{stars}</span> <span class="ml-2 text-xl text-amber-800 text-shadow-md dark:text-amber-300">{stars}</span>
</div> </div>
{/if} {/if}

View File

@@ -1,5 +1,3 @@
import globalJSON from '../../../../global/affinity.json';
/** /**
* Precomputed character pair and trio affinity. * Precomputed character pair and trio affinity.
*/ */
@@ -24,9 +22,10 @@ export interface Affinity {
affinity: number; affinity: number;
} }
export const affinity = { export async function affinity(): Promise<Affinity[]> {
global: globalJSON as Affinity[], const resp = await fetch('/api/global/affinity');
} as const; return resp.json();
}
export function lookup(aff: Affinity[], chara_a: number, chara_b: number, chara_c?: number): number { export function lookup(aff: Affinity[], chara_a: number, chara_b: number, chara_c?: number): number {
const [a, b, c] = [chara_a, chara_b, chara_c ?? Infinity].sort((a, b) => a - b); const [a, b, c] = [chara_a, chara_b, chara_c ?? Infinity].sort((a, b) => a - b);

View File

@@ -1,5 +1,4 @@
import type { RegionalName } from '$lib/regional-name'; import type { RegionalName } from '$lib/regional-name';
import globalJSON from '../../../../global/character.json';
/** /**
* Character definitions. * Character definitions.
@@ -16,11 +15,11 @@ export interface Character {
name: string; name: string;
} }
export const character = { export async function character(): Promise<Character[]> {
global: globalJSON as Character[], const resp = await fetch('/api/global/character');
}; return resp.json();
}
export const charaNames = globalJSON.reduce( export function charaNames(charas: Character[]) {
(m, c) => m.set(c.chara_id, { en: c.name }), return charas.reduce((m, c) => m.set(c.chara_id, { en: c.name }), new Map<number, RegionalName>());
new Map<Character['chara_id'], RegionalName>(), }
);

View File

@@ -1,5 +1,4 @@
import type { RegionalName } from '$lib/regional-name'; import type { RegionalName } from '$lib/regional-name';
import globalJSON from '../../../../global/conversation.json';
/** /**
* Lobby conversation data. * Lobby conversation data.
@@ -17,10 +16,6 @@ export interface Conversation {
* Location ID of the conversation. * Location ID of the conversation.
*/ */
location: 110 | 120 | 130 | 210 | 220 | 310 | 410 | 420 | 430 | 510 | 520 | 530; location: 110 | 120 | 130 | 210 | 220 | 310 | 410 | 420 | 430 | 510 | 520 | 530;
/**
* English name of the location, for convenience.
*/
location_name: string;
/** /**
* First character in the conversation. * First character in the conversation.
* Not necessarily equal to chara_id. * Not necessarily equal to chara_id.
@@ -40,16 +35,17 @@ export interface Conversation {
condition_type: 0 | 1 | 2 | 3 | 4; condition_type: 0 | 1 | 2 | 3 | 4;
} }
export const conversation = { export async function conversation(): Promise<Conversation[]> {
global: globalJSON as Conversation[], const resp = await fetch('/api/global/conversation');
}; return resp.json();
}
export const byChara = { export function byChara(convos: Conversation[]) {
global: globalJSON.reduce( return convos.reduce(
(m, c) => m.set(c.chara_id, (m.get(c.chara_id) ?? []).concat(c as Conversation)), (m, c) => m.set(c.chara_id, (m.get(c.chara_id) ?? []).concat(c as Conversation)),
new Map<Conversation['chara_id'], Conversation[]>(), new Map<number, Conversation[]>(),
), );
}; }
export const locations: Record<Conversation['location'], { name: RegionalName; group: 1 | 2 | 3 | 4 | 5 }> = { export const locations: Record<Conversation['location'], { name: RegionalName; group: 1 | 2 | 3 | 4 | 5 }> = {
110: { name: { en: 'right side front' }, group: 1 }, 110: { name: { en: 'right side front' }, group: 1 },
@@ -74,12 +70,12 @@ function locCharas(convos: Conversation[], locGroup: 1 | 2 | 3 | 4 | 5) {
return [...m].toSorted((a, b) => b[1] - a[1]); // descending return [...m].toSorted((a, b) => b[1] - a[1]); // descending
} }
export const groupPopulars = { export function groupPopulars(convos: Conversation[]) {
global: { return {
1: locCharas(conversation.global, 1), 1: locCharas(convos, 1),
2: locCharas(conversation.global, 2), 2: locCharas(convos, 2),
3: locCharas(conversation.global, 3), 3: locCharas(convos, 3),
4: locCharas(conversation.global, 4), 4: locCharas(convos, 4),
5: locCharas(conversation.global, 5), 5: locCharas(convos, 5),
}, };
}; }

View File

@@ -1,6 +1,3 @@
import skillGlobal from '../../../../global/skill.json';
import groupGlobal from '../../../../global/skill-group.json';
/** /**
* Skill data. * Skill data.
*/ */
@@ -323,22 +320,12 @@ export interface SkillGroup {
skill_bad?: number; skill_bad?: number;
} }
export const skills = { export async function skills(): Promise<Skill[]> {
global: skillGlobal as Skill[], const resp = await fetch('/api/global/skill');
} as const; return resp.json();
}
export const skillGroups = { export async function skillGroups(): Promise<SkillGroup[]> {
global: groupGlobal as SkillGroup[], const resp = await fetch('/api/global/skill-group');
} as const; return resp.json();
}
export const ZERO_SKILL: Readonly<Skill> = {
skill_id: 0,
name: 'invalid skill',
description: 'an invalid skill was specified',
group: 0,
rarity: 1,
group_rate: 1,
wit_check: false,
activations: [],
icon_id: 0,
} as const;

View File

@@ -1,5 +1,3 @@
import globalJSON from '../../../../global/spark.json';
/** /**
* Sparks, or succession factors. * Sparks, or succession factors.
*/ */
@@ -48,6 +46,7 @@ export interface SparkEffect {
value2: number; value2: number;
} }
export const sparks = { export async function sparks(): Promise<Spark[]> {
global: globalJSON as Spark[], const resp = await fetch('/api/global/spark');
} as const; return resp.json();
}

View File

@@ -1,5 +1,3 @@
import globalJSON from '../../../../global/uma.json';
/** /**
* Uma or character card definitions. * Uma or character card definitions.
*/ */
@@ -70,6 +68,7 @@ export interface Uma {
export type AptitudeLevel = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7; export type AptitudeLevel = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7;
export const uma = { export async function uma(): Promise<Uma[]> {
global: globalJSON as Uma[], const resp = await fetch('/api/global/uma');
}; return resp.json();
}

View File

@@ -1,30 +1,42 @@
<script lang="ts"> <script lang="ts">
import { character, charaNames } from '$lib/data/character'; import { character, charaNames, type Character } from '$lib/data/character';
import { byChara, locations, groupPopulars } from '$lib/data/convo'; import { byChara, locations, groupPopulars, conversation, type Conversation } from '$lib/data/convo';
import CharaPick from '$lib/CharaPick.svelte'; import CharaPick from '$lib/CharaPick.svelte';
import { onMount } from 'svelte';
const characters = character.global.filter((c) => byChara.global.has(c.chara_id)); let conversations: Conversation[] = $state([]);
const convoMap = $derived(byChara(conversations));
const popular = $derived(groupPopulars(conversations));
let characters: Character[] = $state([]);
const names = $derived(charaNames(characters ?? []));
const minSuggest = 8; const minSuggest = 8;
onMount(async () => {
const [convos, charas] = await Promise.all([conversation(), character()]);
conversations = convos;
characters = charas.filter((c) => convoMap.has(c.chara_id));
});
let charaID = $state(1001); let charaID = $state(1001);
let convo = $state(1); let convo = $state(1);
const options = $derived(byChara.global.get(charaID) ?? []); const options = $derived(convoMap.get(charaID) ?? []);
const cur = $derived(options.find((c) => c.number === convo)); const cur = $derived(options.find((c) => c.number === convo));
const cur1Name = $derived(cur?.chara_1 && charaNames.get(cur.chara_1)?.en); const cur1Name = $derived(cur?.chara_1 && names.get(cur.chara_1)?.en);
const cur2Name = $derived(cur?.chara_2 && charaNames.get(cur.chara_2)?.en); const cur2Name = $derived(cur?.chara_2 && names.get(cur.chara_2)?.en);
const cur3Name = $derived(cur?.chara_3 && charaNames.get(cur.chara_3)?.en); const cur3Name = $derived(cur?.chara_3 && names.get(cur.chara_3)?.en);
const alone = $derived([cur?.chara_1, cur?.chara_2, cur?.chara_3].filter((x) => x != null).length == 1 ? ' alone' : ''); const alone = $derived([cur?.chara_1, cur?.chara_2, cur?.chara_3].filter((x) => x != null).length == 1 ? ' alone' : '');
const suggested = $derived.by(() => { const suggested = $derived.by(async () => {
if (cur == null) { if (cur == null) {
return []; return [];
} }
const u = groupPopulars.global[locations[cur.location].group].filter( const u = popular[locations[cur.location].group].filter(
(s) => charaNames.get(s[0]) != null && s[0] !== cur.chara_1 && s[0] !== cur.chara_2 && s[0] !== cur.chara_3, (s) => names.get(s[0]) != null && s[0] !== cur.chara_1 && s[0] !== cur.chara_2 && s[0] !== cur.chara_3,
); );
const r = u.length <= minSuggest ? u : u.filter((s) => s[1] >= u[minSuggest][1]); const r = u.length <= minSuggest ? u : u.filter((s) => s[1] >= u[minSuggest][1]);
return r.map(([chara_id, count]) => ({ chara_id, count })); return r.map(([chara_id, count]) => ({ chara_id, chara_name: names.get(chara_id), count }));
}); });
const curLoc = $derived(cur != null ? locations[cur.location] : null);
</script> </script>
<h1 class="text-4xl">Lobby Conversations</h1> <h1 class="text-4xl">Lobby Conversations</h1>
@@ -42,7 +54,10 @@
</select> </select>
</div> </div>
</div> </div>
{#if cur} {#await suggested}
<div class="mt-4 w-full text-center text-3xl">Loading...</div>
{:then suggested}
{#if cur}
<div class="shadow-sm transition-shadow hover:shadow-md"> <div class="shadow-sm transition-shadow hover:shadow-md">
<div class="mt-8 flex text-center text-lg"> <div class="mt-8 flex text-center text-lg">
<span class="flex-1">{cur1Name}{alone}</span> <span class="flex-1">{cur1Name}{alone}</span>
@@ -54,7 +69,7 @@
{/if} {/if}
</div> </div>
<div class="flex w-full text-center text-lg"> <div class="flex w-full text-center text-lg">
<span class="flex-1">at {locations[cur.location].name.en}</span> <span class="flex-1">at {curLoc?.name.en}</span>
</div> </div>
</div> </div>
<div class="mt-4 block text-center"> <div class="mt-4 block text-center">
@@ -62,12 +77,14 @@
</div> </div>
<div class="mt-4 grid text-center shadow-sm transition-shadow ease-in hover:shadow-md hover:ease-out md:grid-cols-4"> <div class="mt-4 grid text-center shadow-sm transition-shadow ease-in hover:shadow-md hover:ease-out md:grid-cols-4">
{#each suggested as s (s.chara_id)} {#each suggested as s (s.chara_id)}
<span>{charaNames.get(s.chara_id)?.en}: {s.count}&#xd7;</span> <span>{s.chara_name?.en}: {s.count}&#xd7;</span>
{/each} {/each}
</div> </div>
<div class="mt-4 block text-center"> <div class="mt-4 block text-center">
<span> <span>
Set these characters to fixed positions (main, upgrades, story, races) to maximize the chance of getting this conversation. Set these characters to fixed positions (main, upgrades, story, races) to maximize the chance of getting this
conversation.
</span> </span>
</div> </div>
{/if} {/if}
{/await}

View File

@@ -20,13 +20,13 @@
tocViewed = true; tocViewed = true;
obs.disconnect(); obs.disconnect();
} }
} };
$effect(() => { $effect(() => {
if (tocElem == null) { if (tocElem == null) {
return; return;
} }
const obs = new IntersectionObserver(observeTOC, {rootMargin: "20% 0px"}); const obs = new IntersectionObserver(observeTOC, { rootMargin: '20% 0px' });
obs.observe(tocElem); obs.observe(tocElem);
}); });

View File

@@ -20,12 +20,93 @@
} from '$lib/race'; } from '$lib/race';
import Skill from '$lib/Skill.svelte'; import Skill from '$lib/Skill.svelte';
import StatChart from '$lib/StatChart.svelte'; import StatChart from '$lib/StatChart.svelte';
import { onMount } from 'svelte';
import Article from '../Article.svelte'; import Article from '../Article.svelte';
import Sec from '../Sec.svelte'; import Sec from '../Sec.svelte';
import * as skill from '$lib/data/skill';
let raceLen = $state(2000); let raceLen = $state(2000);
let secSpeedStyle = $state(RunningStyle.FrontRunner); let secSpeedStyle = $state(RunningStyle.FrontRunner);
let allSkillsList: skill.Skill[] = $state([]);
onMount(async () => {
allSkillsList = await skill.skills();
});
const allSkills = $derived(allSkillsList.reduce((m, s) => m.set(s.skill_id, s), new Map<number, skill.Skill>()));
const skills = $derived({
view: allSkills.get(100021),
sfv: allSkills.get(100101),
uma2: allSkills.get(100321),
falcoUlt: allSkills.get(100461),
palmerUlt: allSkills.get(100641),
kfc: allSkills.get(110041),
cacao: allSkills.get(110261),
right: allSkills.get(200012),
left: allSkills.get(200022),
firm: allSkills.get(200152),
compSpirit: allSkills.get(200282),
professor: allSkills.get(200331),
cornerAdept: allSkills.get(200332),
cornerConn: allSkills.get(200341),
rushingGale: allSkills.get(200371),
conc: allSkills.get(200431),
focus: allSkills.get(200432),
centerStage: allSkills.get(200451),
pp: allSkills.get(200452),
ramp: allSkills.get(200462),
nsm: allSkills.get(200491),
nn: allSkills.get(200492),
homestretchHaste: allSkills.get(200512),
ttl: allSkills.get(200531),
earlyLead: allSkills.get(200532),
escapeArtist: allSkills.get(200541),
fastPaced: allSkills.get(200542),
unrestrained: allSkills.get(200551),
encroaching: allSkills.get(200641),
spurt: allSkills.get(200642),
turboSprint: allSkills.get(200651),
tunes: allSkills.get(200721),
greed: allSkills.get(201081),
speedEater: allSkills.get(201082),
siphon: allSkills.get(201221),
murmurGold: allSkills.get(201161),
longStraights: allSkills.get(201172),
blast: allSkills.get(201173),
straights: allSkills.get(201242),
corners: allSkills.get(201252),
sixthSense: allSkills.get(201261),
dd: allSkills.get(201262),
topRunner: allSkills.get(201271),
leadersPride: allSkills.get(201272),
moxie: allSkills.get(201282),
eyes: allSkills.get(201441),
savvy: allSkills.get(201522),
lucky7: allSkills.get(201562),
gw: allSkills.get(201601),
thh: allSkills.get(201611),
loneWolf: allSkills.get(201641),
slipstream: allSkills.get(201651),
pto: allSkills.get(201661),
risky: allSkills.get(202032),
runaway: allSkills.get(202051),
burningWIT: allSkills.get(210051),
ignitedWIT: allSkills.get(210052),
radiant: allSkills.get(210061),
redshiftInherit: allSkills.get(900041),
pulseInherit: allSkills.get(900061),
anglingInherit: allSkills.get(900201),
pumpInherit: allSkills.get(900271),
inesInherit: allSkills.get(900311),
uma2Inherit: allSkills.get(900321),
beyondInherit: allSkills.get(900591),
vcInherit: allSkills.get(900681),
pastaInherit: allSkills.get(900141),
kfcInherit: allSkills.get(910041),
barcaroleInherit: allSkills.get(910151),
cacaoInherit: allSkills.get(910261),
mummyCreekInherit: allSkills.get(910451),
});
function mean2(x: [number, number]): number { function mean2(x: [number, number]): number {
return (x[0] + x[1]) * 0.5; return (x[0] + x[1]) * 0.5;
} }
@@ -193,7 +274,7 @@
At the start of late race, if they have enough HP remaining for their last spurt, horses accelerate from the mid race base At the start of late race, if they have enough HP remaining for their last spurt, horses accelerate from the mid race base
target speed to their spurt speed, which varies by speed stat, distance aptitude, running style, race distance, and guts stat, target speed to their spurt speed, which varies by speed stat, distance aptitude, running style, race distance, and guts stat,
in decreasing order of effect. "Last spurt" and "last spurt phase" are different and unrelated things; the latter is only used in decreasing order of effect. "Last spurt" and "last spurt phase" are different and unrelated things; the latter is only used
mechanically in the condition for <Skill skill={200512} hint="homestretch haste" mention />. mechanically in the condition for <Skill skill={skills.homestretchHaste} mention />.
</p> </p>
<p> <p>
Speed skills add a flat amount of target speed, generally +0.15 m/s for white skills, +0.25 m/s for double circle skills and Speed skills add a flat amount of target speed, generally +0.15 m/s for white skills, +0.25 m/s for double circle skills and
@@ -204,8 +285,8 @@
<Sec h={3} id="runaway">Runaway</Sec> <Sec h={3} id="runaway">Runaway</Sec>
<p> <p>
The skill <Skill skill={202051} hint="runaway" /> converts front runners into the <i>Great Escape</i> running style. However, The skill <Skill skill={skills.runaway} /> converts front runners into the <i>Great Escape</i> running style. However, no
no player has ever uttered the words "Great Escape" when talking about Umamusume, presumably because Runaway is a much cooler player has ever uttered the words "Great Escape" when talking about Umamusume, presumably because Runaway is a much cooler
name. ("Great Escape" is a direct translation of Japanese 大逃げ <i>oonige</i>, whereas "Front Runner" is a more liberal name. ("Great Escape" is a direct translation of Japanese 大逃げ <i>oonige</i>, whereas "Front Runner" is a more liberal
localization of 逃げ <i>nige</i> that technically just means "escape.") localization of 逃げ <i>nige</i> that technically just means "escape.")
</p> </p>
@@ -239,32 +320,31 @@
</p> </p>
<ul class="mb-4 list-disc pl-4"> <ul class="mb-4 list-disc pl-4">
<li> <li>
<Skill skill={900201} hint="angling" />, sometimes called Rod, is currently the second best skill in the game. Its condition <Skill skill={skills.anglingInherit} />, sometimes called Rod, is currently the second best skill in the game. Its condition
is to be in first place on any late race corner, which is the case immediately at the start of late race on all medium is to be in first place on any late race corner, which is the case immediately at the start of late race on all medium
tracks, tracks,
<a href="#niigata-1600">all but one mile</a>, and some sprints. <a href="#niigata-1600">all but one mile</a>, and some sprints.
</li> </li>
<li> <li>
On long distance tracks, <Skill skill={900681} hint="vc" /> takes that role instead. The front two horses get it, and it has half On long distance tracks, <Skill skill={skills.vcInherit} /> takes that role instead. The front two horses get it, and it has half
the acceleration value. the acceleration value.
</li> </li>
<li> <li>
On those sprints where Angling is dead, the front-specific option is <Skill skill={900141} hint="pasta" /> (VPP, or Pasta). Multi-front On those sprints where Angling is dead, the front-specific option is <Skill skill={skills.pastaInherit} /> (VPP, or Pasta). Multi-front
builds also have access to <Skill skill={910451} hint="mummy creek" /> (HCreek). It takes both of them to equal Angling, so such builds also have access to <Skill skill={skills.mummyCreekInherit} /> (HCreek). It takes both of them to equal Angling, so such
sprints may be better served gambling on <Skill skill={200651} hint="turbo sprint" mention />, <Skill sprints may be better served gambling on <Skill skill={skills.turboSprint} mention />, <Skill
skill={200371} skill={skills.rushingGale}
hint="rushing gale"
mention mention
/>, and possibly <Skill skill={200551} hint="unrestrained" mention /> instead. Front runners are especially strong on sprints />, and possibly <Skill skill={skills.unrestrained} mention /> instead. Front runners are especially strong on sprints for
for <a href="#spot-struggle">other reasons</a> anyway. <a href="#spot-struggle">other reasons</a> anyway.
</li> </li>
</ul> </ul>
<p> <p>
<Skill skill={200491} hint="nsm" /> is the best skill in the game. Unfortunately, for the most part, it's bad on front runners; <Skill skill={skills.nsm} /> is the best skill in the game. Unfortunately, for the most part, it's bad on front runners; generally
generally not a win condition. Activating NSM requires not being in first, which means whoever <i>was</i> used Angling and is not a win condition. Activating NSM requires not being in first, which means whoever <i>was</i> used Angling and is pulling
pulling away from you before you accumulate the blocked time to activate it. That said, on VC tracks specifically, NSM or its away from you before you accumulate the blocked time to activate it. That said, on VC tracks specifically, NSM or its white
white version <Skill skill={200492} hint="nn" mention /> can be an option for multi-front builds, since the two frontmost horses version <Skill skill={skills.nn} mention /> can be an option for multi-front builds, since the two frontmost horses get VC and final
get VC and final corner lane movement hasn't happened. corner lane movement hasn't happened.
</p> </p>
<Sec h={2} id="positioning">Positioning Mechanics</Sec> <Sec h={2} id="positioning">Positioning Mechanics</Sec>
@@ -357,14 +437,13 @@
/> />
</div> </div>
<p> <p>
Front runners have access to the skill <Skill skill={201262} hint="dd" />, which forces a horse who uses it to move outward to Front runners have access to the skill <Skill skill={skills.dd} />, which forces a horse who uses it to move outward to a
a specific distance from the rail. DD almost always ends shortly before the horse has finished accelerating to early race specific distance from the rail. DD almost always ends shortly before the horse has finished accelerating to early race speed,
speed, so it does not convert the move lane speed modifier into distance. so it does not convert the move lane speed modifier into distance.
</p> </p>
<p> <p>
We get advantage from move lane speed modifier by following DD with <Skill skill={200452} hint="pp" /> or <Skill We get advantage from move lane speed modifier by following DD with <Skill skill={skills.pp} /> or <Skill
skill={210052} skill={skills.ignitedWIT}
hint="ignited wit"
/>. DD created an opportunity for those return skills to convert into huge forward speed. This setup is called />. DD created an opportunity for those return skills to convert into huge forward speed. This setup is called
<i>lane combo</i>. <i>lane combo</i>.
</p> </p>
@@ -379,13 +458,12 @@
an efficient pickup as a short burst of high speed to gain position. an efficient pickup as a short burst of high speed to gain position.
</p> </p>
<p> <p>
The gold versions of lane combo skills &ndash; <Skill skill={201261} hint="gold dd" mention />, <Skill The gold versions of lane combo skills &ndash; <Skill skill={skills.sixthSense} mention />, <Skill
skill={200451} skill={skills.centerStage}
hint="gold pp"
mention mention
/>, <Skill skill={210051} hint="burning wit" mention /> &ndash; are excellent to take on parents, but they generally make lane combo />, <Skill skill={skills.burningWIT} mention /> &ndash; are excellent to take on parents, but they generally make lane combo itself
itself less effective. They have stronger lane change movement boosts, which does not affect the forward speed boost and is likely less effective. They have stronger lane change movement boosts, which does not affect the forward speed boost and is likely to make
to make it last a shorter time, since the horse will return to the rail more quickly. it last a shorter time, since the horse will return to the rail more quickly.
</p> </p>
<p> <p>
For the same reasons, Ignited WIT is a bit stronger than PP, because it has a <i>smaller</i> effect value and also a longer base For the same reasons, Ignited WIT is a bit stronger than PP, because it has a <i>smaller</i> effect value and also a longer base
@@ -509,9 +587,9 @@
<p> <p>
For the most part, there's nothing you can do about the no-overtake zone. The exception to this is with Smart Falcon, who has For the most part, there's nothing you can do about the no-overtake zone. The exception to this is with Smart Falcon, who has
a speed unique that can fire on any mid race straight. On Tokyo 1600 (both turf and dirt), the first corner is far enough into a speed unique that can fire on any mid race straight. On Tokyo 1600 (both turf and dirt), the first corner is far enough into
mid race that <Skill skill={100461} hint="falco ult" /> is likely to fire before entering the no-overtake zone, helping to propel mid race that <Skill skill={skills.falcoUlt} /> is likely to fire before entering the no-overtake zone, helping to propel her into
her into a lead that other front runners can't challenge until the corner begins &ndash; which is especially strong because it's a lead that other front runners can't challenge until the corner begins &ndash; which is especially strong because it's harder to
harder to pass on corners, and on those tracks, that corner lasts all the way into late race. pass on corners, and on those tracks, that corner lasts all the way into late race.
</p> </p>
<Sec h={2} id="skills">Skills</Sec> <Sec h={2} id="skills">Skills</Sec>
@@ -522,37 +600,34 @@
</p> </p>
<ul class="mb-4 list-disc pl-4"> <ul class="mb-4 list-disc pl-4">
<li> <li>
On miles, <Skill skill={201082} hint="speed eater" /> is the strongest speed skill in the game, because it is both a full strength On miles, <Skill skill={skills.speedEater} /> is the strongest speed skill in the game, because it is both a full strength speed
speed skill (i.e. +0.15 target speed for base 3s) and a full strength speed debuff. It plays both offense and defense simultaneously. skill (i.e. +0.15 target speed for base 3s) and a full strength speed debuff. It plays both offense and defense simultaneously.
Every front runner should have it on every mile. Speed Eater technically has a gold version, <Skill Every front runner should have it on every mile. Speed Eater technically has a gold version, <Skill
skill={201081} skill={skills.greed}
hint="gold speed eater" mention
/>, but Cygames apparently recognized that it must not ever be allowed to exist, because there's still no source of it on />, but Cygames apparently recognized that it must not ever be allowed to exist, because there's still no source of it on
JP. JP.
</li> </li>
<li> <li>
<Skill skill={201611} hint="thh" /> is a full strength speed skill that is triggered by other skills, so it excels at stacking <Skill skill={skills.thh} /> is a full strength speed skill that is triggered by other skills, so it excels at stacking &ndash;
&ndash; triggering THH with another speed skill is very likely to secure a pass. triggering THH with another speed skill is very likely to secure a pass.
</li> </li>
<li> <li>
<Skill skill={200462} hint="ramp" /> is only a half strength speed skill (base 1.8s), but it fires upon overtake, which helps <Skill skill={skills.ramp} /> is only a half strength speed skill (base 1.8s), but it fires upon overtake, which helps to turn
to turn that into a complete pass. that into a complete pass.
</li> </li>
<li> <li>
<Skill skill={201661} hint="pto" /> and <Skill skill={201651} hint="slipstream" /> are mechanically similar full-strength speed <Skill skill={skills.pto} /> and <Skill skill={skills.slipstream} /> are mechanically similar full-strength speed skills with
skills with cooldowns, so they can fire multiple times per race. Slipstream requires not being in first, and it's always wasted cooldowns, so they can fire multiple times per race. Slipstream requires not being in first, and it's always wasted if it triggers
if it triggers during the <a href="#no-zone">no-overtake zone</a>, so it's marginally weaker. Both want multi-front builds. during the <a href="#no-zone">no-overtake zone</a>, so it's marginally weaker. Both want multi-front builds.
</li> </li>
</ul> </ul>
<Sec h={3} id="gate-skills">Gate Skills</Sec> <Sec h={3} id="gate-skills">Gate Skills</Sec>
<p> <p>
Gate skills are <Skill skill={201601} hint="gw" /> (GW), <Skill skill={200532} hint="early lead" />, and <Skill Gate skills are <Skill skill={skills.gw} /> (GW), <Skill skill={skills.earlyLead} />, and <Skill skill={skills.conc} /> (Conc),
skill={200431} as well as all green skills including <Skill skill={skills.runaway} mention /> (but excluding <Skill
hint="conc" skill={skills.lucky7}
/> (Conc), as well as all green skills including <Skill skill={202051} hint="runaway" mention /> (but excluding <Skill
skill={201562}
hint="lucky 7"
mention mention
/>). These skills activate the moment the race starts. Other running styles can largely ignore them, but for front runners, />). These skills activate the moment the race starts. Other running styles can largely ignore them, but for front runners,
they are critical. they are critical.
@@ -574,33 +649,31 @@
/> />
</div> </div>
<p> <p>
GW must be combined with <Skill skill={200532} hint="el" /> if you want any chance of being first out of early race. The gold version GW must be combined with <Skill skill={skills.earlyLead} /> if you want any chance of being first out of early race. The gold version
of EL, <Skill skill={200531} hint="ttl" />, is highly accessible as the skill from the Mihono Bourbon Wit event SSR. In of EL, <Skill skill={skills.ttl} />, is highly accessible as the skill from the Mihono Bourbon Wit event SSR. In practice,
practice, I've found it adds fewer lengths over the white, and hence less positioning ability, than a mid race gold speed I've found it adds fewer lengths over the white, and hence less positioning ability, than a mid race gold speed skill. It is
skill. It is still absolutely <i>good</i>, and Bourbon Wit is a very usable card (treat her as a speed card that gives extra still absolutely <i>good</i>, and Bourbon Wit is a very usable card (treat her as a speed card that gives extra energy on
energy on wit), but I don't consider it mandatory anymore. wit), but I don't consider it mandatory anymore.
</p> </p>
<p> <p>
Conc is less critical. It's worth taking on horses who have it, but it isn't worth using support card slots just to get it. On Conc is less critical. It's worth taking on horses who have it, but it isn't worth using support card slots just to get it. On
the other hand, its white version, <Skill skill={200432} hint="focus" />, is bad; its only real use is as a backup gate skill the other hand, its white version, <Skill skill={skills.focus} />, is bad; its only real use is as a backup gate skill for GW
for GW when you don't have enough greens available. when you don't have enough greens available.
</p> </p>
<Sec h={3} id="spurt-skills">Spurt Skills</Sec> <Sec h={3} id="spurt-skills">Spurt Skills</Sec>
<p> <p>
Because they are post-Angling, skills that activate in the final spurt are typically less interesting to front runners. Because they are post-Angling, skills that activate in the final spurt are typically less interesting to front runners.
Notable exceptions are <Skill skill={910151} hint="barcarole" /> and, on Tokyo turf, <Skill Notable exceptions are <Skill skill={skills.barcaroleInherit} /> and, on Tokyo turf, <Skill
skill={900311} skill={skills.inesInherit}
hint="ines inherit"
/><!-- skill name ends with ! --> /><!-- skill name ends with ! -->
These are good inherits for those who don't have easy access to <Skill skill={910261} hint="cacao" mention /> and <Skill These are good inherits for those who don't have easy access to <Skill skill={skills.cacaoInherit} mention /> and <Skill
skill={910041} skill={skills.kfcInherit}
hint="kfc"
mention mention
/>. />.
</p> </p>
<p> <p>
<Skill skill={900061} hint="pulse" /> is another spurt skill that may come up sometimes and is interesting to think about. It's <Skill skill={skills.pulseInherit} /> is another spurt skill that may come up sometimes and is interesting to think about. It's
a 0.25 speed skill that requires being in at best second place to activate. Is it worth it to take? a 0.25 speed skill that requires being in at best second place to activate. Is it worth it to take?
</p> </p>
<p> <p>
@@ -618,9 +691,8 @@
<Sec h={3} id="others-skills">Other Horses' Skills</Sec> <Sec h={3} id="others-skills">Other Horses' Skills</Sec>
<p>There are two categories of other horses' skills to think about.</p> <p>There are two categories of other horses' skills to think about.</p>
<p> <p>
The first is stamina debuffs: <Skill skill={201441} hint="eyes" />, <Skill skill={201161} hint="murmur" />, <Skill The first is stamina debuffs: <Skill skill={skills.eyes} />, <Skill skill={skills.murmurGold} />, <Skill
skill={201221} skill={skills.siphon}
hint="siphon"
/>. My conclusion is that Global doesn't understand how to build debuffers, so front runners can mostly ignore these &ndash; />. My conclusion is that Global doesn't understand how to build debuffers, so front runners can mostly ignore these &ndash;
assume one will hit you, but not three. assume one will hit you, but not three.
</p> </p>
@@ -631,9 +703,9 @@
</p> </p>
<p> <p>
The other category of skills to think about is other horses' uniques. The other category of skills to think about is other horses' uniques.
<Skill skill={100101} hint="sfv" />, <Skill skill={100321} hint="u=ma2" />, and a number of others need tight positioning, <Skill skill={skills.sfv} />, <Skill skill={skills.uma2} />, and a number of others need tight positioning, requiring
requiring something like 2-4 or 3-4 in CM. The number of front runners in the match can dictate whether it's ever possible for something like 2-4 or 3-4 in CM. The number of front runners in the match can dictate whether it's ever possible for those
those uniques to activate. This is the fundamental idea behind <a href="#triple-front">triple front</a> builds. uniques to activate. This is the fundamental idea behind <a href="#triple-front">triple front</a> builds.
</p> </p>
<Sec h={3} id="skill-timing">Skill Timing</Sec> <Sec h={3} id="skill-timing">Skill Timing</Sec>
@@ -692,11 +764,10 @@
the early and mid race skills you can manage. the early and mid race skills you can manage.
<a href="#gate-skills">Gate skills</a> are especially important, because runaways have a tremendously higher early race target <a href="#gate-skills">Gate skills</a> are especially important, because runaways have a tremendously higher early race target
speed. If there is a real difference between a correctly built runaway blocker and a runaway ace, it's that <Skill speed. If there is a real difference between a correctly built runaway blocker and a runaway ace, it's that <Skill
skill={910261} skill={skills.cacaoInherit}
hint="cacao"
mention mention
/> />
and <Skill skill={910041} hint="kfc" mention /> are arguably more appropriate inherits than Angling, but the argument isn't strong and <Skill skill={skills.kfcInherit} mention /> are arguably more appropriate inherits than Angling, but the argument isn't strong
if you're still able to hit a good stat line on your runaway. if you're still able to hit a good stat line on your runaway.
</p> </p>
<p> <p>
@@ -729,21 +800,19 @@
<Sec h={3} id="long-double-front">Long Double Front</Sec> <Sec h={3} id="long-double-front">Long Double Front</Sec>
<p> <p>
At long distances, double front has different implications. At long distances, double front has different implications.
<Skill skill={900681} hint="vc" /> is the front runner win condition, and the front two horses both get it. With late race being <Skill skill={skills.vcInherit} /> is the front runner win condition, and the front two horses both get it. With late race being
before the final corner and hence extra move lane not having started, you can take advantage of <Skill before the final corner and hence extra move lane not having started, you can take advantage of <Skill skill={skills.nn} /> to turn
skill={200492} the <i>second place</i> front runner into the winner.
hint="nn"
/> to turn the <i>second place</i> front runner into the winner.
</p> </p>
<p> <p>
Building for second place to bunny with NN does not mean manipulating stats and skills to force one of the front runners into Building for second place to bunny with NN does not mean manipulating stats and skills to force one of the front runners into
second. Both fronts need to be strong enough to be adjacent at late race start, and you have to beat other people's front second. Both fronts need to be strong enough to be adjacent at late race start, and you have to beat other people's front
runners, too. (Especially since VC and <Skill skill={200641} hint="encroaching" mention /> are currently the only consistent accels runners, too. (Especially since VC and <Skill skill={skills.encroaching} mention /> are currently the only consistent accels for
for long distance.) So, double front for long is ultimately about the same as double front for other distances, just with different long distance.) So, double front for long is ultimately about the same as double front for other distances, just with different
goals when choosing the legacy. goals when choosing the legacy.
</p> </p>
<p> <p>
Given that NN is good, it's also worth considering the gold version, <Skill skill={200491} hint="nsm" /><!-- ends with ! --> Given that NN is good, it's also worth considering the gold version, <Skill skill={skills.nsm} /><!-- ends with ! -->
NSM is a better skill for the long double front build, but for now, the only way to get it while running MANT is from Yukino Bijin NSM is a better skill for the long double front build, but for now, the only way to get it while running MANT is from Yukino Bijin
Wit. That card's numbers are not great. It's still possible to get a good stat line using her, but it will take more careers to Wit. That card's numbers are not great. It's still possible to get a good stat line using her, but it will take more careers to
get there than to just get NN from Fine Motion. get there than to just get NN from Fine Motion.
@@ -752,8 +821,7 @@
If you're feeling adventurous, runaway is another consideration for double (and triple) front on long distances. Your ace If you're feeling adventurous, runaway is another consideration for double (and triple) front on long distances. Your ace
(hopefully) still gets VC, but the runaway paces up the race. As mentioned in the <a href="#solo-front">solo front</a> (hopefully) still gets VC, but the runaway paces up the race. As mentioned in the <a href="#solo-front">solo front</a>
section, this especially punishes end closers, who tend to be popular on long tracks because of <Skill section, this especially punishes end closers, who tend to be popular on long tracks because of <Skill
skill={200642} skill={skills.spurt}
hint="straight spurt"
mention mention
/>. It also keeps your ace in <a href="#front-modes">overtake mode</a>, which is better than speed-up mode, for position keep. />. It also keeps your ace in <a href="#front-modes">overtake mode</a>, which is better than speed-up mode, for position keep.
</p> </p>
@@ -771,9 +839,8 @@
One type of support that all front runners do automatically is helping to kill position-based pace chaser skills. Such skills One type of support that all front runners do automatically is helping to kill position-based pace chaser skills. Such skills
have conditions that translate into needing to be in 3rd or 4th, or sometimes 2nd through 4th, to activate. When you're have conditions that translate into needing to be in 3rd or 4th, or sometimes 2nd through 4th, to activate. When you're
bringing three front runners, if anyone else brings a single other one, they're going to occupy 2-4 naturally. If there happen bringing three front runners, if anyone else brings a single other one, they're going to occupy 2-4 naturally. If there happen
to be three others, then even late/end win cons like <Skill skill={900591} hint="beyond" mention /> and <Skill to be three others, then even late/end win cons like <Skill skill={skills.beyondInherit} mention /> and <Skill
skill={900271} skill={skills.pumpInherit}
hint="pump"
mention mention
/> are dead. /> are dead.
</p> </p>
@@ -794,10 +861,9 @@
An SS support doesn't strictly need as much in the way of mid race skills, since her main job is to give the others overtake An SS support doesn't strictly need as much in the way of mid race skills, since her main job is to give the others overtake
mode and then be passed. It's nonetheless a good idea to take those skills for less risk if your other fronts have a poor mode and then be passed. It's nonetheless a good idea to take those skills for less risk if your other fronts have a poor
showing. In addition to the normal front win cons, it's potentially strong to take unconditional gambles like <Skill showing. In addition to the normal front win cons, it's potentially strong to take unconditional gambles like <Skill
skill={200341} skill={skills.cornerConn}
hint="corner conn"
mention mention
/> and <Skill skill={210061} hint="radiant" mention />. /> and <Skill skill={skills.radiant} mention />.
</p> </p>
<p> <p>
SS supports do best on medium and long tracks, because you want to be building <i>everyone</i> for spot struggle on miles and SS supports do best on medium and long tracks, because you want to be building <i>everyone</i> for spot struggle on miles and
@@ -808,11 +874,7 @@
<Sec h={3} id="chariot">Chariot</Sec> <Sec h={3} id="chariot">Chariot</Sec>
<p> <p>
A front runner build that I have seen but not attempted is the chariot: a runaway with a strong mid race but insufficient HP A front runner build that I have seen but not attempted is the chariot: a runaway with a strong mid race but insufficient HP
to spurt stays in front of one or two other front runners who have <Skill to spurt stays in front of one or two other front runners who have <Skill skill={skills.nsm} mention /><!-- ends with ! -->
skill={200491}
hint="nsm"
mention
/><!-- ends with ! -->
</p> </p>
<p> <p>
I saw a team using a chariot in CM13 round 2 day 2; that team had an overall eleven wins at the time. Maybe their horses just I saw a team using a chariot in CM13 round 2 day 2; that team had an overall eleven wins at the time. Maybe their horses just
@@ -828,7 +890,7 @@
<p>Most front runners enjoy easy careers thanks to strong kits and little chance to be blocked.</p> <p>Most front runners enjoy easy careers thanks to strong kits and little chance to be blocked.</p>
<p> <p>
Currently, this chapter is about MANT (a.k.a. Trackblazer). Unity Cup is still useful &ndash; obviously for runaways, but also Currently, this chapter is about MANT (a.k.a. Trackblazer). Unity Cup is still useful &ndash; obviously for runaways, but also
for spinning up an <Skill skill={210052} hint="ignited wit" mention /> legacy. for spinning up an <Skill skill={skills.ignitedWIT} mention /> legacy.
</p> </p>
<Sec h={3} id="support-cards">Support Cards</Sec> <Sec h={3} id="support-cards">Support Cards</Sec>
@@ -838,47 +900,41 @@
</p> </p>
<ul class="mb-4 list-disc pl-4"> <ul class="mb-4 list-disc pl-4">
<li> <li>
Ines Fujin gives <Skill skill={201082} hint="speed eater" mention />, <Skill skill={201661} hint="pto" mention />, and <Skill Ines Fujin gives <Skill skill={skills.speedEater} mention />, <Skill skill={skills.pto} mention />, and <Skill
skill={201651} skill={skills.slipstream}
hint="slipstream"
mention mention
/>. Her guts SSR is the Kitasan Black of guts cards, with 15% training effectiveness and 80 specialty priority. She also has />. Her guts SSR is the Kitasan Black of guts cards, with 15% training effectiveness and 80 specialty priority. She also has
a relatively new wit SR that is decently strong even at LB0, though still objectively beaten by Marv SR until MLB. a relatively new wit SR that is decently strong even at LB0, though still objectively beaten by Marv SR until MLB.
</li> </li>
<li> <li>
Marvelous Sunday, both power SSR and wit SR versions, give <Skill skill={200462} hint="ramp" mention /> and <Skill Marvelous Sunday, both power SSR and wit SR versions, give <Skill skill={skills.ramp} mention /> and <Skill
skill={201611} skill={skills.thh}
hint="thh"
mention mention
/> as hints. The SSR has 15% race bonus, while the SR has 10% race bonus and gives +3 hints. The numbers on both are otherwise /> as hints. The SSR has 15% race bonus, while the SR has 10% race bonus and gives +3 hints. The numbers on both are otherwise
disappointing, but those elements alone are enough to justify using them. disappointing, but those elements alone are enough to justify using them.
</li> </li>
<li> <li>
Cards that give generic or distance-specific gold speed skills, especially mid race ones, are very valuable to front Cards that give generic or distance-specific gold speed skills, especially mid race ones, are very valuable to front
runners. Since <Skill skill={200331} hint="professor" mention /> is strong, Kitasan Black is still around despite only 5% race runners. Since <Skill skill={skills.professor} mention /> is strong, Kitasan Black is still around despite only 5% race bonus.
bonus. El Condor Pasa gives <Skill skill={200721} hint="tunes" mention />. El Condor Pasa gives <Skill skill={skills.tunes} mention />.
</li> </li>
<li> <li>
For parent runs, Smart Falcon SSR is mandatory. She gives guaranteed <Skill skill={201601} hint="gw" mention /> in her chain, For parent runs, Smart Falcon SSR is mandatory. She gives guaranteed <Skill skill={skills.gw} mention /> in her chain, and her
and her gold skill is <Skill skill={200451} hint="gold pp" mention />, which you want for building a gold skill is <Skill skill={skills.centerStage} mention />, which you want for building a
<a href="#lane-combo">lane combo</a> legacy. On ace runs, she is acceptable if you own her at MLB, but you'd rather get her skills <a href="#lane-combo">lane combo</a> legacy. On ace runs, she is acceptable if you own her at MLB, but you'd rather get her skills
from inheritance and use the card slot for a strong speed skill. from inheritance and use the card slot for a strong speed skill.
</li> </li>
<li> <li>
Seiun Sky SSR is another good parent card for parents. Her chain starts with <Skill skill={201262} hint="dd" mention /> and ends Seiun Sky SSR is another good parent card for parents. Her chain starts with <Skill skill={skills.dd} mention /> and ends with
with <Skill skill={skills.escapeArtist} mention /> (albeit agemasen). She also carries a <Skill skill={skills.thh} mention /> hint.
<Skill skill={200541} hint="escape artist" mention /> (albeit agemasen). She also carries a <Skill Unfortunately, between being a stamina card and not being Super Creek, she isn't viable for ace runs.
skill={201611}
hint="thh"
mention
/> hint. Unfortunately, between being a stamina card and not being Super Creek, she isn't viable for ace runs.
</li> </li>
<li>Other parenting cards include Kawakami Princess speed and Hishi Akebono guts, for gold versions of lane combo skills.</li> <li>Other parenting cards include Kawakami Princess speed and Hishi Akebono guts, for gold versions of lane combo skills.</li>
</ul> </ul>
<p> <p>
A future sight advisory: Maruzensky's speed SSR is coming in early July. At this point, you should probably be saving all your A future sight advisory: Maruzensky's speed SSR is coming in early July. At this point, you should probably be saving all your
carats for her. She is an extremely strong stat stick and gives <Skill skill={201271} hint="top runner" mention />, the gold carats for her. She is an extremely strong stat stick and gives <Skill skill={skills.topRunner} mention />, the gold version
version of <Skill skill={201272} hint="leader's pride" mention />. of <Skill skill={skills.leadersPride} mention />.
</p> </p>
<Sec h={3} id="career-skills">Taking Skills</Sec> <Sec h={3} id="career-skills">Taking Skills</Sec>
@@ -890,38 +946,37 @@
your chance of getting skills you don't have hints for. your chance of getting skills you don't have hints for.
</p> </p>
<p> <p>
<Skill skill={200532} hint="early lead" /> is a snap take skill. The <i>only</i> time to sit on EL is when you happen to get <Skill skill={skills.earlyLead} /> is a snap take skill. The <i>only</i> time to sit on EL is when you happen to get the first
the first +1 hint the turn before inspiration. (Even then, I'd probably still take it, since there's still a race to run.) +1 hint the turn before inspiration. (Even then, I'd probably still take it, since there's still a race to run.) Early Lead is
Early Lead is one of the strongest skills in terms of lengths gained, it applies to all tracks and conditions, and one of the strongest skills in terms of lengths gained, it applies to all tracks and conditions, and
<i>it saves late starts</i>, which are your only source of losses on most races after junior year. Moreover, it has a base <i>it saves late starts</i>, which are your only source of losses on most races after junior year. Moreover, it has a base
cost of only 120 SP; even if you do get Fast Learner after taking it, your opportunity cost was 12 SP. If you prune EL and a cost of only 120 SP; even if you do get Fast Learner after taking it, your opportunity cost was 12 SP. If you prune EL and a
hint lands on <Skill skill={200542} hint="fast-paced" mention /> or <Skill skill={201272} hint="leader's pride" mention /> instead, hint lands on <Skill skill={skills.fastPaced} mention /> or <Skill skill={skills.leadersPride} mention /> instead, you gave up that
you gave up that potential 12 SP to save 18. It's incredibly good to take early. potential 12 SP to save 18. It's incredibly good to take early.
</p> </p>
<p> <p>
On parent runs, or exactly one of your three CM horses, <Skill skill={201641} hint="lone wolf" /> is another snap take. Base cost On parent runs, or exactly one of your three CM horses, <Skill skill={skills.loneWolf} /> is another snap take. Base cost of 60
of 60 SP for +40 speed, which can secure a lot of races, especially early in career. Be extremely careful not to take it on multiple SP for +40 speed, which can secure a lot of races, especially early in career. Be extremely careful not to take it on multiple horses
horses on a team. Save and quit from the career if you need to check. It's technically better to have it on two horses than zero, on a team. Save and quit from the career if you need to check. It's technically better to have it on two horses than zero, but it's
but it's tremendously better than that to have it on one. tremendously better than that to have it on one.
</p> </p>
<p> <p>
<Skill skill={900201} hint="angling" /> is a strong consideration as a mid-career take. Inheritance events are more likely to activate <Skill skill={skills.anglingInherit} /> is a strong consideration as a mid-career take. Inheritance events are more likely to activate
green sparks than white sparks, so the risk of missing out on SP by taking it early is higher. However, Angling is an almost automatic green sparks than white sparks, so the risk of missing out on SP by taking it early is higher. However, Angling is an almost automatic
win condition for career (outside of <a href="#3k">3Ks</a> and <a href="#niigata-1600">Niigata 1600</a>). Taking Angling early win condition for career (outside of <a href="#3k">3Ks</a> and <a href="#niigata-1600">Niigata 1600</a>). Taking Angling early
can save a lot of clocks, and it can rescue runs that don't get what is normally the minimum speed to win races before summer. can save a lot of clocks, and it can rescue runs that don't get what is normally the minimum speed to win races before summer.
</p> </p>
<p> <p>
I've had debate about this one, but I feel that <Skill skill={201522} hint="savvy" /> is a skill you will pretty much always want I've had debate about this one, but I feel that <Skill skill={skills.savvy} /> is a skill you will pretty much always want at least
at least the first level of. Wit is a strong stat for front runners, and Savvy is a guaranteed Groundwork trigger. It's also the the first level of. Wit is a strong stat for front runners, and Savvy is a guaranteed Groundwork trigger. It's also the second cheapest
second cheapest front-specific skill, after Dodging Danger. On parent runs, it could arguably be worth sitting on it until the +2 front-specific skill, after Dodging Danger. On parent runs, it could arguably be worth sitting on it until the +2 or +3 hint, because
or +3 hint, because taking the second level gives a slightly boosted chance to generate the spark, and hints save twice as much taking the second level gives a slightly boosted chance to generate the spark, and hints save twice as much SP on the double circle.
SP on the double circle.
</p> </p>
<p> <p>
<Skill skill={201242} hint="front straights" /> and <Skill skill={201252} hint="front corners" /> are strong and cheap. If you've <Skill skill={skills.straights} /> and <Skill skill={skills.corners} /> are strong and cheap. If you've taken Early Lead and Angling,
taken Early Lead and Angling, they probably won't change the outcomes of any races, but it's still reasonable to take the first they probably won't change the outcomes of any races, but it's still reasonable to take the first level to prune. As a corollary,
level to prune. As a corollary, outside parent runs, you should have a specific distance in mind, so your distance straights/corners outside parent runs, you should have a specific distance in mind, so your distance straights/corners should usually be even quicker
should usually be even quicker takes. takes.
</p> </p>
<Sec h={3} id="niigata-1600">Niigata Junior Stakes</Sec> <Sec h={3} id="niigata-1600">Niigata Junior Stakes</Sec>
@@ -969,9 +1024,9 @@
tested much without them, because I don't like throwing away my runs. tested much without them, because I don't like throwing away my runs.
</p> </p>
<p> <p>
<Skill skill={201282} hint="moxie" /> is the only front-specific recovery skill you can get from MANT rivals. It also is a guaranteed <Skill skill={skills.moxie} /> is the only front-specific recovery skill you can get from MANT rivals. It also is a guaranteed option
option in Bourbon Wit's first chain event. That makes it pretty often available for the 3Ks. However, if you end up overstam at in Bourbon Wit's first chain event. That makes it pretty often available for the 3Ks. However, if you end up overstam at the end
the end of the run, buying Moxie can be as much as -162 SP, which is certainly not a trivial amount. of the run, buying Moxie can be as much as -162 SP, which is certainly not a trivial amount.
</p> </p>
<p> <p>
An alternative option to buying a recovery is to switch to Late Surger for those races. I've won Kikuka Sho with circa 300 An alternative option to buying a recovery is to switch to Late Surger for those races. I've won Kikuka Sho with circa 300
@@ -1005,44 +1060,36 @@
<ul class="mb-4 list-disc pl-4"> <ul class="mb-4 list-disc pl-4">
<li> <li>
Valentine's Mihono Bourbon (VBourbon) is the easiest font runner to train because she has <Skill Valentine's Mihono Bourbon (VBourbon) is the easiest font runner to train because she has <Skill
skill={201601} skill={skills.gw}
hint="gw"
mention mention
/> built in, whereas most others have to get it from either inheritance or cards that aren't terribly strong. She is also the /> built in, whereas most others have to get it from either inheritance or cards that aren't terribly strong. She is also the
strongest front runner, because <Skill skill={110261} hint="cacao" mention /> is full strength, mid race, extremely forgiving strongest front runner, because <Skill skill={skills.cacao} mention /> is full strength, mid race, extremely forgiving in activation,
in activation, and even has a heal. And she has <Skill skill={200431} hint="conc" mention /> and <Skill and even has a heal. And she has <Skill skill={skills.conc} mention /> and <Skill skill={skills.escapeArtist} mention /> built
skill={200541} in, both strong distance-agnostic front runner skills with awkward sources otherwise. And she's a great parent for all the same
hint="escape artist" reasons that her unique is strong (except that the heal becomes irrelevant).
mention
/> built in, both strong distance-agnostic front runner skills with awkward sources otherwise. And she's a great parent for all
the same reasons that her unique is strong (except that the heal becomes irrelevant).
</li> </li>
<li> <li>
Summer Maruzensky (SMaru or KFC) is just shy of VBourbon in strength with her unique, <Skill Summer Maruzensky (SMaru or KFC) is just shy of VBourbon in strength with her unique, <Skill skill={skills.kfc} mention />.
skill={110041} It uses a heal to trigger instead of having a heal built in, but that means it sometimes has carryover potential. Using
hint="kfc"
mention
/>. It uses a heal to trigger instead of having a heal built in, but that means it sometimes has carryover potential. Using
VBourbon as a parent for SMaru works as a trigger, too, which is especially good for shorter distances that don't want to VBourbon as a parent for SMaru works as a trigger, too, which is especially good for shorter distances that don't want to
spend SP on pure recoveries. spend SP on pure recoveries.
</li> </li>
<li> <li>
Seiun Sky is the source of <Skill skill={900201} hint="angling" mention /> and therefore the best horse for front runner parenting Seiun Sky is the source of <Skill skill={skills.anglingInherit} mention /> and therefore the best horse for front runner parenting
in the game, forever. As a runner, she is outshone by the former two and others who will come later, but she is an excellent choice in the game, forever. As a runner, she is outshone by the former two and others who will come later, but she is an excellent choice
for a <a href="#double-front">second front runner</a> in a team comp. for a <a href="#double-front">second front runner</a> in a team comp.
</li> </li>
<li> <li>
Kitasan Black is the definitive front runner of long distance, both as a parent and as a competitor. Kitasan Black is the definitive front runner of long distance, both as a parent and as a competitor.
<Skill skill={201173} hint="blast" mention /> is the gold version of <Skill skill={201172} hint="long straights" mention />, <Skill skill={skills.blast} mention /> is the gold version of <Skill skill={skills.longStraights} mention />, which is
which is extremely strong to have built in (especially noting that hints on Long Straights take 27 SP off the price of extremely strong to have built in (especially noting that hints on Long Straights take 27 SP off the price of Blast).
Blast).
</li> </li>
<li> <li>
Silence Suzuka and Mejiro Palmer are currently the only runaways in the game. Both of them have uniques that are Silence Suzuka and Mejiro Palmer are currently the only runaways in the game. Both of them have uniques that are
inconsistent normally but very consistent as runaways: inconsistent normally but very consistent as runaways:
<Skill skill={100021} hint="view" mention /> and <Skill skill={100641} hint="palmer" mention />. Outside of Team Trials, <Skill skill={skills.view} mention /> and <Skill skill={skills.palmerUlt} mention />. Outside of Team Trials, runaways
runaways aren't very useful in the MANT era. (My Suzuka runaway remains my #1 top scorer in TT, though. Runaway and Conc are aren't very useful in the MANT era. (My Suzuka runaway remains my #1 top scorer in TT, though. Runaway and Conc are both
both busted for points.) busted for points.)
</li> </li>
</ul> </ul>
<p> <p>
@@ -1053,8 +1100,8 @@
<Sec h={3} id="coc">Christmas Oguri Cap</Sec> <Sec h={3} id="coc">Christmas Oguri Cap</Sec>
<p> <p>
As is perhaps expected, Christmas Oguri Cap (COC) is very strong as a front runner on specific tracks. The front-specific heal As is perhaps expected, Christmas Oguri Cap (COC) is very strong as a front runner on specific tracks. The front-specific heal
is <Skill skill={201282} hint="moxie" mention />, which activates at the very start of the first uphill. When that first is <Skill skill={skills.moxie} mention />, which activates at the very start of the first uphill. When that first uphill is at
uphill is at the start of late race, as in the case of Tokyo 1600 Dirt, COC is online as a front runner. the start of late race, as in the case of Tokyo 1600 Dirt, COC is online as a front runner.
</p> </p>
<p> <p>
I've been told COC is very hard to train as a front runner. Something about aptitudes. I don't have any variety of Oguri, but I've been told COC is very hard to train as a front runner. Something about aptitudes. I don't have any variety of Oguri, but
@@ -1062,8 +1109,7 @@
</p> </p>
<p> <p>
Another rare manifestation of Front COC is as a third place horse in a <a href="#triple-front">triple front</a> build where <Skill Another rare manifestation of Front COC is as a third place horse in a <a href="#triple-front">triple front</a> build where <Skill
skill={900321} skill={skills.uma2Inherit}
hint="u=ma2"
mention mention
/> is strong. I convinced Werseter, the Umadump guy, to try this for CM12 after he accidentally made an 8★ front Tachyon parent. /> is strong. I convinced Werseter, the Umadump guy, to try this for CM12 after he accidentally made an 8★ front Tachyon parent.
He reported a 7% win rate for her. (But a much higher win rate overall &ndash; after all, he was using triple front.) He reported a 7% win rate for her. (But a much higher win rate overall &ndash; after all, he was using triple front.)
@@ -1111,37 +1157,36 @@
<p>Front runners are more reliant than other styles on getting certain skills from inspiration:</p> <p>Front runners are more reliant than other styles on getting certain skills from inspiration:</p>
<ul class="mb-4 list-disc pl-4"> <ul class="mb-4 list-disc pl-4">
<li> <li>
Building a full <Skill skill={201601} hint="gw" /> legacy is the first step to front runner training. Fronts without it are non-competitive Building a full <Skill skill={skills.gw} /> legacy is the first step to front runner training. Fronts without it are non-competitive
even as supports. The cards that give it aren't great for ace builds. There is no gold version of it yet, so getting it from inheritance even as supports. The cards that give it aren't great for ace builds. There is no gold version of it yet, so getting it from inheritance
is truly ideal. is truly ideal.
</li> </li>
<li> <li>
<Skill skill={200452} hint="pp" /> similarly doesn't come from good cards (since Sweep Tosho has fallen off). As a piece of <Skill skill={skills.pp} /> similarly doesn't come from good cards (since Sweep Tosho has fallen off). As a piece of
<a href="#lane-combo">lane combo</a>, it isn't applicable to every race, but it's very strong when it is. The white skill is <a href="#lane-combo">lane combo</a>, it isn't applicable to every race, but it's very strong when it is. The white skill is
better than the gold skill, so it is another ideal inherit. better than the gold skill, so it is another ideal inherit.
</li> </li>
<li> <li>
<Skill skill={210052} hint="ignited wit" /> is the stronger lane combo piece. The only sources of it are inheritance and Unity <Skill skill={skills.ignitedWIT} /> is the stronger lane combo piece. The only sources of it are inheritance and Unity Cup; which
Cup; which is to say, the source of it is inheritance. When searching databases for borrows, looking for Ignited WIT is a shortcut is to say, the source of it is inheritance. When searching databases for borrows, looking for Ignited WIT is a shortcut for listing
for listing good front runner legacies, since it's only valuable to fronts and somewhat hard to get even when you focus on it. good front runner legacies, since it's only valuable to fronts and somewhat hard to get even when you focus on it.
</li> </li>
<li> <li>
Almost all green skills are valuable to inherit at one point or another as GW triggers. Almost all green skills are valuable to inherit at one point or another as GW triggers.
<Skill skill={200012} hint="right" /> and <Skill skill={200022} hint="left" /> are particularly good; one of the two is always <Skill skill={skills.right} /> and <Skill skill={skills.left} /> are particularly good; one of the two is always the best green
the best green available for a race. available for a race.
<Skill skill={200152} hint="firm" /> is a bit less strong, and slightly superseded by the existence of Narita Top Road, but it <Skill skill={skills.firm} /> is a bit less strong, and slightly superseded by the existence of Narita Top Road, but it applies
applies to the majority of CM races. Season greens are great, but a bit narrow; distance greens are good. Weather greens are acceptable, to the majority of CM races. Season greens are great, but a bit narrow; distance greens are good. Weather greens are acceptable,
but while guts is better on front runners than other styles, it isn't good. but while guts is better on front runners than other styles, it isn't good.
<Skill skill={200282} hint="comp spirit" /> is good if you like to do <a href="#triple-front">triple front</a> builds, <Skill skill={skills.compSpirit} /> is good if you like to do <a href="#triple-front">triple front</a> builds, because it
because it activates when there are four of the runner's style in CM. activates when there are four of the runner's style in CM.
<Skill skill={201522} hint="savvy" /> is slightly less valuable as an inherit, since it can come from rivals. <Skill skill={skills.savvy} /> is slightly less valuable as an inherit, since it can come from rivals.
</li> </li>
<li> <li>
All generic speed skills that aren't strictly late race are good inherits. All generic speed skills that aren't strictly late race are good inherits.
<Skill skill={202032} hint="risky" /> is the best one by ratio of strength to difficulty to acquire. <Skill skill={skills.risky} /> is the best one by ratio of strength to difficulty to acquire.
<Skill skill={201611} hint="thh" />, <Skill skill={201661} hint="pto" />, <Skill skill={200462} hint="ramp" />, and <Skill <Skill skill={skills.thh} />, <Skill skill={skills.pto} />, <Skill skill={skills.ramp} />, and <Skill
skill={200332} skill={skills.cornerAdept}
hint="corner adept"
/> are also strong, but available as hints or chain skills from some usable-to-good cards. /> are also strong, but available as hints or chain skills from some usable-to-good cards.
</li> </li>
<li>Obviously, getting front-runner-specific skills from inheritance makes them cheaper and more consistent to get.</li> <li>Obviously, getting front-runner-specific skills from inheritance makes them cheaper and more consistent to get.</li>
@@ -1300,7 +1345,7 @@
<Sec h={3} id="cm13">CM13 &ndash; Taurus Cup (Tokyo Derby)</Sec> <Sec h={3} id="cm13">CM13 &ndash; Taurus Cup (Tokyo Derby)</Sec>
<p> <p>
Maruzensky's unique, <Skill skill={900041} hint="redshift" mention />, is live for approximately everyone. Filling the ranks Maruzensky's unique, <Skill skill={skills.redshiftInherit} mention />, is live for approximately everyone. Filling the ranks
with front runners should be a strong means to delay it for later positions, especially COC. with front runners should be a strong means to delay it for later positions, especially COC.
</p> </p>
<p> <p>
@@ -1425,8 +1470,8 @@
</p> </p>
<p>As a sprint, this is also where spot struggle shines. Time for Unity Cup guts builds.</p> <p>As a sprint, this is also where spot struggle shines. Time for Unity Cup guts builds.</p>
<p> <p>
I forgot that <Skill skill={200551} hint="unrestrained" mention /> requires being in first place, so I thought it would be reasonable I forgot that <Skill skill={skills.unrestrained} mention /> requires being in first place, so I thought it would be reasonable to
to base my team around gambling on it. That turned out not to be a great decision. base my team around gambling on it. That turned out not to be a great decision.
</p> </p>
<ol class="mb-4 list-decimal pl-4"> <ol class="mb-4 list-decimal pl-4">
<li> <li>
@@ -1447,13 +1492,12 @@
</li> </li>
</ol> </ol>
<p> <p>
The plan worked exactly as I hoped, but what the plan lacked was <Skill skill={900141} hint="vpp" mention />. While I was The plan worked exactly as I hoped, but what the plan lacked was <Skill skill={skills.pastaInherit} mention />. While I was
suppressing it on other teams' front runners with my outstanding mid race, they were also gambling on <Skill suppressing it on other teams' front runners with my outstanding mid race, they were also gambling on <Skill
skill={200651} skill={skills.turboSprint}
hint="gale"
mention mention
/> and <Skill skill={200371} hint="turbo sprint" mention />, and I didn't have enough accel to beat them. I found a mention in /> and <Skill skill={skills.rushingGale} mention />, and I didn't have enough accel to beat them. I found a mention in my chat
my chat history that, as of round 2 day 1, I had a 78% top two rate with a 32% win rate. Lessons learned. Still managed to get history that, as of round 2 day 1, I had a 78% top two rate with a 32% win rate. Lessons learned. Still managed to get 2nd in
2nd in the finals, and also my first ever group A round 2 sweep. the finals, and also my first ever group A round 2 sweep.
</p> </p>
</Article> </Article>

View File

@@ -12,6 +12,9 @@ const config = {
return isExternalLibrary ? undefined : true; return isExternalLibrary ? undefined : true;
}, },
experimental: {
async: true,
},
}, },
kit: { kit: {
adapter: adapter(), adapter: adapter(),

View File

@@ -4,6 +4,7 @@ import { playwright } from '@vitest/browser-playwright';
import { sveltekit } from '@sveltejs/kit/vite'; import { sveltekit } from '@sveltejs/kit/vite';
export default defineConfig({ export default defineConfig({
clearScreen: false,
plugins: [tailwindcss(), sveltekit()], plugins: [tailwindcss(), sveltekit()],
test: { test: {
expect: { requireAssertions: true }, expect: { requireAssertions: true },
@@ -33,4 +34,11 @@ export default defineConfig({
}, },
], ],
}, },
server: {
proxy: {
'/api': {
target: 'http://localhost:13669',
},
},
},
}); });