zenno: don't use sakura

This commit is contained in:
2026-03-31 16:52:37 -04:00
parent 773625b842
commit d157dfc9b6
5 changed files with 104 additions and 454 deletions

View File

@@ -7,9 +7,10 @@
<svelte:head><link rel="icon" href={favicon} /></svelte:head>
<nav class="mb-4 flex min-w-full p-4 shadow-md">
<div class="flex h-screen flex-col">
<nav class="mb-4 flex min-w-full bg-mist-300 p-4 shadow-md dark:bg-mist-900">
<span class="hidden flex-1 md:inline">
<a href="/" class="text-7xl">Zenno Rob Roy</a>
<a href="/" class="text-4xl">Zenno Rob Roy</a>
</span>
<span class="flex-1 text-center">
<a href="/" class="mx-8 my-1 block font-semibold md:hidden">Zenno Rob Roy</a>
@@ -18,11 +19,12 @@
<a href="/vet" class="mx-8 my-1 inline-block">My Veterans</a>
<a href="/convo" class="mx-8 my-1 inline-block">Lobby Conversations</a>
</span>
</nav>
<div class="md:m-auto md:max-w-7xl md:min-w-7xl">
</nav>
<div class="mx-4 grow lg:m-auto lg:max-w-7xl lg:min-w-7xl">
{@render children()}
</div>
<footer class="inset-x-0 bottom-0 mt-32 border-t p-4 text-center text-[14px]">
</div>
<footer class="inset-x-0 bottom-0 mt-8 border-t bg-mist-300 p-4 text-center text-sm md:mt-20 dark:border-none dark:bg-mist-900">
Umamusume: Pretty Derby tools by <a href="https://zephyrtronium.date/">zephyrtronium</a>.<br />
All data is generated from the game's local database.
</footer>
</footer>
</div>

View File

@@ -1,13 +1,26 @@
<script lang="ts">
import CharaPick from '$lib/CharaPick.svelte';
let selChara = $state(0);
</script>
<h1>Welcome to SvelteKit</h1>
<CharaPick id="test-chara" bind:value={selChara} />
<p>selected character is id {selChara}</p>
<p>Visit <a href="https://svelte.dev/docs/kit">svelte.dev/docs/kit</a> to read the documentation</p>
<h1 class="m-8 text-center text-7xl">Zenno Rob Roy</h1>
<p>She's read all about Umamusume, and she's always happy to share her knowledge and give recommendations!</p>
<h2 class="mt-8 mb-4 text-4xl">Tools</h2>
<ul class="list-disc pl-4">
<li>
<a href="/inherit">Inheritance Chance</a><i>Not yet implemented</i> — Given a legacy, calculate the probability distribution
of activation counts for each spark.
</li>
<li>
<a href="/spark">Spark Chance</a><i>Not yet implemented</i> — Given a legacy, calculate the chance of generating each spark if
you fulfill the conditions to do so, and the distribution of total spark counts.
</li>
<li>
<a href="/vet">My Veterans</a><i>Not yet implemented</i> — Set up and track your veterans for Zenno Rob Roy's inspiration and
spark calculators.
</li>
<li>
<a href="/convo">Lobby Conversations</a> — Check participants in lobby conversations and get recommendations on unlocking them quickly.
</li>
</ul>
<h2 class="mt-8 mb-4 text-4xl">About</h2>
<p>Tools to fill some gaps I've felt in Umamusume optimization.</p>
<p>This site is very under construction. To demonstrate just how under construction it is, here is lorem ipsum:</p>
<p>
Lorem ipsum (/ ˌ l ɔː. r ə m ˈ ɪ p. s ə m/ LOR-əm IP-səm) is a dummy or placeholder text commonly used in graphic design,
publishing, and web development. It is typically a corrupted version of De finibus bonorum et malorum, a 1st-century BC text by

View File

