| import { describe, expect, it } from "vitest"; |
| import { generateLayout, PLACEMENT_STRIDE } from "./layout"; |
|
|
| const options = { |
| aspect: 16 / 9, |
| count: 88, |
| logoScale: 1, |
| sizeVariation: 1, |
| spacing: 1, |
| rotation: 52, |
| seed: 84237, |
| }; |
|
|
| describe("generateLayout", () => { |
| it("is deterministic", () => { |
| expect(generateLayout(options)).toEqual(generateLayout(options)); |
| }); |
|
|
| it("returns finite packed placements", () => { |
| const layout = generateLayout(options); |
| expect(layout).toHaveLength(options.count * PLACEMENT_STRIDE); |
| expect([...layout].every(Number.isFinite)).toBe(true); |
| }); |
|
|
| it("responds to the seed", () => { |
| expect(generateLayout(options)).not.toEqual(generateLayout({ ...options, seed: 84238 })); |
| }); |
|
|
| it("spreads placements across the canvas", () => { |
| const layout = generateLayout(options); |
| const xs: number[] = []; |
| const ys: number[] = []; |
| for (let offset = 0; offset < layout.length; offset += PLACEMENT_STRIDE) { |
| xs.push(layout[offset] ?? 0); |
| ys.push(layout[offset + 1] ?? 0); |
| } |
| expect(Math.max(...xs) - Math.min(...xs)).toBeGreaterThan(1.5); |
| expect(Math.max(...ys) - Math.min(...ys)).toBeGreaterThan(0.85); |
| }); |
|
|
| it("supports very dense layouts", () => { |
| const layout = generateLayout({ ...options, count: 512, logoScale: 0.5 }); |
| expect(layout).toHaveLength(512 * PLACEMENT_STRIDE); |
| expect([...layout].every(Number.isFinite)).toBe(true); |
| }); |
|
|
| it("controls size variation continuously", () => { |
| const uniform = generateLayout({ ...options, sizeVariation: 0 }); |
| const varied = generateLayout({ ...options, sizeVariation: 1 }); |
| const exaggerated = generateLayout({ ...options, sizeVariation: 1.5 }); |
| const widths = (layout: Float32Array): number[] => { |
| const values: number[] = []; |
| for (let offset = 2; offset < layout.length; offset += PLACEMENT_STRIDE) values.push(layout[offset] ?? 0); |
| return values; |
| }; |
| const range = (values: number[]): number => Math.max(...values) - Math.min(...values); |
|
|
| expect(range(widths(uniform))).toBeLessThan(0.000001); |
| expect(range(widths(varied))).toBeGreaterThan(0.15); |
| expect(range(widths(exaggerated))).toBeGreaterThan(range(widths(varied))); |
| }); |
|
|
| it("changes spacing continuously and visibly", () => { |
| const compact = generateLayout({ ...options, spacing: 0.5 }); |
| const neutral = generateLayout({ ...options, spacing: 1 }); |
| const airy = generateLayout({ ...options, spacing: 1.5 }); |
| expect(compact[2]).toBeGreaterThan(neutral[2] ?? 0); |
| expect(airy[2]).toBeLessThan(neutral[2] ?? 0); |
|
|
| const adjacent = generateLayout({ ...options, spacing: 1.01 }); |
| expect(Math.abs((adjacent[2] ?? 0) - (neutral[2] ?? 0))).toBeLessThan(0.001); |
| expect(Math.abs((adjacent[0] ?? 0) - (neutral[0] ?? 0))).toBeLessThan(0.001); |
| }); |
| }); |
|
|