@prosopo/icon-order-assets 0.2.5 → 0.2.6
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/.turbo/turbo-build$colon$cjs.log +6 -5
- package/.turbo/turbo-build$colon$esm.log +7 -5
- package/.turbo/turbo-build$colon$tsc.log +5 -5
- package/CHANGELOG.md +13 -0
- package/dist/cjs/background.cjs +2 -2
- package/dist/cjs/compose.cjs +5 -95
- package/dist/cjs/index.cjs +6 -6
- package/dist/cjs/markup.cjs +97 -0
- package/dist/esm/background.js +1 -1
- package/dist/esm/browser.js +24 -0
- package/dist/esm/compose.js +5 -93
- package/dist/esm/index.js +5 -5
- package/dist/esm/markup.js +94 -0
- package/dist/tsc/background.d.ts +1 -1
- package/dist/tsc/background.d.ts.map +1 -1
- package/dist/tsc/background.js +1 -1
- package/dist/tsc/background.js.map +1 -1
- package/dist/tsc/browser.d.ts +14 -0
- package/dist/tsc/browser.d.ts.map +1 -0
- package/dist/tsc/browser.js +18 -0
- package/dist/tsc/browser.js.map +1 -0
- package/dist/tsc/compose.d.ts +1 -1
- package/dist/tsc/compose.d.ts.map +1 -1
- package/dist/tsc/compose.js +5 -77
- package/dist/tsc/compose.js.map +1 -1
- package/dist/tsc/index.d.ts +2 -2
- package/dist/tsc/index.d.ts.map +1 -1
- package/dist/tsc/index.js +5 -3
- package/dist/tsc/index.js.map +1 -1
- package/dist/tsc/markup.d.ts +7 -0
- package/dist/tsc/markup.d.ts.map +1 -0
- package/dist/tsc/markup.js +75 -0
- package/dist/tsc/markup.js.map +1 -0
- package/dist/tsc/place.d.ts +1 -1
- package/dist/tsc/place.d.ts.map +1 -1
- package/dist/tsc/shuffle.d.ts +1 -1
- package/dist/tsc/shuffle.d.ts.map +1 -1
- package/dist/tsc/tests/iconOrderAssets.unit.test.js +29 -0
- package/dist/tsc/tests/iconOrderAssets.unit.test.js.map +1 -1
- package/dist/tsc/types.d.ts +1 -0
- package/dist/tsc/types.d.ts.map +1 -1
- package/dist/types/background.d.ts +1 -1
- package/dist/types/background.d.ts.map +1 -1
- package/dist/types/browser.d.ts +14 -0
- package/dist/types/browser.d.ts.map +1 -0
- package/dist/types/compose.d.ts +1 -1
- package/dist/types/compose.d.ts.map +1 -1
- package/dist/types/index.d.ts +2 -2
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/markup.d.ts +7 -0
- package/dist/types/markup.d.ts.map +1 -0
- package/dist/types/place.d.ts +1 -1
- package/dist/types/place.d.ts.map +1 -1
- package/dist/types/shuffle.d.ts +1 -1
- package/dist/types/shuffle.d.ts.map +1 -1
- package/dist/types/types.d.ts +1 -0
- package/dist/types/types.d.ts.map +1 -1
- package/package.json +8 -3
- package/vite.esm.config.ts +1 -0
|
@@ -10,15 +10,16 @@ ViteCommonJSConfig: .
|
|
|
10
10
|
[36mvite v8.1.6 [32mbuilding ssr environment for production...[36m[39m
|
|
11
11
|
Bundle build started
|
|
12
12
|
[2K
|
|
13
|
-
✓
|
|
13
|
+
✓ 8 modules transformed.
|
|
14
14
|
rendering chunks...
|
|
15
15
|
computing gzip size...
|
|
16
16
|
dist/cjs/shuffle.cjs 0.44 kB │ gzip: 0.29 kB
|
|
17
|
+
dist/cjs/compose.cjs 0.83 kB │ gzip: 0.41 kB
|
|
17
18
|
dist/cjs/_virtual/_rolldown/runtime.cjs 1.00 kB │ gzip: 0.50 kB
|
|
18
19
|
dist/cjs/glyphs.cjs 1.56 kB │ gzip: 0.77 kB
|
|
19
20
|
dist/cjs/place.cjs 2.46 kB │ gzip: 1.12 kB
|
|
20
|
-
dist/cjs/index.cjs 2.
|
|
21
|
-
dist/cjs/background.cjs 4.
|
|
22
|
-
dist/cjs/
|
|
21
|
+
dist/cjs/index.cjs 2.70 kB │ gzip: 1.11 kB
|
|
22
|
+
dist/cjs/background.cjs 4.11 kB │ gzip: 1.43 kB
|
|
23
|
+
dist/cjs/markup.cjs 4.32 kB │ gzip: 1.89 kB
|
|
23
24
|
|
|
24
|
-
[32m✓ built in
|
|
25
|
+
[32m✓ built in 44ms[39m
|
|
@@ -10,15 +10,17 @@ ViteEsmConfig: .
|
|
|
10
10
|
[36mvite v8.1.6 [32mbuilding ssr environment for production...[36m[39m
|
|
11
11
|
Bundle build started
|
|
12
12
|
[2K
|
|
13
|
-
✓
|
|
13
|
+
✓ 9 modules transformed.
|
|
14
14
|
rendering chunks...
|
|
15
15
|
computing gzip size...
|
|
16
16
|
dist/esm/_virtual/_rolldown/runtime.js 0.04 kB │ gzip: 0.06 kB
|
|
17
17
|
dist/esm/shuffle.js 0.43 kB │ gzip: 0.29 kB
|
|
18
|
+
dist/esm/compose.js 0.64 kB │ gzip: 0.35 kB
|
|
19
|
+
dist/esm/browser.js 1.02 kB │ gzip: 0.54 kB
|
|
18
20
|
dist/esm/glyphs.js 1.51 kB │ gzip: 0.76 kB
|
|
19
|
-
dist/esm/index.js 2.
|
|
21
|
+
dist/esm/index.js 2.20 kB │ gzip: 1.02 kB
|
|
20
22
|
dist/esm/place.js 2.38 kB │ gzip: 1.11 kB
|
|
21
|
-
dist/esm/background.js 4.
|
|
22
|
-
dist/esm/
|
|
23
|
+
dist/esm/background.js 4.04 kB │ gzip: 1.41 kB
|
|
24
|
+
dist/esm/markup.js 4.11 kB │ gzip: 1.86 kB
|
|
23
25
|
|
|
24
|
-
[32m✓ built in
|
|
26
|
+
[32m✓ built in 224ms[39m
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
$ tsc --build --verbose
|
|
2
|
-
10:
|
|
2
|
+
10:05:54 AM - Projects in this build:
|
|
3
3
|
* ../../dev/config/tsconfig.json
|
|
4
4
|
* ../puzzle-assets/tsconfig.json
|
|
5
5
|
* tsconfig.json
|
|
6
6
|
|
|
7
|
-
10:
|
|
7
|
+
10:05:54 AM - Project '../../dev/config/tsconfig.json' is up to date because newest input '../../dev/config/src/webpack/webpack.config.ts' is older than output '../../dev/config/dist/tsc/tsconfig.tsbuildinfo'
|
|
8
8
|
|
|
9
|
-
10:
|
|
9
|
+
10:05:54 AM - Project '../puzzle-assets/tsconfig.json' is up to date because newest input '../puzzle-assets/src/types.ts' is older than output '../puzzle-assets/dist/tsc/tsconfig.tsbuildinfo'
|
|
10
10
|
|
|
11
|
-
10:
|
|
11
|
+
10:05:54 AM - Project 'tsconfig.json' is out of date because output file 'dist/tsc/tsconfig.tsbuildinfo' does not exist
|
|
12
12
|
|
|
13
|
-
10:
|
|
13
|
+
10:05:54 AM - Building project '/home/runner/work/captcha/captcha/packages/icon-order-assets/tsconfig.json'...
|
|
14
14
|
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# @prosopo/icon-order-assets
|
|
2
2
|
|
|
3
|
+
## 0.2.6
|
|
4
|
+
### Patch Changes
|
|
5
|
+
|
|
6
|
+
- e1cb7f4: Icon order challenges can now be redrawn exactly, the way puzzle challenges already can.
|
|
7
|
+
|
|
8
|
+
- The provider saves what it needs to redraw each icon order challenge on its record: the render seed, the frame geometry and the render settings (`render`).
|
|
9
|
+
- `@prosopo/icon-order-assets/browser` is a new entry that rebuilds a challenge from those inputs without `sharp`, so the portal can show the image a visitor was served. It returns the frame and the target strip as SVG plus the grain to lay over the frame. Rasterised the same way, the frame matches the served one byte for byte.
|
|
10
|
+
- `@prosopo/puzzle-assets/browser` also exports `hslToRgb` and the `Prng` type, which the new entry uses.
|
|
11
|
+
|
|
12
|
+
The seed regenerates the answer too, so like the puzzle seeds it is never sent to a client.
|
|
13
|
+
- Updated dependencies [e1cb7f4]
|
|
14
|
+
- @prosopo/puzzle-assets@0.2.7
|
|
15
|
+
|
|
3
16
|
## 0.2.5
|
|
4
17
|
### Patch Changes
|
|
5
18
|
|
package/dist/cjs/background.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
let
|
|
1
|
+
let _prosopo_puzzle_assets_browser = require("@prosopo/puzzle-assets/browser");
|
|
2
2
|
//#region src/background.ts
|
|
3
3
|
/**
|
|
4
4
|
* A hard-edged collage rather than a smooth gradient: on a gradient every icon
|
|
@@ -7,7 +7,7 @@ let _prosopo_puzzle_assets = require("@prosopo/puzzle-assets");
|
|
|
7
7
|
*/
|
|
8
8
|
var round = (value) => Math.round(value * 100) / 100;
|
|
9
9
|
var rgb = (hue, saturation, lightness) => {
|
|
10
|
-
const { r, g, b } = (0,
|
|
10
|
+
const { r, g, b } = (0, _prosopo_puzzle_assets_browser.hslToRgb)(hue, saturation, lightness);
|
|
11
11
|
return `rgb(${r},${g},${b})`;
|
|
12
12
|
};
|
|
13
13
|
var panels = (prng, geometry, hues, count) => {
|
package/dist/cjs/compose.cjs
CHANGED
|
@@ -1,108 +1,18 @@
|
|
|
1
1
|
const require_runtime = require("./_virtual/_rolldown/runtime.cjs");
|
|
2
|
-
const
|
|
3
|
-
const require_glyphs = require("./glyphs.cjs");
|
|
4
|
-
const require_shuffle = require("./shuffle.cjs");
|
|
5
|
-
let _prosopo_puzzle_assets = require("@prosopo/puzzle-assets");
|
|
2
|
+
const require_markup = require("./markup.cjs");
|
|
6
3
|
let sharp = require("sharp");
|
|
7
4
|
sharp = require_runtime.__toESM(sharp, 1);
|
|
8
5
|
//#region src/compose.ts
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Width of the dark outline stroke relative to the bright one. Narrower and
|
|
13
|
-
* icons vanish over light regions; wider and the halo becomes the strongest
|
|
14
|
-
* edge in the frame, which is what a solver looks for.
|
|
15
|
-
*/
|
|
16
|
-
var HALO_WIDTH_MULTIPLE = 2.4;
|
|
17
|
-
var HALO_COLOUR = "rgb(12,14,22)";
|
|
18
|
-
var LEGEND_CHIP_COLOUR = "rgb(24,27,38)";
|
|
19
|
-
var LEGEND_GAP = 6;
|
|
20
|
-
var LEGEND_GLYPH_INSET = .62;
|
|
21
|
-
var round = (value) => Math.round(value * 100) / 100;
|
|
22
|
-
var strokeColour = (hue) => {
|
|
23
|
-
const { r, g, b } = (0, _prosopo_puzzle_assets.hslToRgb)(hue, .86, .64);
|
|
24
|
-
return `rgb(${r},${g},${b})`;
|
|
25
|
-
};
|
|
26
|
-
/**
|
|
27
|
-
* Converts a frame-pixel stroke width into glyph-box units, so line weight
|
|
28
|
-
* does not vary with (and so leak) the icon's size.
|
|
29
|
-
*/
|
|
30
|
-
var strokeUnits = (widthPx, size) => widthPx * GLYPH_BOX / size;
|
|
31
|
-
var glyphMarkup = (placement, settings, rotationOverride) => {
|
|
32
|
-
const scale = placement.size / GLYPH_BOX;
|
|
33
|
-
const rotation = rotationOverride ?? placement.rotation;
|
|
34
|
-
const inner = strokeUnits(settings.strokeWidth, placement.size);
|
|
35
|
-
const halo = inner * HALO_WIDTH_MULTIPLE;
|
|
36
|
-
const path = require_glyphs.glyphPath(placement.kind);
|
|
37
|
-
return [
|
|
38
|
-
`<g transform="${[
|
|
39
|
-
`translate(${round(placement.x)} ${round(placement.y)})`,
|
|
40
|
-
`rotate(${round(rotation)})`,
|
|
41
|
-
`scale(${round(scale)})`,
|
|
42
|
-
`translate(${-GLYPH_BOX / 2} ${-GLYPH_BOX / 2})`
|
|
43
|
-
].join(" ")}" fill="none" stroke-linecap="round" stroke-linejoin="round">`,
|
|
44
|
-
`<path d="${path}" stroke="${HALO_COLOUR}" stroke-opacity="${round(settings.haloOpacity)}" stroke-width="${round(halo)}"/>`,
|
|
45
|
-
`<path d="${path}" stroke="${strokeColour(placement.hue)}" stroke-opacity="${round(settings.iconOpacity)}" stroke-width="${round(inner)}"/>`,
|
|
46
|
-
"</g>"
|
|
47
|
-
].join("");
|
|
48
|
-
};
|
|
49
|
-
var svgDocument = (width, height, body) => Buffer.from(`<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}">${body}</svg>`);
|
|
50
|
-
/**
|
|
51
|
-
* Draw order is shuffled here because callers hold targets and decoys as
|
|
52
|
-
* separate lists, and concatenating them would paint every target on top
|
|
53
|
-
* wherever icons overlap — a tell that needs no shape recognition.
|
|
54
|
-
*/
|
|
55
|
-
var compositeIcons = async (prng, icons, geometry, settings) => {
|
|
56
|
-
const body = require_shuffle.shuffle(prng, icons).map((placement) => glyphMarkup(placement, settings)).join("");
|
|
57
|
-
const document = svgDocument(geometry.width, geometry.height, require_background.collageMarkup(prng, geometry, settings.backgroundClutter) + body);
|
|
58
|
-
const { data, info } = await (0, sharp.default)(document).ensureAlpha().raw().toBuffer({ resolveWithObject: true });
|
|
59
|
-
return addGrain(prng, {
|
|
60
|
-
data,
|
|
61
|
-
width: info.width,
|
|
62
|
-
height: info.height
|
|
63
|
-
});
|
|
64
|
-
};
|
|
65
|
-
/**
|
|
66
|
-
* Noise over the flat vector fills, so region boundaries are not perfectly
|
|
67
|
-
* clean input for an edge detector.
|
|
68
|
-
*/
|
|
69
|
-
var GRAIN_AMPLITUDE = 6;
|
|
70
|
-
var addGrain = (prng, image) => {
|
|
71
|
-
const { data } = image;
|
|
72
|
-
for (let i = 0; i < data.length; i += 4) {
|
|
73
|
-
const noise = Math.round((prng.next() - .5) * 2 * GRAIN_AMPLITUDE);
|
|
74
|
-
for (let channel = 0; channel < 3; channel++) {
|
|
75
|
-
const value = (data[i + channel] ?? 0) + noise;
|
|
76
|
-
data[i + channel] = value < 0 ? 0 : value > 255 ? 255 : value;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
return image;
|
|
80
|
-
};
|
|
81
|
-
/**
|
|
82
|
-
* Legend glyphs are drawn upright whatever their rotation on the frame, so a
|
|
83
|
-
* template-matching solver is not handed a rotation-aligned crib. The hue is
|
|
84
|
-
* kept: it helps a human and a solver already has it from the pixels.
|
|
85
|
-
*/
|
|
86
|
-
var renderLegend = async (targets, legendIconSize, settings) => {
|
|
87
|
-
const step = legendIconSize + LEGEND_GAP;
|
|
88
|
-
const width = Math.max(legendIconSize, targets.length * step - (targets.length > 0 ? LEGEND_GAP : 0));
|
|
89
|
-
const radius = legendIconSize / 2;
|
|
90
|
-
const body = targets.map((target, index) => {
|
|
91
|
-
const cx = index * step + radius;
|
|
92
|
-
return `<circle cx="${round(cx)}" cy="${round(radius)}" r="${round(radius)}" fill="${LEGEND_CHIP_COLOUR}"/>` + glyphMarkup({
|
|
93
|
-
...target,
|
|
94
|
-
x: cx,
|
|
95
|
-
y: radius,
|
|
96
|
-
size: legendIconSize * LEGEND_GLYPH_INSET
|
|
97
|
-
}, settings, 0);
|
|
98
|
-
}).join("");
|
|
99
|
-
const { data, info } = await (0, sharp.default)(svgDocument(width, legendIconSize, body)).ensureAlpha().raw().toBuffer({ resolveWithObject: true });
|
|
6
|
+
var rasterise = async (svg) => {
|
|
7
|
+
const { data, info } = await (0, sharp.default)(Buffer.from(svg)).ensureAlpha().raw().toBuffer({ resolveWithObject: true });
|
|
100
8
|
return {
|
|
101
9
|
data,
|
|
102
10
|
width: info.width,
|
|
103
11
|
height: info.height
|
|
104
12
|
};
|
|
105
13
|
};
|
|
14
|
+
var compositeIcons = async (prng, icons, geometry, settings) => require_markup.addGrain(prng, await rasterise(require_markup.frameMarkup(prng, icons, geometry, settings)));
|
|
15
|
+
var renderLegend = (targets, legendIconSize, settings) => rasterise(require_markup.legendMarkup(targets, legendIconSize, settings));
|
|
106
16
|
//#endregion
|
|
107
17
|
exports.compositeIcons = compositeIcons;
|
|
108
18
|
exports.renderLegend = renderLegend;
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_glyphs = require("./glyphs.cjs");
|
|
3
|
+
const require_markup = require("./markup.cjs");
|
|
3
4
|
const require_compose = require("./compose.cjs");
|
|
4
5
|
const require_place = require("./place.cjs");
|
|
5
6
|
let _prosopo_puzzle_assets = require("@prosopo/puzzle-assets");
|
|
@@ -19,15 +20,13 @@ var DEFAULT_RENDER_SETTINGS = {
|
|
|
19
20
|
haloOpacity: .7,
|
|
20
21
|
backgroundClutter: 8
|
|
21
22
|
};
|
|
22
|
-
/** Fixed because the widget lays the legend out against its own header. */
|
|
23
|
-
var LEGEND_ICON_SIZE = 26;
|
|
24
23
|
/**
|
|
25
24
|
* The background is drawn fresh per call and never reused: two layouts on the
|
|
26
25
|
* same background could be diffed to read both answers. The returned
|
|
27
26
|
* `targets` are the answer and must never be serialised into a response.
|
|
28
27
|
*/
|
|
29
|
-
var renderIconOrder = async (geometry = DEFAULT_GEOMETRY, settings = DEFAULT_RENDER_SETTINGS) => {
|
|
30
|
-
const prng = (0, _prosopo_puzzle_assets.createPrng)(
|
|
28
|
+
var renderIconOrder = async (geometry = DEFAULT_GEOMETRY, settings = DEFAULT_RENDER_SETTINGS, seed = (0, _prosopo_puzzle_assets.createSeed)()) => {
|
|
29
|
+
const prng = (0, _prosopo_puzzle_assets.createPrng)(seed);
|
|
31
30
|
const { targets, decoys } = require_place.placeIcons(prng, geometry, settings.targetCount, settings.decoyCount);
|
|
32
31
|
const composited = await require_compose.compositeIcons(prng, [...targets, ...decoys], geometry, settings);
|
|
33
32
|
const legend = await require_compose.renderLegend(targets, 26, settings);
|
|
@@ -36,7 +35,8 @@ var renderIconOrder = async (geometry = DEFAULT_GEOMETRY, settings = DEFAULT_REN
|
|
|
36
35
|
background: backgroundWebp,
|
|
37
36
|
legend: legendWebp,
|
|
38
37
|
legendIconSize: 26,
|
|
39
|
-
targets
|
|
38
|
+
targets,
|
|
39
|
+
seed: seed.toString("hex")
|
|
40
40
|
};
|
|
41
41
|
};
|
|
42
42
|
/**
|
|
@@ -55,7 +55,7 @@ exports.DEFAULT_GEOMETRY = DEFAULT_GEOMETRY;
|
|
|
55
55
|
exports.DEFAULT_RENDER_SETTINGS = DEFAULT_RENDER_SETTINGS;
|
|
56
56
|
exports.GLYPH_KINDS = require_glyphs.GLYPH_KINDS;
|
|
57
57
|
exports.GlyphKind = require_glyphs.GlyphKind;
|
|
58
|
-
exports.LEGEND_ICON_SIZE = LEGEND_ICON_SIZE;
|
|
58
|
+
exports.LEGEND_ICON_SIZE = require_markup.LEGEND_ICON_SIZE;
|
|
59
59
|
exports.compositeIcons = require_compose.compositeIcons;
|
|
60
60
|
exports.glyphPath = require_glyphs.glyphPath;
|
|
61
61
|
exports.gradeClicks = gradeClicks;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
const require_background = require("./background.cjs");
|
|
2
|
+
const require_glyphs = require("./glyphs.cjs");
|
|
3
|
+
const require_shuffle = require("./shuffle.cjs");
|
|
4
|
+
let _prosopo_puzzle_assets_browser = require("@prosopo/puzzle-assets/browser");
|
|
5
|
+
//#region src/markup.ts
|
|
6
|
+
/** Glyph path data is authored in this box; see glyphs.ts. */
|
|
7
|
+
var GLYPH_BOX = 100;
|
|
8
|
+
/**
|
|
9
|
+
* Width of the dark outline stroke relative to the bright one. Narrower and
|
|
10
|
+
* icons vanish over light regions; wider and the halo becomes the strongest
|
|
11
|
+
* edge in the frame, which is what a solver looks for.
|
|
12
|
+
*/
|
|
13
|
+
var HALO_WIDTH_MULTIPLE = 2.4;
|
|
14
|
+
var HALO_COLOUR = "rgb(12,14,22)";
|
|
15
|
+
/** Fixed because the widget lays the legend out against its own header. */
|
|
16
|
+
var LEGEND_ICON_SIZE = 26;
|
|
17
|
+
var LEGEND_CHIP_COLOUR = "rgb(24,27,38)";
|
|
18
|
+
var LEGEND_GAP = 6;
|
|
19
|
+
var LEGEND_GLYPH_INSET = .62;
|
|
20
|
+
var round = (value) => Math.round(value * 100) / 100;
|
|
21
|
+
var strokeColour = (hue) => {
|
|
22
|
+
const { r, g, b } = (0, _prosopo_puzzle_assets_browser.hslToRgb)(hue, .86, .64);
|
|
23
|
+
return `rgb(${r},${g},${b})`;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Converts a frame-pixel stroke width into glyph-box units, so line weight
|
|
27
|
+
* does not vary with (and so leak) the icon's size.
|
|
28
|
+
*/
|
|
29
|
+
var strokeUnits = (widthPx, size) => widthPx * GLYPH_BOX / size;
|
|
30
|
+
var glyphMarkup = (placement, settings, rotationOverride) => {
|
|
31
|
+
const scale = placement.size / GLYPH_BOX;
|
|
32
|
+
const rotation = rotationOverride ?? placement.rotation;
|
|
33
|
+
const inner = strokeUnits(settings.strokeWidth, placement.size);
|
|
34
|
+
const halo = inner * HALO_WIDTH_MULTIPLE;
|
|
35
|
+
const path = require_glyphs.glyphPath(placement.kind);
|
|
36
|
+
return [
|
|
37
|
+
`<g transform="${[
|
|
38
|
+
`translate(${round(placement.x)} ${round(placement.y)})`,
|
|
39
|
+
`rotate(${round(rotation)})`,
|
|
40
|
+
`scale(${round(scale)})`,
|
|
41
|
+
`translate(${-GLYPH_BOX / 2} ${-GLYPH_BOX / 2})`
|
|
42
|
+
].join(" ")}" fill="none" stroke-linecap="round" stroke-linejoin="round">`,
|
|
43
|
+
`<path d="${path}" stroke="${HALO_COLOUR}" stroke-opacity="${round(settings.haloOpacity)}" stroke-width="${round(halo)}"/>`,
|
|
44
|
+
`<path d="${path}" stroke="${strokeColour(placement.hue)}" stroke-opacity="${round(settings.iconOpacity)}" stroke-width="${round(inner)}"/>`,
|
|
45
|
+
"</g>"
|
|
46
|
+
].join("");
|
|
47
|
+
};
|
|
48
|
+
var svgDocument = (width, height, body) => `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}">${body}</svg>`;
|
|
49
|
+
/**
|
|
50
|
+
* Draw order is shuffled here because callers hold targets and decoys as
|
|
51
|
+
* separate lists, and concatenating them would paint every target on top
|
|
52
|
+
* wherever icons overlap — a tell that needs no shape recognition.
|
|
53
|
+
*/
|
|
54
|
+
var frameMarkup = (prng, icons, geometry, settings) => {
|
|
55
|
+
const body = require_shuffle.shuffle(prng, icons).map((placement) => glyphMarkup(placement, settings)).join("");
|
|
56
|
+
return svgDocument(geometry.width, geometry.height, require_background.collageMarkup(prng, geometry, settings.backgroundClutter) + body);
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* Noise over the flat vector fills, so region boundaries are not perfectly
|
|
60
|
+
* clean input for an edge detector.
|
|
61
|
+
*/
|
|
62
|
+
var GRAIN_AMPLITUDE = 6;
|
|
63
|
+
var addGrain = (prng, image) => {
|
|
64
|
+
const { data } = image;
|
|
65
|
+
for (let i = 0; i < data.length; i += 4) {
|
|
66
|
+
const noise = Math.round((prng.next() - .5) * 2 * GRAIN_AMPLITUDE);
|
|
67
|
+
for (let channel = 0; channel < 3; channel++) {
|
|
68
|
+
const value = (data[i + channel] ?? 0) + noise;
|
|
69
|
+
data[i + channel] = value < 0 ? 0 : value > 255 ? 255 : value;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return image;
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* Legend glyphs are drawn upright whatever their rotation on the frame, so a
|
|
76
|
+
* template-matching solver is not handed a rotation-aligned crib. The hue is
|
|
77
|
+
* kept: it helps a human and a solver already has it from the pixels.
|
|
78
|
+
*/
|
|
79
|
+
var legendMarkup = (targets, legendIconSize, settings) => {
|
|
80
|
+
const step = legendIconSize + LEGEND_GAP;
|
|
81
|
+
const width = Math.max(legendIconSize, targets.length * step - (targets.length > 0 ? LEGEND_GAP : 0));
|
|
82
|
+
const radius = legendIconSize / 2;
|
|
83
|
+
return svgDocument(width, legendIconSize, targets.map((target, index) => {
|
|
84
|
+
const cx = index * step + radius;
|
|
85
|
+
return `<circle cx="${round(cx)}" cy="${round(radius)}" r="${round(radius)}" fill="${LEGEND_CHIP_COLOUR}"/>` + glyphMarkup({
|
|
86
|
+
...target,
|
|
87
|
+
x: cx,
|
|
88
|
+
y: radius,
|
|
89
|
+
size: legendIconSize * LEGEND_GLYPH_INSET
|
|
90
|
+
}, settings, 0);
|
|
91
|
+
}).join(""));
|
|
92
|
+
};
|
|
93
|
+
//#endregion
|
|
94
|
+
exports.LEGEND_ICON_SIZE = LEGEND_ICON_SIZE;
|
|
95
|
+
exports.addGrain = addGrain;
|
|
96
|
+
exports.frameMarkup = frameMarkup;
|
|
97
|
+
exports.legendMarkup = legendMarkup;
|
package/dist/esm/background.js
CHANGED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import "./_virtual/_rolldown/runtime.js";
|
|
2
|
+
import { GLYPH_KINDS, GlyphKind, glyphPath } from "./glyphs.js";
|
|
3
|
+
import { LEGEND_ICON_SIZE, addGrain, frameMarkup, legendMarkup } from "./markup.js";
|
|
4
|
+
import { placeIcons } from "./place.js";
|
|
5
|
+
import { createPrng } from "@prosopo/puzzle-assets/browser";
|
|
6
|
+
//#region src/browser.ts
|
|
7
|
+
/**
|
|
8
|
+
* Rebuilds what the provider drew for `seed`. A browser rasterises SVG a
|
|
9
|
+
* little differently from sharp, so the result matches the served image
|
|
10
|
+
* closely rather than pixel for pixel.
|
|
11
|
+
*/
|
|
12
|
+
var redrawIconOrder = (seed, geometry, settings) => {
|
|
13
|
+
const prng = createPrng(Buffer.from(seed, "hex"));
|
|
14
|
+
const { targets, decoys } = placeIcons(prng, geometry, settings.targetCount, settings.decoyCount);
|
|
15
|
+
return {
|
|
16
|
+
frame: frameMarkup(prng, [...targets, ...decoys], geometry, settings),
|
|
17
|
+
legend: legendMarkup(targets, 26, settings),
|
|
18
|
+
legendIconSize: 26,
|
|
19
|
+
targets,
|
|
20
|
+
addGrain: (image) => addGrain(prng, image)
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
//#endregion
|
|
24
|
+
export { GLYPH_KINDS, GlyphKind, LEGEND_ICON_SIZE, glyphPath, redrawIconOrder };
|
package/dist/esm/compose.js
CHANGED
|
@@ -1,103 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { glyphPath } from "./glyphs.js";
|
|
3
|
-
import { shuffle } from "./shuffle.js";
|
|
4
|
-
import { hslToRgb } from "@prosopo/puzzle-assets";
|
|
1
|
+
import { addGrain, frameMarkup, legendMarkup } from "./markup.js";
|
|
5
2
|
import sharp from "sharp";
|
|
6
3
|
//#region src/compose.ts
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Width of the dark outline stroke relative to the bright one. Narrower and
|
|
11
|
-
* icons vanish over light regions; wider and the halo becomes the strongest
|
|
12
|
-
* edge in the frame, which is what a solver looks for.
|
|
13
|
-
*/
|
|
14
|
-
var HALO_WIDTH_MULTIPLE = 2.4;
|
|
15
|
-
var HALO_COLOUR = "rgb(12,14,22)";
|
|
16
|
-
var LEGEND_CHIP_COLOUR = "rgb(24,27,38)";
|
|
17
|
-
var LEGEND_GAP = 6;
|
|
18
|
-
var LEGEND_GLYPH_INSET = .62;
|
|
19
|
-
var round = (value) => Math.round(value * 100) / 100;
|
|
20
|
-
var strokeColour = (hue) => {
|
|
21
|
-
const { r, g, b } = hslToRgb(hue, .86, .64);
|
|
22
|
-
return `rgb(${r},${g},${b})`;
|
|
23
|
-
};
|
|
24
|
-
/**
|
|
25
|
-
* Converts a frame-pixel stroke width into glyph-box units, so line weight
|
|
26
|
-
* does not vary with (and so leak) the icon's size.
|
|
27
|
-
*/
|
|
28
|
-
var strokeUnits = (widthPx, size) => widthPx * GLYPH_BOX / size;
|
|
29
|
-
var glyphMarkup = (placement, settings, rotationOverride) => {
|
|
30
|
-
const scale = placement.size / GLYPH_BOX;
|
|
31
|
-
const rotation = rotationOverride ?? placement.rotation;
|
|
32
|
-
const inner = strokeUnits(settings.strokeWidth, placement.size);
|
|
33
|
-
const halo = inner * HALO_WIDTH_MULTIPLE;
|
|
34
|
-
const path = glyphPath(placement.kind);
|
|
35
|
-
return [
|
|
36
|
-
`<g transform="${[
|
|
37
|
-
`translate(${round(placement.x)} ${round(placement.y)})`,
|
|
38
|
-
`rotate(${round(rotation)})`,
|
|
39
|
-
`scale(${round(scale)})`,
|
|
40
|
-
`translate(${-GLYPH_BOX / 2} ${-GLYPH_BOX / 2})`
|
|
41
|
-
].join(" ")}" fill="none" stroke-linecap="round" stroke-linejoin="round">`,
|
|
42
|
-
`<path d="${path}" stroke="${HALO_COLOUR}" stroke-opacity="${round(settings.haloOpacity)}" stroke-width="${round(halo)}"/>`,
|
|
43
|
-
`<path d="${path}" stroke="${strokeColour(placement.hue)}" stroke-opacity="${round(settings.iconOpacity)}" stroke-width="${round(inner)}"/>`,
|
|
44
|
-
"</g>"
|
|
45
|
-
].join("");
|
|
46
|
-
};
|
|
47
|
-
var svgDocument = (width, height, body) => Buffer.from(`<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}">${body}</svg>`);
|
|
48
|
-
/**
|
|
49
|
-
* Draw order is shuffled here because callers hold targets and decoys as
|
|
50
|
-
* separate lists, and concatenating them would paint every target on top
|
|
51
|
-
* wherever icons overlap — a tell that needs no shape recognition.
|
|
52
|
-
*/
|
|
53
|
-
var compositeIcons = async (prng, icons, geometry, settings) => {
|
|
54
|
-
const body = shuffle(prng, icons).map((placement) => glyphMarkup(placement, settings)).join("");
|
|
55
|
-
const { data, info } = await sharp(svgDocument(geometry.width, geometry.height, collageMarkup(prng, geometry, settings.backgroundClutter) + body)).ensureAlpha().raw().toBuffer({ resolveWithObject: true });
|
|
56
|
-
return addGrain(prng, {
|
|
57
|
-
data,
|
|
58
|
-
width: info.width,
|
|
59
|
-
height: info.height
|
|
60
|
-
});
|
|
61
|
-
};
|
|
62
|
-
/**
|
|
63
|
-
* Noise over the flat vector fills, so region boundaries are not perfectly
|
|
64
|
-
* clean input for an edge detector.
|
|
65
|
-
*/
|
|
66
|
-
var GRAIN_AMPLITUDE = 6;
|
|
67
|
-
var addGrain = (prng, image) => {
|
|
68
|
-
const { data } = image;
|
|
69
|
-
for (let i = 0; i < data.length; i += 4) {
|
|
70
|
-
const noise = Math.round((prng.next() - .5) * 2 * GRAIN_AMPLITUDE);
|
|
71
|
-
for (let channel = 0; channel < 3; channel++) {
|
|
72
|
-
const value = (data[i + channel] ?? 0) + noise;
|
|
73
|
-
data[i + channel] = value < 0 ? 0 : value > 255 ? 255 : value;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
return image;
|
|
77
|
-
};
|
|
78
|
-
/**
|
|
79
|
-
* Legend glyphs are drawn upright whatever their rotation on the frame, so a
|
|
80
|
-
* template-matching solver is not handed a rotation-aligned crib. The hue is
|
|
81
|
-
* kept: it helps a human and a solver already has it from the pixels.
|
|
82
|
-
*/
|
|
83
|
-
var renderLegend = async (targets, legendIconSize, settings) => {
|
|
84
|
-
const step = legendIconSize + LEGEND_GAP;
|
|
85
|
-
const width = Math.max(legendIconSize, targets.length * step - (targets.length > 0 ? LEGEND_GAP : 0));
|
|
86
|
-
const radius = legendIconSize / 2;
|
|
87
|
-
const { data, info } = await sharp(svgDocument(width, legendIconSize, targets.map((target, index) => {
|
|
88
|
-
const cx = index * step + radius;
|
|
89
|
-
return `<circle cx="${round(cx)}" cy="${round(radius)}" r="${round(radius)}" fill="${LEGEND_CHIP_COLOUR}"/>` + glyphMarkup({
|
|
90
|
-
...target,
|
|
91
|
-
x: cx,
|
|
92
|
-
y: radius,
|
|
93
|
-
size: legendIconSize * LEGEND_GLYPH_INSET
|
|
94
|
-
}, settings, 0);
|
|
95
|
-
}).join(""))).ensureAlpha().raw().toBuffer({ resolveWithObject: true });
|
|
4
|
+
var rasterise = async (svg) => {
|
|
5
|
+
const { data, info } = await sharp(Buffer.from(svg)).ensureAlpha().raw().toBuffer({ resolveWithObject: true });
|
|
96
6
|
return {
|
|
97
7
|
data,
|
|
98
8
|
width: info.width,
|
|
99
9
|
height: info.height
|
|
100
10
|
};
|
|
101
11
|
};
|
|
12
|
+
var compositeIcons = async (prng, icons, geometry, settings) => addGrain(prng, await rasterise(frameMarkup(prng, icons, geometry, settings)));
|
|
13
|
+
var renderLegend = (targets, legendIconSize, settings) => rasterise(legendMarkup(targets, legendIconSize, settings));
|
|
102
14
|
//#endregion
|
|
103
15
|
export { compositeIcons, renderLegend };
|
package/dist/esm/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import "./_virtual/_rolldown/runtime.js";
|
|
2
2
|
import { GLYPH_KINDS, GlyphKind, glyphPath } from "./glyphs.js";
|
|
3
|
+
import { LEGEND_ICON_SIZE } from "./markup.js";
|
|
3
4
|
import { compositeIcons, renderLegend } from "./compose.js";
|
|
4
5
|
import { placeIcons } from "./place.js";
|
|
5
6
|
import { createPrng, createSeed, encodeBackground, encodePiece } from "@prosopo/puzzle-assets";
|
|
@@ -19,15 +20,13 @@ var DEFAULT_RENDER_SETTINGS = {
|
|
|
19
20
|
haloOpacity: .7,
|
|
20
21
|
backgroundClutter: 8
|
|
21
22
|
};
|
|
22
|
-
/** Fixed because the widget lays the legend out against its own header. */
|
|
23
|
-
var LEGEND_ICON_SIZE = 26;
|
|
24
23
|
/**
|
|
25
24
|
* The background is drawn fresh per call and never reused: two layouts on the
|
|
26
25
|
* same background could be diffed to read both answers. The returned
|
|
27
26
|
* `targets` are the answer and must never be serialised into a response.
|
|
28
27
|
*/
|
|
29
|
-
var renderIconOrder = async (geometry = DEFAULT_GEOMETRY, settings = DEFAULT_RENDER_SETTINGS) => {
|
|
30
|
-
const prng = createPrng(
|
|
28
|
+
var renderIconOrder = async (geometry = DEFAULT_GEOMETRY, settings = DEFAULT_RENDER_SETTINGS, seed = createSeed()) => {
|
|
29
|
+
const prng = createPrng(seed);
|
|
31
30
|
const { targets, decoys } = placeIcons(prng, geometry, settings.targetCount, settings.decoyCount);
|
|
32
31
|
const composited = await compositeIcons(prng, [...targets, ...decoys], geometry, settings);
|
|
33
32
|
const legend = await renderLegend(targets, 26, settings);
|
|
@@ -36,7 +35,8 @@ var renderIconOrder = async (geometry = DEFAULT_GEOMETRY, settings = DEFAULT_REN
|
|
|
36
35
|
background: backgroundWebp,
|
|
37
36
|
legend: legendWebp,
|
|
38
37
|
legendIconSize: 26,
|
|
39
|
-
targets
|
|
38
|
+
targets,
|
|
39
|
+
seed: seed.toString("hex")
|
|
40
40
|
};
|
|
41
41
|
};
|
|
42
42
|
/**
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { collageMarkup } from "./background.js";
|
|
2
|
+
import { glyphPath } from "./glyphs.js";
|
|
3
|
+
import { shuffle } from "./shuffle.js";
|
|
4
|
+
import { hslToRgb } from "@prosopo/puzzle-assets/browser";
|
|
5
|
+
//#region src/markup.ts
|
|
6
|
+
/** Glyph path data is authored in this box; see glyphs.ts. */
|
|
7
|
+
var GLYPH_BOX = 100;
|
|
8
|
+
/**
|
|
9
|
+
* Width of the dark outline stroke relative to the bright one. Narrower and
|
|
10
|
+
* icons vanish over light regions; wider and the halo becomes the strongest
|
|
11
|
+
* edge in the frame, which is what a solver looks for.
|
|
12
|
+
*/
|
|
13
|
+
var HALO_WIDTH_MULTIPLE = 2.4;
|
|
14
|
+
var HALO_COLOUR = "rgb(12,14,22)";
|
|
15
|
+
/** Fixed because the widget lays the legend out against its own header. */
|
|
16
|
+
var LEGEND_ICON_SIZE = 26;
|
|
17
|
+
var LEGEND_CHIP_COLOUR = "rgb(24,27,38)";
|
|
18
|
+
var LEGEND_GAP = 6;
|
|
19
|
+
var LEGEND_GLYPH_INSET = .62;
|
|
20
|
+
var round = (value) => Math.round(value * 100) / 100;
|
|
21
|
+
var strokeColour = (hue) => {
|
|
22
|
+
const { r, g, b } = hslToRgb(hue, .86, .64);
|
|
23
|
+
return `rgb(${r},${g},${b})`;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Converts a frame-pixel stroke width into glyph-box units, so line weight
|
|
27
|
+
* does not vary with (and so leak) the icon's size.
|
|
28
|
+
*/
|
|
29
|
+
var strokeUnits = (widthPx, size) => widthPx * GLYPH_BOX / size;
|
|
30
|
+
var glyphMarkup = (placement, settings, rotationOverride) => {
|
|
31
|
+
const scale = placement.size / GLYPH_BOX;
|
|
32
|
+
const rotation = rotationOverride ?? placement.rotation;
|
|
33
|
+
const inner = strokeUnits(settings.strokeWidth, placement.size);
|
|
34
|
+
const halo = inner * HALO_WIDTH_MULTIPLE;
|
|
35
|
+
const path = glyphPath(placement.kind);
|
|
36
|
+
return [
|
|
37
|
+
`<g transform="${[
|
|
38
|
+
`translate(${round(placement.x)} ${round(placement.y)})`,
|
|
39
|
+
`rotate(${round(rotation)})`,
|
|
40
|
+
`scale(${round(scale)})`,
|
|
41
|
+
`translate(${-GLYPH_BOX / 2} ${-GLYPH_BOX / 2})`
|
|
42
|
+
].join(" ")}" fill="none" stroke-linecap="round" stroke-linejoin="round">`,
|
|
43
|
+
`<path d="${path}" stroke="${HALO_COLOUR}" stroke-opacity="${round(settings.haloOpacity)}" stroke-width="${round(halo)}"/>`,
|
|
44
|
+
`<path d="${path}" stroke="${strokeColour(placement.hue)}" stroke-opacity="${round(settings.iconOpacity)}" stroke-width="${round(inner)}"/>`,
|
|
45
|
+
"</g>"
|
|
46
|
+
].join("");
|
|
47
|
+
};
|
|
48
|
+
var svgDocument = (width, height, body) => `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}">${body}</svg>`;
|
|
49
|
+
/**
|
|
50
|
+
* Draw order is shuffled here because callers hold targets and decoys as
|
|
51
|
+
* separate lists, and concatenating them would paint every target on top
|
|
52
|
+
* wherever icons overlap — a tell that needs no shape recognition.
|
|
53
|
+
*/
|
|
54
|
+
var frameMarkup = (prng, icons, geometry, settings) => {
|
|
55
|
+
const body = shuffle(prng, icons).map((placement) => glyphMarkup(placement, settings)).join("");
|
|
56
|
+
return svgDocument(geometry.width, geometry.height, collageMarkup(prng, geometry, settings.backgroundClutter) + body);
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* Noise over the flat vector fills, so region boundaries are not perfectly
|
|
60
|
+
* clean input for an edge detector.
|
|
61
|
+
*/
|
|
62
|
+
var GRAIN_AMPLITUDE = 6;
|
|
63
|
+
var addGrain = (prng, image) => {
|
|
64
|
+
const { data } = image;
|
|
65
|
+
for (let i = 0; i < data.length; i += 4) {
|
|
66
|
+
const noise = Math.round((prng.next() - .5) * 2 * GRAIN_AMPLITUDE);
|
|
67
|
+
for (let channel = 0; channel < 3; channel++) {
|
|
68
|
+
const value = (data[i + channel] ?? 0) + noise;
|
|
69
|
+
data[i + channel] = value < 0 ? 0 : value > 255 ? 255 : value;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return image;
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* Legend glyphs are drawn upright whatever their rotation on the frame, so a
|
|
76
|
+
* template-matching solver is not handed a rotation-aligned crib. The hue is
|
|
77
|
+
* kept: it helps a human and a solver already has it from the pixels.
|
|
78
|
+
*/
|
|
79
|
+
var legendMarkup = (targets, legendIconSize, settings) => {
|
|
80
|
+
const step = legendIconSize + LEGEND_GAP;
|
|
81
|
+
const width = Math.max(legendIconSize, targets.length * step - (targets.length > 0 ? LEGEND_GAP : 0));
|
|
82
|
+
const radius = legendIconSize / 2;
|
|
83
|
+
return svgDocument(width, legendIconSize, targets.map((target, index) => {
|
|
84
|
+
const cx = index * step + radius;
|
|
85
|
+
return `<circle cx="${round(cx)}" cy="${round(radius)}" r="${round(radius)}" fill="${LEGEND_CHIP_COLOUR}"/>` + glyphMarkup({
|
|
86
|
+
...target,
|
|
87
|
+
x: cx,
|
|
88
|
+
y: radius,
|
|
89
|
+
size: legendIconSize * LEGEND_GLYPH_INSET
|
|
90
|
+
}, settings, 0);
|
|
91
|
+
}).join(""));
|
|
92
|
+
};
|
|
93
|
+
//#endregion
|
|
94
|
+
export { LEGEND_ICON_SIZE, addGrain, frameMarkup, legendMarkup };
|
package/dist/tsc/background.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type Prng } from "@prosopo/puzzle-assets";
|
|
1
|
+
import { type Prng } from "@prosopo/puzzle-assets/browser";
|
|
2
2
|
import type { IconOrderGeometry } from "./types.js";
|
|
3
3
|
export declare const collageMarkup: (prng: Prng, geometry: IconOrderGeometry, clutter: number) => string;
|
|
4
4
|
//# sourceMappingURL=background.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"background.d.ts","sourceRoot":"","sources":["../../src/background.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,KAAK,IAAI,EAAY,MAAM,
|
|
1
|
+
{"version":3,"file":"background.d.ts","sourceRoot":"","sources":["../../src/background.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,KAAK,IAAI,EAAY,MAAM,gCAAgC,CAAC;AACrE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AA6GpD,eAAO,MAAM,aAAa,SACnB,IAAI,YACA,iBAAiB,WAClB,MAAM,KACb,MA0BF,CAAC"}
|
package/dist/tsc/background.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { hslToRgb } from "@prosopo/puzzle-assets";
|
|
1
|
+
import { hslToRgb } from "@prosopo/puzzle-assets/browser";
|
|
2
2
|
const round = (value) => Math.round(value * 100) / 100;
|
|
3
3
|
const rgb = (hue, saturation, lightness) => {
|
|
4
4
|
const { r, g, b } = hslToRgb(hue, saturation, lightness);
|