From f26d3773d5b1b5aa76632e7ba7464481c789eaa5 Mon Sep 17 00:00:00 2001 From: Aleksandr Sukiasov Date: Mon, 7 Sep 2026 00:51:45 +0400 Subject: [PATCH] fix(web): Randomize rolls a fresh seed on every click MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change B's Randomize only seeded a blank field, so the second and later clicks reused the same seed and produced the identical shape — it looked frozen after the first click. Randomize now always overwrites the seed; type a seed and press Enter to deliberately re-run one. Co-Authored-By: Claude Sonnet 5 --- web/src/composition-panel.ts | 14 ++++++++++- web/test/composition-panel.test.ts | 37 ++++++++++++++++++++++++------ 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/web/src/composition-panel.ts b/web/src/composition-panel.ts index e39f806..6b1b237 100644 --- a/web/src/composition-panel.ts +++ b/web/src/composition-panel.ts @@ -104,7 +104,8 @@ export function buildCompositionPanel( const seedHint = document.createElement("p"); seedHint.className = "section-hint seed-hint"; seedHint.textContent = - "Same seed → same shape from Randomize. To share an exact shape, copy its ID or URL instead."; + "Randomize rolls a fresh seed each time. Type a seed and press Enter to re-run it. " + + "To share an exact shape, copy its ID or URL instead."; panel.appendChild(seedHint); const primitives = document.createElement("div"); @@ -159,7 +160,18 @@ export function buildCompositionPanel( ); }); + // Randomize always rolls a fresh seed, so repeated clicks keep producing new + // shapes. To re-run a specific seed, type it and press Enter in the field. randomizeButton.addEventListener("click", () => { + seedInput.value = randomSeed(); + opts.onRandomize(); + }); + + seedInput.addEventListener("keydown", (event) => { + if (event.key !== "Enter") { + return; + } + event.preventDefault(); if (seedInput.value.trim().length === 0) { seedInput.value = randomSeed(); } diff --git a/web/test/composition-panel.test.ts b/web/test/composition-panel.test.ts index e4dba13..e592749 100644 --- a/web/test/composition-panel.test.ts +++ b/web/test/composition-panel.test.ts @@ -29,24 +29,47 @@ describe("buildCompositionPanel — primitive toggles", () => { }); describe("buildCompositionPanel — Randomize", () => { - it("auto-fills a blank seed and calls onRandomize", () => { + it("rolls a fresh seed and calls onRandomize on every click", () => { const onRandomize = vi.fn(); const { container, handle } = build(onRandomize); - container.querySelector(".randomize-button")?.click(); - expect(handle.seedValue().length).toBeGreaterThan(0); + const button = container.querySelector(".randomize-button"); + + button?.click(); + const first = handle.seedValue(); + expect(first.length).toBeGreaterThan(0); + + button?.click(); + const second = handle.seedValue(); + + expect(second).not.toBe(first); + expect(onRandomize).toHaveBeenCalledTimes(2); + }); + + it("re-runs a typed seed on Enter without overwriting it", () => { + const onRandomize = vi.fn(); + const { container } = build(onRandomize); + const seed = container.querySelector('input[name="seed"]'); + if (seed) { + seed.value = "pinecone"; + seed.dispatchEvent(new KeyboardEvent("keydown", { key: "Enter", bubbles: true })); + } + expect(seed?.value).toBe("pinecone"); expect(onRandomize).toHaveBeenCalledOnce(); }); - it("feeds a decodable, deterministic id when wired to generateFilteredShapeId", () => { + it("feeds a decodable, deterministic id for a fixed seed (Enter re-run)", () => { const ids: string[] = []; const { container, handle } = build(() => { ids.push( generateFilteredShapeId(handle.seedValue(), handle.gridSize(), handle.allowedTypes()), ); }); - (container.querySelector('input[name="seed"]') as HTMLInputElement).value = "wallpaper"; - container.querySelector(".randomize-button")?.click(); - container.querySelector(".randomize-button")?.click(); + const seed = container.querySelector('input[name="seed"]'); + if (seed) { + seed.value = "wallpaper"; + seed.dispatchEvent(new KeyboardEvent("keydown", { key: "Enter", bubbles: true })); + seed.dispatchEvent(new KeyboardEvent("keydown", { key: "Enter", bubbles: true })); + } expect(ids[0]).toBe(ids[1]); expect(() => decodeShapeId(ids[0] as string)).not.toThrow(); });