@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.
- package/CHANGELOG.md +39 -0
- package/dist/_virtual/_rolldown/runtime.js +3 -0
- package/dist/background.d.ts +4 -0
- package/dist/background.d.ts.map +1 -0
- package/dist/background.js +131 -0
- package/dist/background.js.map +1 -0
- package/dist/browser.d.ts +15 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +38 -0
- package/dist/browser.js.map +1 -0
- package/dist/cjs/_virtual/_rolldown/runtime.cjs +23 -0
- package/dist/cjs/background.cjs +131 -0
- package/dist/cjs/compose.cjs +126 -0
- package/dist/cjs/decoys.cjs +105 -0
- package/dist/cjs/encode.cjs +51 -0
- package/dist/cjs/index.cjs +74 -0
- package/dist/cjs/notch.cjs +122 -0
- package/dist/cjs/palette.cjs +94 -0
- package/dist/cjs/prng.cjs +44 -0
- package/dist/compose.d.ts +9 -0
- package/dist/compose.d.ts.map +1 -0
- package/dist/compose.js +126 -0
- package/dist/compose.js.map +1 -0
- package/dist/decoys.d.ts +5 -0
- package/dist/decoys.d.ts.map +1 -0
- package/dist/decoys.js +104 -0
- package/dist/decoys.js.map +1 -0
- package/dist/encode.d.ts +6 -0
- package/dist/encode.d.ts.map +1 -0
- package/dist/encode.js +46 -0
- package/dist/encode.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +59 -0
- package/dist/index.js.map +1 -0
- package/dist/notch.d.ts +7 -0
- package/dist/notch.d.ts.map +1 -0
- package/dist/notch.js +121 -0
- package/dist/notch.js.map +1 -0
- package/dist/palette.d.ts +9 -0
- package/dist/palette.d.ts.map +1 -0
- package/dist/palette.js +93 -0
- package/dist/palette.js.map +1 -0
- package/dist/prng.d.ts +10 -0
- package/dist/prng.d.ts.map +1 -0
- package/dist/prng.js +42 -0
- package/dist/prng.js.map +1 -0
- package/dist/tests/puzzleAssets.unit.test.d.ts +2 -0
- package/dist/tests/puzzleAssets.unit.test.d.ts.map +1 -0
- package/dist/tests/puzzleAssets.unit.test.js +257 -0
- package/dist/tests/puzzleAssets.unit.test.js.map +1 -0
- package/dist/types.d.ts +28 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +61 -0
- package/scripts/preview.ts +197 -0
- package/vite.cjs.config.ts +23 -0
- package/vite.esm.config.ts +27 -0
- 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"}
|
package/dist/index.d.ts
ADDED
|
@@ -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"}
|
package/dist/notch.d.ts
ADDED
|
@@ -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"}
|
package/dist/palette.js
ADDED
|
@@ -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 };
|
package/dist/prng.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prng.js","sourceRoot":"","sources":["../src/prng.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"puzzleAssets.unit.test.d.ts","sourceRoot":"","sources":["../../src/tests/puzzleAssets.unit.test.ts"],"names":[],"mappings":""}
|