File size: 2,854 Bytes
5aed101
 
 
 
 
 
 
3a2fcd3
5aed101
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7bd60d9
 
 
 
 
 
c0515fc
3a2fcd3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c0515fc
 
 
 
 
 
 
 
 
 
 
5aed101
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
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);
  });
});