);
@@ -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 (
-
+