@prosopo/puzzle-assets 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/dist/_virtual/_rolldown/runtime.js +3 -0
  3. package/dist/background.d.ts +4 -0
  4. package/dist/background.d.ts.map +1 -0
  5. package/dist/background.js +131 -0
  6. package/dist/background.js.map +1 -0
  7. package/dist/browser.d.ts +15 -0
  8. package/dist/browser.d.ts.map +1 -0
  9. package/dist/browser.js +38 -0
  10. package/dist/browser.js.map +1 -0
  11. package/dist/cjs/_virtual/_rolldown/runtime.cjs +23 -0
  12. package/dist/cjs/background.cjs +131 -0
  13. package/dist/cjs/compose.cjs +126 -0
  14. package/dist/cjs/decoys.cjs +105 -0
  15. package/dist/cjs/encode.cjs +51 -0
  16. package/dist/cjs/index.cjs +74 -0
  17. package/dist/cjs/notch.cjs +122 -0
  18. package/dist/cjs/palette.cjs +94 -0
  19. package/dist/cjs/prng.cjs +44 -0
  20. package/dist/compose.d.ts +9 -0
  21. package/dist/compose.d.ts.map +1 -0
  22. package/dist/compose.js +126 -0
  23. package/dist/compose.js.map +1 -0
  24. package/dist/decoys.d.ts +5 -0
  25. package/dist/decoys.d.ts.map +1 -0
  26. package/dist/decoys.js +104 -0
  27. package/dist/decoys.js.map +1 -0
  28. package/dist/encode.d.ts +6 -0
  29. package/dist/encode.d.ts.map +1 -0
  30. package/dist/encode.js +46 -0
  31. package/dist/encode.js.map +1 -0
  32. package/dist/index.d.ts +12 -0
  33. package/dist/index.d.ts.map +1 -0
  34. package/dist/index.js +59 -0
  35. package/dist/index.js.map +1 -0
  36. package/dist/notch.d.ts +7 -0
  37. package/dist/notch.d.ts.map +1 -0
  38. package/dist/notch.js +121 -0
  39. package/dist/notch.js.map +1 -0
  40. package/dist/palette.d.ts +9 -0
  41. package/dist/palette.d.ts.map +1 -0
  42. package/dist/palette.js +93 -0
  43. package/dist/palette.js.map +1 -0
  44. package/dist/prng.d.ts +10 -0
  45. package/dist/prng.d.ts.map +1 -0
  46. package/dist/prng.js +42 -0
  47. package/dist/prng.js.map +1 -0
  48. package/dist/tests/puzzleAssets.unit.test.d.ts +2 -0
  49. package/dist/tests/puzzleAssets.unit.test.d.ts.map +1 -0
  50. package/dist/tests/puzzleAssets.unit.test.js +257 -0
  51. package/dist/tests/puzzleAssets.unit.test.js.map +1 -0
  52. package/dist/types.d.ts +28 -0
  53. package/dist/types.d.ts.map +1 -0
  54. package/dist/types.js +2 -0
  55. package/dist/types.js.map +1 -0
  56. package/package.json +61 -0
  57. package/scripts/preview.ts +197 -0
  58. package/vite.cjs.config.ts +23 -0
  59. package/vite.esm.config.ts +27 -0
  60. package/vite.test.config.ts +32 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encode.d.ts","sourceRoot":"","sources":["../src/encode.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAa5C,eAAO,MAAM,gBAAgB,UAAW,SAAS,KAAG,OAAO,CAAC,MAAM,CAKrD,CAAC;AASd,eAAO,MAAM,WAAW,UAAW,SAAS,KAAG,OAAO,CAAC,MAAM,CAKhD,CAAC;AAGd,eAAO,MAAM,SAAS,UAAW,SAAS,KAAG,OAAO,CAAC,MAAM,CAK9C,CAAC;AAEd,eAAO,MAAM,SAAS,SAAU,MAAM,KAAG,MACW,CAAC"}