@@ -3,33 +3,32 @@
import { byChara, locations, groupPopulars } from '$lib/data/convo';
import CharaPick from '$lib/CharaPick.svelte';
const minSuggest = 8;
let charaID = $state(1001);
let convo = $state(1);
let options = $derived(byChara.global.get(charaID) ?? []);
let cur = $derived(options.find((c) => c.number === convo));
function suggest(n: number, pops: (typeof groupPopulars)['global']) {
let suggested = $derived.by(() => {
if (cur == null) {
return [];
}
const u = pops[locations[cur.location].group].filter(
const u = groupPopulars.global[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,
);
if (u.length <= n) {
return u;
}
return u.filter((s) => s[1] >= u[n][1]);
}
const r = u.length <= minSuggest ? u : u.filter((s) => s[1] >= u[minSuggest][1]);
return r.map(([chara_id, count]) => ({ chara_id, count }));
});
</script>
<h1>Lobby Conversations</h1>
<div class="mt-8 flex text-center">
<div class="flex-1">
<CharaPick id="chara" class="w-full" label="Character" bind:value={charaID} required />
<h1 class="text-4xl">Lobby Conversations</h1>
<div class="mx-auto mt-8 flex flex-col rounded-md text-center shadow-md ring md:max-w-xl md:flex-row">
<div class="m-4 flex-1 md:mt-3">
<CharaPick id="chara" class="w-full" label="Character" labelClass="hidden md:inline" bind:value={charaID} required />
</div>
<div class="flex-1">
<label for="convo">Conversation</label>
<div class="m-4 flex-1 md:mt-3">
<label for="convo" class="hidden md:inline">Conversation</label>
<select id="convo" bind:value={convo} class="w-full">
{#each options as opt}
<option value={opt.number}>Slice of Life {opt.number}</option>
@@ -39,8 +38,10 @@
</div>
{#if cur}
<div class="shadow-sm transition-shadow hover:shadow-md">
<div class="mt-8 flex text-center">
<span class="flex-1">{charaNames.get(cur.chara_1)?.en ?? 'someone not a trainee'}</span>
<div class="mt-8 flex text-center text-lg">
<span class="flex-1"
>{charaNames.get(cur.chara_1)?.en ?? 'someone not a trainee'}{(cur.chara_2 ?? cur.chara_3) == null ? ' alone' : ''}</span
>
{#if cur.chara_2}
<span class="flex-1">{charaNames.get(cur.chara_2)?.en ?? 'someone not a trainee'}</span>
{/if}
@@ -48,22 +49,21 @@
<span class="flex-1">{charaNames.get(cur.chara_3)?.en ?? 'someone not a trainee'}</span>
{/if}
</div>
<div class="mt-4 flex w-full text-center">
<div class="flex w-full text-center text-lg">
<span class="flex-1">at {locations[cur.location].name.en}</span>
</div>
</div>
<div class="mt-4 block text-center">
<span>Characters who appear here most often:</span>
<span>Other characters who appear here most often:</span>
</div>
<div class="mt-4 grid text-center shadow-sm transition-shadow ease-in hover:shadow-md hover:ease-out md:grid-cols-4">
{#each suggest(8, groupPopulars.global) as s}
<span>{charaNames.get(s[0])?.en}: {s[1]}&#xd7;</span>
{#each suggested as s}
<span>{charaNames.get(s.chara_id)?.en}: {s.count}&#xd7;</span>
{/each}
</div>
<div class="mt-4 block text-center">
<span>
Set characters that appear more often 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>
</div>
{/if}

View File

@@ -1,6 +1,42 @@
@import 'tailwindcss';
@import './sakura-vars.css';
@theme {
--text-sm: 1.25rem;
:root {
color-scheme: light dark;
}
html,
body {
height: 100%;
padding: 0;
margin: 0;
}
html {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif;
}
body {
background-color: light-dark(var(--color-mist-200), var(--color-mist-800));
color: light-dark(var(--color-amber-950), var(--color-amber-50));
}
p {
margin-bottom: calc(var(--spacing) * 4);
}
a {
color: light-dark(var(--color-sky-900), var(--color-sky-100));
}
nav > span > a {
color: light-dark(var(--color-amber-950), var(--color-amber-50));
}
a:hover {
border-bottom-width: 1px;
}
select {
background-color: light-dark(var(--color-mist-300), var(--color-mist-900));
padding: 0.5rem 0.75rem;
}

View File

@@ -1,401 +0,0 @@
/* Sakura.css v1.5.0
* ================
* Minimal css theme.
* Project: https://github.com/oxalorg/sakura/
*/
/* data-theme="taiyō" */
:root {
--blossom: #292722;
--fade: #7d7768;
--bg: #ffecec;
--bg-alt: #ffecec;
--text: #292222;
}
[data-theme='iron goddess'] {
--blossom: #424b51;
--fade: #64707a;
--bg: #fff2e2;
--bg-alt: #fffce2;
--text: #2c2923;
}
[data-theme='main sequence'] {
--blossom: #3a5425;
--fade: #698650;
--bg: #fffde5;
--bg-alt: #fff4e5;
--text: #5e592a;
}
[data-theme='sorcery'] {
--blossom: #5a5a69;
--fade: #868698;
--bg: #e5f4e5;
--bg-alt: #e6f4e6;
--text: #323932;
}
[data-theme='cirrus'] {
--blossom: #565a4b;
--fade: #9da587;
--bg: #e5f6fa;
--bg-alt: #e5f6fa;
--text: #31393b;
}
[data-theme='oxygen'] {
--blossom: #162011;
--fade: #343932;
--bg: #e1e2e4;
--bg-alt: #e3e0e3;
--text: #27282c;
}
[data-theme='dauphin'] {
--blossom: #171e1c;
--fade: #485b58;
--bg: #ebe5f8;
--bg-alt: #ebe5f8;
--text: #1c1a20;
}
[data-theme='diamond-burned'] {
--blossom: #0f0d0b;
--fade: #4d4743;
--bg: #f8ebf2;
--bg-alt: #ebe8f4;
--text: #3e363a;
}
[data-theme='chi'] {
--blossom: #908975;
--fade: #fff8e5;
--bg: #110c0c;
--bg-alt: #0a090c;
--text: #cfa9a9;
}
[data-theme='darjeeling'] {
--blossom: #ba949c;
--fade: #f8e1e6;
--bg: #1c160d;
--bg-alt: #1c160d;
--text: #c9b9a0;
}
[data-theme='subgiant'] {
--blossom: #9fad8a;
--fade: #e8f2d7;
--bg: #16130b;
--bg-alt: #16130b;
--text: #bbb396;
}
[data-theme='goblin'] {
--blossom: #7a808e;
--fade: #dae1ef;
--bg: #070905;
--bg-alt: #0a0906;
--text: #acbd9f;
}
[data-theme='altostratus'] {
--blossom: #a8a0b7;
--fade: #e5dbf7;
--bg: #0c0f0f;
--bg-alt: #1a1614;
--text: #8da4a4;
}
[data-theme='silicon'] {
--blossom: #717f63;
--fade: #c4d4b3;
--bg: #050a0f;
--bg-alt: #050a0f;
--text: #838e9a;
}
[data-theme='imperator'] {
--blossom: #93a0a3;
--fade: #f3fbfd;
--bg: #0e0c12;
--bg-alt: #0e0c12;
--text: #a8a1b1;
}
[data-theme='mædi'] {
--blossom: #ccd3b6;
--fade: #fdfbf3;
--bg: #10090f;
--bg-alt: #2f282e;
--text: #9e889a;
}
/* Body */
html {
font-size: 62.5%;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif;
}
body {
font-size: 1.8rem;
line-height: 1.618;
/* max-width: 38em; */
margin: auto;
color: var(--text);
background-color: var(--bg);
padding: 13px;
}
@media (max-width: 684px) {
body {
font-size: 1.53rem;
}
}
@media (max-width: 382px) {
body {
font-size: 1.35rem;
}
}
h1,
h2,
h3,
h4,
h5,
h6 {
line-height: 1.1;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif;
font-weight: 700;
margin-top: 3rem;
margin-bottom: 1.5rem;
overflow-wrap: break-word;
word-wrap: break-word;
-ms-word-break: break-all;
word-break: break-word;
}
h1 {
font-size: 2.35em;
}
h2 {
font-size: 2em;
}
h3 {
font-size: 1.75em;
}
h4 {
font-size: 1.5em;
}
h5 {
font-size: 1.25em;
}
h6 {
font-size: 1em;
}
p {
margin-top: 0px;
margin-bottom: 2.5rem;
}
small,
sub,
sup {
font-size: 75%;
}
hr {
border-color: var(--blossom);
}
a {
text-decoration: none;
color: var(--blossom);
}
a:hover {
color: var(--fade);
border-bottom: 2px solid var(--text);
}
ul {
padding-left: 1.4em;
margin-top: 0px;
margin-bottom: 2.5rem;
}
li {
margin-bottom: 0.4em;
}
blockquote {
margin-left: 0px;
margin-right: 0px;
padding-left: 1em;
padding-top: 0.8em;
padding-bottom: 0.8em;
padding-right: 0.8em;
border-left: 5px solid var(--blossom);
margin-bottom: 2.5rem;
background-color: var(--bg-alt);
}
blockquote p {
margin-bottom: 0;
}
img,
video {
height: auto;
max-width: 100%;
margin-top: 0px;
margin-bottom: 2.5rem;
}
/* Pre and Code */
pre {
background-color: var(--bg-alt);
display: block;
padding: 1em;
overflow-x: auto;
margin-top: 0px;
margin-bottom: 2.5rem;
font-size: 0.9em;
}
code,
kbd,
samp {
font-size: 0.9em;
padding: 0 0.5em;
background-color: var(--bg-alt);
white-space: pre-wrap;
}
pre > code {
padding: 0;
background-color: transparent;
white-space: pre;
font-size: 1em;
}
/* Tables */
table {
text-align: justify;
width: 100%;
border-collapse: collapse;
margin-bottom: 2rem;
}
td,
th {
padding: 0.5em;
border-bottom: 1px solid var(--bg-alt);
}
/* Buttons, forms and input */
input,
textarea {
border: 1px solid var(--text);
}
input:focus,
textarea:focus {
border: 1px solid var(--blossom);
}
textarea {
width: 100%;
}
.button,
button,
input[type='submit'],
input[type='reset'],
input[type='button'],
input[type='file']::file-selector-button {
display: inline-block;
padding: 5px 10px;
text-align: center;
text-decoration: none;
white-space: nowrap;
background-color: var(--blossom);
color: var(--bg);
border-radius: 1px;
border: 1px solid var(--blossom);
cursor: pointer;
box-sizing: border-box;
}
.button[disabled],
button[disabled],
input[type='submit'][disabled],
input[type='reset'][disabled],
input[type='button'][disabled],
input[type='file']::file-selector-button[disabled] {
cursor: default;
opacity: 0.5;
}
.button:hover,
button:hover,
input[type='submit']:hover,
input[type='reset']:hover,
input[type='button']:hover,
input[type='file']::file-selector-button:hover {
background-color: var(--fade);
color: var(--bg);
outline: 0;
}
.button:focus-visible,
button:focus-visible,
input[type='submit']:focus-visible,
input[type='reset']:focus-visible,
input[type='button']:focus-visible,
input[type='file']::file-selector-button:focus-visible {
outline-style: solid;
outline-width: 2px;
}
textarea,
select,
input {
color: var(--text);
padding: 6px 10px;
/* The 6px vertically centers text on FF, ignored by Webkit */
margin-bottom: 10px;
background-color: var(--bg-alt);
border: 1px solid var(--bg-alt);
border-radius: 4px;
box-shadow: none;
box-sizing: border-box;
}
textarea:focus,
select:focus,
input:focus {
border: 1px solid var(--blossom);
outline: 0;
}
input[type='checkbox']:focus {
outline: 1px dotted var(--blossom);
}
label,
legend,
fieldset {
display: block;
margin-bottom: 0.5rem;
font-weight: 600;
}