Files
Claude 807528a613 Phase 4: component library
The approved element rules and ornament kit as Astro components in
packages/ui: buttons, pills, chips, filters, kickers, notices, fields and
cards; star paths, the header divider, tick scales and rings, seals and
edge seals, gilt corners, dust and placeholder art; the site header,
footer and page shell. Brand fonts are self-hosted. A gallery page shows
everything, and astro check now runs with the root typecheck.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012aSbo2D1qP8cMFQCykf7kx
2026-10-11 20:44:16 +00:00

45 lines
1.9 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { dust, ringTicks, seedOf, seeded, starPath, starPoints, ticks } from "../src/lib/ornaments.ts";
describe("ornament geometry", () => {
it("is the same on every build for the same seed", () => {
expect(starPath({ x1: 0, x2: 600, y: 18, steps: 12, seed: 7 })).toEqual(starPath({ x1: 0, x2: 600, y: 18, steps: 12, seed: 7 }));
expect(dust(10, 3)).toBe(dust(10, 3));
expect(seeded(1)()).toBe(seeded(1)());
expect(seedOf("Library")).not.toBe(seedOf("Store"));
});
it("keeps the ends of a star path on the line and nudges within its strength", () => {
const p = starPath({ x1: 0, x2: 600, y: 20, steps: 12, seed: 42, strength: "standard" });
expect(p.marks[0]!.y).toBe(20);
expect(p.marks.at(-1)!.y).toBe(20);
for (const m of p.marks) expect(Math.abs(m.y - 20)).toBeLessThanOrEqual(0.22 * 50 + 0.05);
expect(p.links).toHaveLength(12);
});
it("makes about a third of the points small violet stars and one gold center star", () => {
const p = starPath({ x1: 0, x2: 1200, y: 20, steps: 24, seed: 5, centerStar: true });
const stars = p.marks.filter((m) => m.kind === "star");
expect(stars.filter((s) => s.kind === "star" && s.gold)).toHaveLength(1);
expect(stars.length).toBeGreaterThanOrEqual(8);
expect(stars.length).toBeLessThanOrEqual(10);
});
it("stops each dotted link short of the marks it joins", () => {
const p = starPath({ x1: 0, x2: 100, y: 10, steps: 2, seed: 0, strength: "calm" });
expect(p.links[0]!.x1).toBeGreaterThan(0);
expect(p.links[0]!.x2).toBeLessThan(50);
});
it("draws a long tick every fifth tick", () => {
const t = ticks(200, 30);
expect(t).toHaveLength(31);
expect(t.filter((x) => x.long)).toHaveLength(7);
expect(ringTicks(76)).toHaveLength(48);
});
it("draws a thin four-point star", () => {
expect(starPoints(10, 10, 10)).toBe("10,0 11.6,8.4 20,10 11.6,11.6 10,20 8.4,11.6 0,10 8.4,8.4");
});
});