package/dist/encode.js ADDED
@@ -0,0 +1,46 @@
1
+ import sharp from "sharp";
2
+ //#region src/encode.ts
3
+ /**
4
+ * Background quality is deliberately high. WebP's chroma subsampling and
5
+ * ringing around the cut are exactly the kind of artefact an attacker could
6
+ * key on, *and* at q<95 the ringing becomes visually obvious around the
7
+ * decoy piece silhouettes we paint on top of the background — the mix of
8
+ * bright edge-rim and dark drop-shadow at the decoy edge is precisely the
9
+ * high-contrast local signal WebP butchers hardest. At 300x200 the extra few
10
+ * kilobytes of a higher quality setting are trivial.
11
+ */
12
+ var BACKGROUND_QUALITY = 95;
13
+ var encodeBackground = (image) => sharp(image.data, { raw: {
14
+ width: image.width,
15
+ height: image.height,
16
+ channels: 4
17
+ } }).webp({
18
+ quality: BACKGROUND_QUALITY,
19
+ alphaQuality: 100,
20
+ effort: 4
21
+ }).toBuffer();
22
+ /**
23
+ * Lossless. The piece is a 44x44 sprite on transparency, and lossy WebP's
24
+ * ringing around the alpha edge is the dominant visual artefact — a subtle
25
+ * ripple that reads as wavy edges even at q=92. Lossless costs ~4 KB per
26
+ * piece instead of ~2 KB, which is nothing over the wire, and eliminates
27
+ * the ringing entirely.
28
+ */
29
+ var encodePiece = (image) => sharp(image.data, { raw: {
30
+ width: image.width,
31
+ height: image.height,
32
+ channels: 4
33
+ } }).webp({
34
+ lossless: true,
35
+ alphaQuality: 100,
36
+ effort: 4
37
+ }).toBuffer();
38
+ /** PNG, for the preview script only — lossless so artefacts are visible. */
39
+ var encodePng = (image) => sharp(image.data, { raw: {
40
+ width: image.width,
41
+ height: image.height,
42
+ channels: 4
43
+ } }).png().toBuffer();
44
+ var toDataUri = (webp) => `data:image/webp;base64,${webp.toString("base64")}`;
45
+ //#endregion
46
+ export { encodeBackground, encodePiece, encodePng, toDataUri };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encode.js","sourceRoot":"","sources":["../src/encode.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,MAAM,OAAO,CAAC;AAY1B,MAAM,kBAAkB,GAAG,EAAE,CAAC;AAE9B,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,KAAgB,EAAmB,EAAE,CACrE,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE;IACjB,GAAG,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,EAAE;CAC9D,CAAC;KACA,IAAI,CAAC,EAAE,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;KACnE,QAAQ,EAAE,CAAC;AASd,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,KAAgB,EAAmB,EAAE,CAChE,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE;IACjB,GAAG,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,EAAE;CAC9D,CAAC;KACA,IAAI,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;KACtD,QAAQ,EAAE,CAAC;AAGd,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,KAAgB,EAAmB,EAAE,CAC9D,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE;IACjB,GAAG,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,EAAE;CAC9D,CAAC;KACA,GAAG,EAAE;KACL,QAAQ,EAAE,CAAC;AAEd,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,IAAY,EAAU,EAAE,CACjD,0BAA0B,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { NotchPlacement, PuzzleGeometry, PuzzleRenderSettings, RenderedPuzzle, RgbaImage } from "./types.js";
2
+ export { createPrng, createSeed, SEED_BYTES } from "./prng.js";
3
+ export { generateBackground } from "./background.js";
4
+ export { paintDecoys, paintDecoyPiece } from "./decoys.js";
5
+ export { encodeBackground, encodePiece, encodePng, toDataUri, } from "./encode.js";
6
+ export type { NotchPlacement, PuzzleGeometry, PuzzleRenderSettings, RenderedPuzzle, RgbaImage, } from "./types.js";
7
+ export declare const DEFAULT_GEOMETRY: PuzzleGeometry;
8
+ export declare const DEFAULT_RENDER_SETTINGS: PuzzleRenderSettings;
9
+ export declare const createBackground: (geometry?: PuzzleGeometry) => RgbaImage;
10
+ export declare const renderPuzzle: (background: RgbaImage, placement: NotchPlacement, geometry?: PuzzleGeometry, settings?: PuzzleRenderSettings) => Promise<RenderedPuzzle>;
11
+ export declare const createPuzzle: (placement: NotchPlacement, geometry?: PuzzleGeometry, settings?: PuzzleRenderSettings) => Promise<RenderedPuzzle>;
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EACX,cAAc,EACd,cAAc,EACd,oBAAoB,EACpB,cAAc,EACd,SAAS,EACT,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC3D,OAAO,EACN,gBAAgB,EAChB,WAAW,EACX,SAAS,EACT,SAAS,GACT,MAAM,aAAa,CAAC;AACrB,YAAY,EACX,cAAc,EACd,cAAc,EACd,oBAAoB,EACpB,cAAc,EACd,SAAS,GACT,MAAM,YAAY,CAAC;AAOpB,eAAO,MAAM,gBAAgB,EAAE,cAI9B,CAAC;AAQF,eAAO,MAAM,uBAAuB,EAAE,oBAMrC,CAAC;AAQF,eAAO,MAAM,gBAAgB,cAClB,cAAc,KACtB,SAC2E,CAAC;AAO/E,eAAO,MAAM,YAAY,eACZ,SAAS,aACV,cAAc,aACf,cAAc,aACd,oBAAoB,KAC5B,OAAO,CAAC,cAAc,CAqCxB,CAAC;AAGF,eAAO,MAAM,YAAY,cACb,cAAc,aACf,cAAc,aACd,oBAAoB,KAC5B,OAAO,CAAC,cAAc,CAC+C,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,59 @@
1
+ import "./_virtual/_rolldown/runtime.js";
2
+ import { generateBackground } from "./background.js";
3
+ import { createNotchShape } from "./notch.js";
4
+ import { cutNotch } from "./compose.js";
5
+ import { paintDecoyPiece, paintDecoys } from "./decoys.js";
6
+ import { encodeBackground, encodePiece, encodePng, toDataUri } from "./encode.js";
7
+ import { SEED_BYTES, createPrng, createSeed } from "./prng.js";
8
+ //#region src/index.ts
9
+ /**
10
+ * Matches the widget's container. Kept here so the generator and the provider
11
+ * agree on geometry without the provider having to restate it. Geometry is
12
+ * widget-coupled and not exposed to operators.
13
+ */
14
+ var DEFAULT_GEOMETRY = {
15
+ width: 300,
16
+ height: 200,
17
+ notchSize: 44
18
+ };
19
+ /**
20
+ * Defaults for the per-render tunables. Operators can override any of these
21
+ * per-client (via `ClientSettingsSchema.puzzle`) or per-traffic-category
22
+ * (via `TrafficCategoryPolicySchema.puzzle`); the provider resolves an
23
+ * effective value and passes it to `renderPuzzle`.
24
+ */
25
+ var DEFAULT_RENDER_SETTINGS = {
26
+ decoyCount: 5,
27
+ decoyEdgeDarkness: 20,
28
+ decoyBodyBrightness: 4,
29
+ holeDarken: .55,
30
+ decoyHoleDarken: .7
31
+ };
32
+ /**
33
+ * Generate a fresh background. Each one is single-use by contract: serving the
34
+ * same background twice with two different notch positions would let an
35
+ * attacker diff the two composites and read both targets straight off. The
36
+ * caller's buffer is responsible for enforcing consume-once.
37
+ */
38
+ var createBackground = (geometry = DEFAULT_GEOMETRY) => generateBackground(createPrng(createSeed()), geometry.width, geometry.height);
39
+ /**
40
+ * Cut a notch at `placement` and encode both halves.
41
+ *
42
+ * The background is consumed (mutated) by this call.
43
+ */
44
+ var renderPuzzle = async (background, placement, geometry = DEFAULT_GEOMETRY, settings = DEFAULT_RENDER_SETTINGS) => {
45
+ const prng = createPrng(createSeed());
46
+ const pieceSize = geometry.pieceSize ?? geometry.notchSize;
47
+ paintDecoys(background, prng, settings.decoyCount, pieceSize, placement, settings.decoyEdgeDarkness, settings.decoyBodyBrightness, settings.decoyHoleDarken);
48
+ const { background: cut, piece } = cutNotch(prng, background, createNotchShape(prng, pieceSize), pieceSize, placement, settings.holeDarken);
49
+ const [backgroundWebp, pieceWebp] = await Promise.all([encodeBackground(cut), encodePiece(piece)]);
50
+ return {
51
+ background: backgroundWebp,
52
+ piece: pieceWebp,
53
+ pieceSize
54
+ };
55
+ };
56
+ /** Convenience: generate, cut and encode in one call. */
57
+ var createPuzzle = async (placement, geometry = DEFAULT_GEOMETRY, settings = DEFAULT_RENDER_SETTINGS) => renderPuzzle(createBackground(geometry), placement, geometry, settings);
58
+ //#endregion
59
+ export { DEFAULT_GEOMETRY, DEFAULT_RENDER_SETTINGS, SEED_BYTES, createBackground, createPrng, createPuzzle, createSeed, encodeBackground, encodePiece, encodePng, generateBackground, paintDecoyPiece, paintDecoys, renderPuzzle, toDataUri };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AASnD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC3D,OAAO,EACN,gBAAgB,EAChB,WAAW,EACX,SAAS,EACT,SAAS,GACT,MAAM,aAAa,CAAC;AAcrB,MAAM,CAAC,MAAM,gBAAgB,GAAmB;IAC/C,KAAK,EAAE,GAAG;IACV,MAAM,EAAE,GAAG;IACX,SAAS,EAAE,EAAE;CACb,CAAC;AAQF,MAAM,CAAC,MAAM,uBAAuB,GAAyB;IAC5D,UAAU,EAAE,CAAC;IACb,iBAAiB,EAAE,EAAE;IACrB,mBAAmB,EAAE,CAAC;IACtB,UAAU,EAAE,IAAI;IAChB,eAAe,EAAE,GAAG;CACpB,CAAC;AAQF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAC/B,WAA2B,gBAAgB,EAC/B,EAAE,CACd,kBAAkB,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC,EAAE,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;AAO/E,MAAM,CAAC,MAAM,YAAY,GAAG,KAAK,EAChC,UAAqB,EACrB,SAAyB,EACzB,WAA2B,gBAAgB,EAC3C,WAAiC,uBAAuB,EAC9B,EAAE;IAC5B,MAAM,IAAI,GAAG,UAAU,CAAC,UAAU,EAAE,CAAC,CAAC;IACtC,MAAM,SAAS,GAAG,QAAQ,CAAC,SAAS,IAAI,QAAQ,CAAC,SAAS,CAAC;IAK3D,WAAW,CACV,UAAU,EACV,IAAI,EACJ,QAAQ,CAAC,UAAU,EACnB,SAAS,EACT,SAAS,EACT,QAAQ,CAAC,iBAAiB,EAC1B,QAAQ,CAAC,mBAAmB,EAC5B,QAAQ,CAAC,eAAe,CACxB,CAAC;IACF,MAAM,KAAK,GAAG,gBAAgB,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IAChD,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,QAAQ,CAC1C,IAAI,EACJ,UAAU,EACV,KAAK,EACL,SAAS,EACT,SAAS,EACT,QAAQ,CAAC,UAAU,CACnB,CAAC;IAEF,MAAM,CAAC,cAAc,EAAE,SAAS,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QACrD,gBAAgB,CAAC,GAAG,CAAC;QACrB,WAAW,CAAC,KAAK,CAAC;KAClB,CAAC,CAAC;IAEH,OAAO;QACN,UAAU,EAAE,cAAc;QAC1B,KAAK,EAAE,SAAS;QAChB,SAAS;KACT,CAAC;AACH,CAAC,CAAC;AAGF,MAAM,CAAC,MAAM,YAAY,GAAG,KAAK,EAChC,SAAyB,EACzB,WAA2B,gBAAgB,EAC3C,WAAiC,uBAAuB,EAC9B,EAAE,CAC5B,YAAY,CAAC,gBAAgB,CAAC,QAAQ,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { Prng } from "./prng.js";
2
+ export interface NotchShape {
3
+ distance(lx: number, ly: number): number;
4
+ }
5
+ export declare const createNotchShape: (prng: Prng, size: number) => NotchShape;
6
+ export declare const coverageFromDistance: (distance: number) => number;
7
+ //# sourceMappingURL=notch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notch.d.ts","sourceRoot":"","sources":["../src/notch.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAWtC,MAAM,WAAW,UAAU;IAE1B,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;CACzC;AAwKD,eAAO,MAAM,gBAAgB,SAAU,IAAI,QAAQ,MAAM,KAAG,UAc3D,CAAC;AAMF,eAAO,MAAM,oBAAoB,aAAc,MAAM,KAAG,MAMvD,CAAC"}
package/dist/notch.js ADDED
@@ -0,0 +1,121 @@
1
+ //#region src/notch.ts
2
+ var sideOffset = (side, half, distance) => {
3
+ switch (side) {
4
+ case 0: return [0, -half - distance];
5
+ case 1: return [half + distance, 0];
6
+ case 2: return [0, half + distance];
7
+ default: return [-half - distance, 0];
8
+ }
9
+ };
10
+ var roundedBoxDistance = (px, py, half, radius) => {
11
+ const qx = Math.abs(px) - half + radius;
12
+ const qy = Math.abs(py) - half + radius;
13
+ return Math.hypot(Math.max(qx, 0), Math.max(qy, 0)) + Math.min(Math.max(qx, qy), 0) - radius;
14
+ };
15
+ var createJigsawShape = (prng, size) => {
16
+ const knobRadius = size * prng.range(.15, .19);
17
+ const bodyHalf = size / 2 - knobRadius * .9;
18
+ const cornerRadius = bodyHalf * prng.range(.28, .42);
19
+ const knobSide = prng.int(0, 3);
20
+ const [knobX, knobY] = sideOffset(knobSide, bodyHalf, -knobRadius * .45);
21
+ const hasBite = prng.next() < .55;
22
+ const biteSide = (knobSide + prng.int(1, 3)) % 4;
23
+ const biteRadius = size * prng.range(.13, .17);
24
+ const [biteX, biteY] = sideOffset(biteSide, bodyHalf, -biteRadius * .55);
25
+ return { distance(lx, ly) {
26
+ const px = lx - size / 2;
27
+ const py = ly - size / 2;
28
+ const body = roundedBoxDistance(px, py, bodyHalf, cornerRadius);
29
+ const knob = Math.hypot(px - knobX, py - knobY) - knobRadius;
30
+ let d = Math.min(body, knob);
31
+ if (hasBite) {
32
+ const bite = Math.hypot(px - biteX, py - biteY) - biteRadius;
33
+ d = Math.max(d, -bite);
34
+ }
35
+ return d;
36
+ } };
37
+ };
38
+ var createCircleShape = (prng, size) => {
39
+ const radius = size / 2 * prng.range(.85, .98);
40
+ const cx = size / 2;
41
+ const cy = size / 2;
42
+ return { distance(lx, ly) {
43
+ return Math.hypot(lx - cx, ly - cy) - radius;
44
+ } };
45
+ };
46
+ var createRoundedRectShape = (prng, size) => {
47
+ const aspect = prng.range(.5, 1);
48
+ const halfMax = size / 2 * prng.range(.82, .98);
49
+ const [halfW, halfH] = prng.next() < .5 ? [halfMax, halfMax * aspect] : [halfMax * aspect, halfMax];
50
+ const cornerRadius = Math.min(halfW, halfH) * prng.range(.08, .5);
51
+ const cx = size / 2;
52
+ const cy = size / 2;
53
+ return { distance(lx, ly) {
54
+ const px = lx - cx;
55
+ const py = ly - cy;
56
+ const qx = Math.abs(px) - halfW + cornerRadius;
57
+ const qy = Math.abs(py) - halfH + cornerRadius;
58
+ return Math.hypot(Math.max(qx, 0), Math.max(qy, 0)) + Math.min(Math.max(qx, qy), 0) - cornerRadius;
59
+ } };
60
+ };
61
+ var createPolygonShape = (prng, size) => {
62
+ const n = prng.int(3, 8);
63
+ const inradius = size / 2 * prng.range(.85, .98) * Math.cos(Math.PI / n);
64
+ const rotation = prng.next() * Math.PI * 2;
65
+ const normals = [];
66
+ for (let i = 0; i < n; i++) {
67
+ const angle = 2 * Math.PI * i / n - Math.PI / 2 + rotation;
68
+ normals.push([Math.cos(angle), Math.sin(angle)]);
69
+ }
70
+ const cx = size / 2;
71
+ const cy = size / 2;
72
+ return { distance(lx, ly) {
73
+ const px = lx - cx;
74
+ const py = ly - cy;
75
+ let maxD = Number.NEGATIVE_INFINITY;
76
+ for (const [nx, ny] of normals) {
77
+ const d = px * nx + py * ny - inradius;
78
+ if (d > maxD) maxD = d;
79
+ }
80
+ return maxD;
81
+ } };
82
+ };
83
+ var createFlowerShape = (prng, size) => {
84
+ const petals = prng.int(4, 8);
85
+ const rAvg = size / 2 * prng.range(.72, .88);
86
+ const rAmp = rAvg * prng.range(.1, .22);
87
+ const phase = prng.next() * Math.PI * 2;
88
+ const cx = size / 2;
89
+ const cy = size / 2;
90
+ return { distance(lx, ly) {
91
+ const px = lx - cx;
92
+ const py = ly - cy;
93
+ return Math.hypot(px, py) - (rAvg + rAmp * Math.cos(petals * Math.atan2(py, px) + phase));
94
+ } };
95
+ };
96
+ /**
97
+ * Pick a random shape family per call. The real piece and its hole are cut
98
+ * from the same call so they match; decoys each call independently so they
99
+ * form a mixed field of silhouettes on the frame.
100
+ */
101
+ var createNotchShape = (prng, size) => {
102
+ switch (prng.int(0, 4)) {
103
+ case 0: return createJigsawShape(prng, size);
104
+ case 1: return createCircleShape(prng, size);
105
+ case 2: return createRoundedRectShape(prng, size);
106
+ case 3: return createPolygonShape(prng, size);
107
+ default: return createFlowerShape(prng, size);
108
+ }
109
+ };
110
+ /**
111
+ * Anti-aliased coverage in [0, 1] for a signed distance, using a one-pixel
112
+ * transition band centred on the boundary.
113
+ */
114
+ var coverageFromDistance = (distance) => {
115
+ const t = .5 - distance;
116
+ if (t <= 0) return 0;
117
+ if (t >= 1) return 1;
118
+ return t * t * (3 - 2 * t);
119
+ };
120
+ //#endregion
121
+ export { coverageFromDistance, createNotchShape };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notch.js","sourceRoot":"","sources":["../src/notch.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { Prng } from "./prng.js";
2
+ export interface Rgb {
3
+ r: number;
4
+ g: number;
5
+ b: number;
6
+ }
7
+ export declare const hslToRgb: (h: number, s: number, l: number) => Rgb;
8
+ export declare const drawPalette: (prng: Prng, count: number) => Rgb[];
9
+ //# sourceMappingURL=palette.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"palette.d.ts","sourceRoot":"","sources":["../src/palette.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEtC,MAAM,WAAW,GAAG;IACnB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACV;AA4CD,eAAO,MAAM,QAAQ,MAAO,MAAM,KAAK,MAAM,KAAK,MAAM,KAAG,GAa1D,CAAC;AAYF,eAAO,MAAM,WAAW,SAAU,IAAI,SAAS,MAAM,KAAG,GAAG,EAoB1D,CAAC"}
@@ -0,0 +1,93 @@
1
+ //#region src/palette.ts
2
+ var PALETTES = [
3
+ {
4
+ hue: 268,
5
+ spread: 46,
6
+ saturation: [.55, .78],
7
+ lightness: [.4, .7]
8
+ },
9
+ {
10
+ hue: 212,
11
+ spread: 42,
12
+ saturation: [.58, .8],
13
+ lightness: [.4, .7]
14
+ },
15
+ {
16
+ hue: 178,
17
+ spread: 44,
18
+ saturation: [.5, .72],
19
+ lightness: [.38, .68]
20
+ },
21
+ {
22
+ hue: 32,
23
+ spread: 38,
24
+ saturation: [.58, .8],
25
+ lightness: [.45, .72]
26
+ },
27
+ {
28
+ hue: 338,
29
+ spread: 40,
30
+ saturation: [.52, .74],
31
+ lightness: [.45, .72]
32
+ },
33
+ {
34
+ hue: 138,
35
+ spread: 42,
36
+ saturation: [.46, .66],
37
+ lightness: [.38, .66]
38
+ }
39
+ ];
40
+ var hueToChannel = (p, q, tRaw) => {
41
+ let t = tRaw;
42
+ if (t < 0) t += 1;
43
+ if (t > 1) t -= 1;
44
+ if (t < 1 / 6) return p + (q - p) * 6 * t;
45
+ if (t < 1 / 2) return q;
46
+ if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
47
+ return p;
48
+ };
49
+ /** h in degrees, s and l in [0, 1]. */
50
+ var hslToRgb = (h, s, l) => {
51
+ const hNorm = (h % 360 + 360) % 360 / 360;
52
+ if (s === 0) {
53
+ const v = Math.round(l * 255);
54
+ return {
55
+ r: v,
56
+ g: v,
57
+ b: v
58
+ };
59
+ }
60
+ const q = l < .5 ? l * (1 + s) : l + s - l * s;
61
+ const p = 2 * l - q;
62
+ return {
63
+ r: Math.round(hueToChannel(p, q, hNorm + 1 / 3) * 255),
64
+ g: Math.round(hueToChannel(p, q, hNorm) * 255),
65
+ b: Math.round(hueToChannel(p, q, hNorm - 1 / 3) * 255)
66
+ };
67
+ };
68
+ /**
69
+ * Draw `count` harmonious colours. The base hue is jittered per background so
70
+ * two draws from the same palette are not the same picture.
71
+ *
72
+ * Hues are spread evenly across the band rather than sampled uniformly at
73
+ * random, and lightness alternates between the ends of the range. Drawing both
74
+ * at random clusters them: neighbouring control points come out nearly the same
75
+ * colour and the mesh reads as one flat field with a slight gradient, which is
76
+ * the difference between "designed" and "beige".
77
+ */
78
+ var drawPalette = (prng, count) => {
79
+ const spec = prng.pick(PALETTES);
80
+ const baseHue = spec.hue + prng.range(-20, 20);
81
+ const direction = prng.next() < .5 ? -1 : 1;
82
+ const colours = [];
83
+ for (let i = 0; i < count; i++) {
84
+ const hue = baseHue + direction * ((count === 1 ? .5 : i / (count - 1)) - .5) * 2 * spec.spread + prng.range(-6, 6);
85
+ const saturation = prng.range(spec.saturation[0], spec.saturation[1]);
86
+ const pole = i % 2 === 0 ? 0 : 1;
87
+ const lightness = spec.lightness[pole] + prng.range(-.04, .04) * (pole === 0 ? 1 : -1);
88
+ colours.push(hslToRgb(hue, saturation, lightness));
89
+ }
90
+ return colours;
91
+ };
92
+ //#endregion
93
+ export { drawPalette, hslToRgb };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"palette.js","sourceRoot":"","sources":["../src/palette.ts"],"names":[],"mappings":"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"}
package/dist/prng.d.ts ADDED
@@ -0,0 +1,10 @@
1
+ export interface Prng {
2
+ next(): number;
3
+ int(min: number, max: number): number;
4
+ range(min: number, max: number): number;
5
+ pick<T>(items: readonly T[]): T;
6
+ }
7
+ export declare const SEED_BYTES = 16;
8
+ export declare const createSeed: () => Buffer;
9
+ export declare const createPrng: (seed: Buffer) => Prng;
10
+ //# sourceMappingURL=prng.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prng.d.ts","sourceRoot":"","sources":["../src/prng.ts"],"names":[],"mappings":"AA2BA,MAAM,WAAW,IAAI;IAEpB,IAAI,IAAI,MAAM,CAAC;IAEf,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IAEtC,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IAExC,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,CAAC,EAAE,GAAG,CAAC,CAAC;CAChC;AAED,eAAO,MAAM,UAAU,KAAK,CAAC;AAG7B,eAAO,MAAM,UAAU,QAAO,MAAiC,CAAC;AAMhE,eAAO,MAAM,UAAU,SAAU,MAAM,KAAG,IA+CzC,CAAC"}
package/dist/prng.js ADDED
@@ -0,0 +1,42 @@
1
+ import { randomBytes } from "node:crypto";
2
+ //#region src/prng.ts
3
+ var SEED_BYTES = 16;
4
+ /** Fresh 128-bit seed from the system CSPRNG. */
5
+ var createSeed = () => randomBytes(16);
6
+ /**
7
+ * xoshiro128** — small, fast, and good enough for imagery. Not a CSPRNG: the
8
+ * secrecy of the output rests on the seed, which is.
9
+ */
10
+ var createPrng = (seed) => {
11
+ if (seed.length < 16) throw new Error(`puzzle-assets: seed must be at least 16 bytes, got ${seed.length}`);
12
+ let s0 = seed.readUInt32LE(0);
13
+ let s1 = seed.readUInt32LE(4);
14
+ let s2 = seed.readUInt32LE(8);
15
+ let s3 = seed.readUInt32LE(12);
16
+ if ((s0 | s1 | s2 | s3) === 0) s0 = 1;
17
+ const rotl = (x, k) => (x << k | x >>> 32 - k) >>> 0;
18
+ const nextUint32 = () => {
19
+ const result = Math.imul(rotl(Math.imul(s1, 5) >>> 0, 7), 9) >>> 0 >>> 0;
20
+ const t = s1 << 9 >>> 0;
21
+ s2 = (s2 ^ s0) >>> 0;
22
+ s3 = (s3 ^ s1) >>> 0;
23
+ s1 = (s1 ^ s2) >>> 0;
24
+ s0 = (s0 ^ s3) >>> 0;
25
+ s2 = (s2 ^ t) >>> 0;
26
+ s3 = rotl(s3, 11);
27
+ return result;
28
+ };
29
+ const next = () => nextUint32() / 4294967296;
30
+ return {
31
+ next,
32
+ int: (min, max) => min + Math.floor(next() * (max - min + 1)),
33
+ range: (min, max) => min + next() * (max - min),
34
+ pick: (items) => {
35
+ const item = items[Math.floor(next() * items.length)];
36
+ if (item === void 0) throw new Error("puzzle-assets: cannot pick from an empty list");
37
+ return item;
38
+ }
39
+ };
40
+ };
41
+ //#endregion
42
+ export { SEED_BYTES, createPrng, createSeed };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prng.js","sourceRoot":"","sources":["../src/prng.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=puzzleAssets.unit.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"puzzleAssets.unit.test.d.ts","sourceRoot":"","sources":["../../src/tests/puzzleAssets.unit.test.ts"],"names":[],"mappings":""}