diff --git a/web/src/App.tsx b/web/src/App.tsx index 84d2f06..5bb68de 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -28,7 +28,7 @@ export function App() {
-
+
{at === 0 && } {at === 1 && ( > & { song?: string; artist?: string }; +export type Tokens = Partial> & { + song?: string; + artist?: string; + lyrics?: string[]; +}; /** Fill the `{tokens}` a caption carries. * diff --git a/web/src/stage/Meter.tsx b/web/src/stage/Meter.tsx index c02f6dd..772f134 100644 --- a/web/src/stage/Meter.tsx +++ b/web/src/stage/Meter.tsx @@ -20,7 +20,7 @@ export function Meter({ story, at, solo, onPick }: { story: Scene[]; at: number; const band = BANDS.find((b) => secs <= b.max)!; return ( -
+
{secs.toFixed(0)}s {band.label} diff --git a/web/src/stage/Reel.tsx b/web/src/stage/Reel.tsx index b9278cf..b1b2d49 100644 --- a/web/src/stage/Reel.tsx +++ b/web/src/stage/Reel.tsx @@ -58,7 +58,7 @@ export function Reel({ } return ( -
+
); @@ -72,11 +77,6 @@ export function Stage({ reel, story, tick, id }: Props) { function captionOf(scene: Scene | undefined, k: number, leaving: boolean, id: Tokens): string { if (leaving) return "thanks for stopping by ~"; if (!scene) return ""; - if (scene.act === "sing") { - const song = id.song?.trim() || "an old favourite"; - const artist = id.artist?.trim() || "someone great"; - return fill(`my fav song "${song}" - ${artist}`, id); - } const line = scene.then && k >= GLOW_AT ? scene.then : (scene.say ?? ""); return fill(line, id); } diff --git a/web/src/stage/text.ts b/web/src/stage/text.ts index 788b34e..972fbb1 100644 --- a/web/src/stage/text.ts +++ b/web/src/stage/text.ts @@ -5,6 +5,12 @@ import { glyph, icon } from "../wasm/awan_wasm"; export const SCALE = 3; export const GLYPH = 8 * SCALE; export const CAPTION_H = 56; +/** The karaoke line is smaller and sits up beside him, not under the ground — + * every number from gif.rs. */ +export const LYRIC_SCALE = 2; +export const LYRIC_LIMIT = 18 * 33; +/** Ticks a lyric holds before the next one, from script.rs. */ +export const LYRIC_HOLD = 30; export const INK = "#9696a0"; // [150, 150, 160] in gif.rs — convert, don't eyeball export const ACCENT = "#e6b464"; // [230, 180, 100] @@ -79,3 +85,32 @@ export function drawStreak(ctx: CanvasRenderingContext2D, streak: number, w: num drawBits(ctx, icon("fire"), x, 12, SCALE, ACCENT); drawText(ctx, num, x + 8 * SCALE + SCALE * 2, 12, SCALE, ACCENT); } + +/** One karaoke line down the left while he sings on the right. + * + * Not a caption: `rasterize` picks *either* the strip under the ground *or* + * this, never both, and this one is half the size and up at his shoulder. The + * preview drew the intro line, in the caption strip, at caption size, forever + * — which meant the lyrics somebody had just typed never appeared at all. + */ +export function drawKaraoke( + ctx: CanvasRenderingContext2D, + k: number, + ground: number, + song: string, + artist: string, + lyrics: string[], +) { + const step = Math.floor(k / LYRIC_HOLD); + const [iconName, text] = + step === 0 + ? ["star", `my fav song "${song || "an old favourite"}" - ${artist || "someone great"}`] + : lyrics.length + ? ["globe", lyrics[(step - 1) % lyrics.length]] + : ["globe", "la la la ~"]; + + const fit = Math.floor(Math.max(LYRIC_LIMIT - 24, 0) / (8 * LYRIC_SCALE)); + const y = Math.floor(ground / 2) - 4 * LYRIC_SCALE; + drawBits(ctx, icon(iconName), 24, y, LYRIC_SCALE, ACCENT); + drawText(ctx, [...text].slice(0, fit).join(""), 24 + 8 * LYRIC_SCALE + 6, y, LYRIC_SCALE, INK); +} diff --git a/web/src/steps/StepIdentity.tsx b/web/src/steps/StepIdentity.tsx index 9971499..5eb5900 100644 --- a/web/src/steps/StepIdentity.tsx +++ b/web/src/steps/StepIdentity.tsx @@ -20,7 +20,7 @@ const FIELDS: { key: keyof Identity; label: string; hint: string }[] = [ export function StepIdentity({ id, onChange }: { id: Identity; onChange: (id: Identity) => void }) { const filled = Object.values(id).some((v) => (Array.isArray(v) ? v.length : v)); return ( -
+
diff --git a/web/src/ui/Card.tsx b/web/src/ui/Card.tsx index db5115b..bfa1f64 100644 --- a/web/src/ui/Card.tsx +++ b/web/src/ui/Card.tsx @@ -15,7 +15,7 @@ export function Card({ children: ReactNode; }) { return ( -
+
{title && (

{title}