@slithy/prim-lib 0.7.0 → 0.8.0
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/dist/index.d.ts +18 -0
- package/dist/index.js +53 -12
- package/package.json +15 -14
package/dist/index.d.ts
CHANGED
|
@@ -24,9 +24,12 @@ interface ShapeImageData {
|
|
|
24
24
|
interface ShapeInterface {
|
|
25
25
|
bbox: Bbox;
|
|
26
26
|
tonalRange?: [number, number];
|
|
27
|
+
invertTonal?: boolean;
|
|
27
28
|
saturationRange?: [number, number];
|
|
29
|
+
invertSaturation?: boolean;
|
|
28
30
|
hueCenter?: number;
|
|
29
31
|
hueTolerance?: number;
|
|
32
|
+
invertHue?: boolean;
|
|
30
33
|
/** cfg is rarely used by implementations; accepts Partial to keep call sites flexible. */
|
|
31
34
|
mutate(cfg?: Partial<Cfg>): ShapeInterface;
|
|
32
35
|
toSVG(): SVGElement | undefined;
|
|
@@ -310,9 +313,12 @@ interface NGonOptions {
|
|
|
310
313
|
sizeRange?: [number, number];
|
|
311
314
|
mutationScale?: number;
|
|
312
315
|
tonalRange?: [number, number];
|
|
316
|
+
invertTonal?: boolean;
|
|
313
317
|
saturationRange?: [number, number];
|
|
318
|
+
invertSaturation?: boolean;
|
|
314
319
|
hueCenter?: number;
|
|
315
320
|
hueTolerance?: number;
|
|
321
|
+
invertHue?: boolean;
|
|
316
322
|
}
|
|
317
323
|
declare function makeNGon(opts: NGonOptions): new (w: number, h: number) => ShapeInterface;
|
|
318
324
|
interface RectOptions {
|
|
@@ -322,18 +328,24 @@ interface RectOptions {
|
|
|
322
328
|
rotatable?: boolean;
|
|
323
329
|
mutationScale?: number;
|
|
324
330
|
tonalRange?: [number, number];
|
|
331
|
+
invertTonal?: boolean;
|
|
325
332
|
saturationRange?: [number, number];
|
|
333
|
+
invertSaturation?: boolean;
|
|
326
334
|
hueCenter?: number;
|
|
327
335
|
hueTolerance?: number;
|
|
336
|
+
invertHue?: boolean;
|
|
328
337
|
}
|
|
329
338
|
declare function makeRect(opts?: Partial<RectOptions>): new (w: number, h: number) => ShapeInterface;
|
|
330
339
|
interface CircleOptions {
|
|
331
340
|
sizeRange?: [number, number];
|
|
332
341
|
mutationScale?: number;
|
|
333
342
|
tonalRange?: [number, number];
|
|
343
|
+
invertTonal?: boolean;
|
|
334
344
|
saturationRange?: [number, number];
|
|
345
|
+
invertSaturation?: boolean;
|
|
335
346
|
hueCenter?: number;
|
|
336
347
|
hueTolerance?: number;
|
|
348
|
+
invertHue?: boolean;
|
|
337
349
|
}
|
|
338
350
|
declare function makeCircle(opts?: Partial<CircleOptions>): new (w: number, h: number) => ShapeInterface;
|
|
339
351
|
interface EllipseOptions {
|
|
@@ -342,9 +354,12 @@ interface EllipseOptions {
|
|
|
342
354
|
aspectRatio?: number;
|
|
343
355
|
mutationScale?: number;
|
|
344
356
|
tonalRange?: [number, number];
|
|
357
|
+
invertTonal?: boolean;
|
|
345
358
|
saturationRange?: [number, number];
|
|
359
|
+
invertSaturation?: boolean;
|
|
346
360
|
hueCenter?: number;
|
|
347
361
|
hueTolerance?: number;
|
|
362
|
+
invertHue?: boolean;
|
|
348
363
|
}
|
|
349
364
|
declare function makeEllipse(opts?: Partial<EllipseOptions>): new (w: number, h: number) => ShapeInterface;
|
|
350
365
|
interface GlyphOptions {
|
|
@@ -353,9 +368,12 @@ interface GlyphOptions {
|
|
|
353
368
|
sizeRange?: [number, number];
|
|
354
369
|
mutationScale?: number;
|
|
355
370
|
tonalRange?: [number, number];
|
|
371
|
+
invertTonal?: boolean;
|
|
356
372
|
saturationRange?: [number, number];
|
|
373
|
+
invertSaturation?: boolean;
|
|
357
374
|
hueCenter?: number;
|
|
358
375
|
hueTolerance?: number;
|
|
376
|
+
invertHue?: boolean;
|
|
359
377
|
}
|
|
360
378
|
declare function makeGlyph(opts?: Partial<GlyphOptions>): new (w: number, h: number) => ShapeInterface;
|
|
361
379
|
declare class Debug extends Shape {
|
package/dist/index.js
CHANGED
|
@@ -382,7 +382,7 @@ var Step = class _Step {
|
|
|
382
382
|
compute(state) {
|
|
383
383
|
const pixels = state.canvas.node.width * state.canvas.node.height;
|
|
384
384
|
const offset = this.shape.bbox;
|
|
385
|
-
const { tonalRange, saturationRange, hueCenter, hueTolerance } = this.shape;
|
|
385
|
+
const { tonalRange, invertTonal, saturationRange, invertSaturation, hueCenter, hueTolerance, invertHue } = this.shape;
|
|
386
386
|
if (tonalRange || saturationRange || hueCenter !== void 0 && hueTolerance !== void 0) {
|
|
387
387
|
const { left, top, width, height } = offset;
|
|
388
388
|
const targetData = state.target.getImageData();
|
|
@@ -405,20 +405,25 @@ var Step = class _Step {
|
|
|
405
405
|
if (count > 0) {
|
|
406
406
|
if (tonalRange) {
|
|
407
407
|
const luma = (0.299 * rSum + 0.587 * gSum + 0.114 * bSum) / count;
|
|
408
|
-
|
|
408
|
+
const inRange = luma >= tonalRange[0] && luma <= tonalRange[1];
|
|
409
|
+
if (invertTonal ? inRange : !inRange) {
|
|
409
410
|
this.distance = Infinity;
|
|
410
411
|
return Promise.resolve(this);
|
|
411
412
|
}
|
|
412
413
|
}
|
|
413
414
|
if (saturationRange || hueCenter !== void 0 && hueTolerance !== void 0) {
|
|
414
415
|
const [h, s] = rgbToHsl(rSum / count, gSum / count, bSum / count);
|
|
415
|
-
if (saturationRange
|
|
416
|
-
|
|
417
|
-
|
|
416
|
+
if (saturationRange) {
|
|
417
|
+
const inRange = s >= saturationRange[0] && s <= saturationRange[1];
|
|
418
|
+
if (invertSaturation ? inRange : !inRange) {
|
|
419
|
+
this.distance = Infinity;
|
|
420
|
+
return Promise.resolve(this);
|
|
421
|
+
}
|
|
418
422
|
}
|
|
419
423
|
if (hueCenter !== void 0 && hueTolerance !== void 0) {
|
|
420
424
|
const diff = Math.abs((h - hueCenter + 180 + 360) % 360 - 180);
|
|
421
|
-
|
|
425
|
+
const inRange = diff <= hueTolerance;
|
|
426
|
+
if (invertHue ? inRange : !inRange) {
|
|
422
427
|
this.distance = Infinity;
|
|
423
428
|
return Promise.resolve(this);
|
|
424
429
|
}
|
|
@@ -1026,12 +1031,15 @@ function makeNGon(opts) {
|
|
|
1026
1031
|
static {
|
|
1027
1032
|
__name(this, "NGonRegular");
|
|
1028
1033
|
}
|
|
1029
|
-
static _ngonOpts = { sides, regular: true, rotatable, noise, sizeRange, mutationScale, startAngle, tonalRange: opts.tonalRange, saturationRange: opts.saturationRange, hueCenter: opts.hueCenter, hueTolerance: opts.hueTolerance };
|
|
1034
|
+
static _ngonOpts = { sides, regular: true, rotatable, noise, sizeRange, mutationScale, startAngle, tonalRange: opts.tonalRange, invertTonal: opts.invertTonal, saturationRange: opts.saturationRange, invertSaturation: opts.invertSaturation, hueCenter: opts.hueCenter, hueTolerance: opts.hueTolerance, invertHue: opts.invertHue };
|
|
1030
1035
|
static _shapeSpec = { f: "ngon", o: NGonRegular._ngonOpts };
|
|
1031
1036
|
tonalRange;
|
|
1037
|
+
invertTonal;
|
|
1032
1038
|
saturationRange;
|
|
1039
|
+
invertSaturation;
|
|
1033
1040
|
hueCenter;
|
|
1034
1041
|
hueTolerance;
|
|
1042
|
+
invertHue;
|
|
1035
1043
|
center;
|
|
1036
1044
|
r;
|
|
1037
1045
|
angle;
|
|
@@ -1040,9 +1048,12 @@ function makeNGon(opts) {
|
|
|
1040
1048
|
constructor(w, h) {
|
|
1041
1049
|
super(w, h);
|
|
1042
1050
|
this.tonalRange = opts.tonalRange;
|
|
1051
|
+
this.invertTonal = opts.invertTonal;
|
|
1043
1052
|
this.saturationRange = opts.saturationRange;
|
|
1053
|
+
this.invertSaturation = opts.invertSaturation;
|
|
1044
1054
|
this.hueCenter = opts.hueCenter;
|
|
1045
1055
|
this.hueTolerance = opts.hueTolerance;
|
|
1056
|
+
this.invertHue = opts.invertHue;
|
|
1046
1057
|
this.center = Shape.randomPoint(w, h);
|
|
1047
1058
|
this.r = Math.max(1, sizeRange[0] + ~~(Math.random() * (sizeRange[1] - sizeRange[0])));
|
|
1048
1059
|
this.angle = rotatable ? Math.random() * (2 * Math.PI / sides) : startAngle;
|
|
@@ -1138,19 +1149,25 @@ function makeNGon(opts) {
|
|
|
1138
1149
|
static {
|
|
1139
1150
|
__name(this, "NGonIrregular");
|
|
1140
1151
|
}
|
|
1141
|
-
static _ngonOpts = { sides, regular: false, convex, sizeRange, mutationScale, tonalRange: opts.tonalRange, saturationRange: opts.saturationRange, hueCenter: opts.hueCenter, hueTolerance: opts.hueTolerance };
|
|
1152
|
+
static _ngonOpts = { sides, regular: false, convex, sizeRange, mutationScale, tonalRange: opts.tonalRange, invertTonal: opts.invertTonal, saturationRange: opts.saturationRange, invertSaturation: opts.invertSaturation, hueCenter: opts.hueCenter, hueTolerance: opts.hueTolerance, invertHue: opts.invertHue };
|
|
1142
1153
|
static _shapeSpec = { f: "ngon", o: NGonIrregular._ngonOpts };
|
|
1143
1154
|
tonalRange;
|
|
1155
|
+
invertTonal;
|
|
1144
1156
|
saturationRange;
|
|
1157
|
+
invertSaturation;
|
|
1145
1158
|
hueCenter;
|
|
1146
1159
|
hueTolerance;
|
|
1160
|
+
invertHue;
|
|
1147
1161
|
points;
|
|
1148
1162
|
constructor(w, h) {
|
|
1149
1163
|
super(w, h);
|
|
1150
1164
|
this.tonalRange = opts.tonalRange;
|
|
1165
|
+
this.invertTonal = opts.invertTonal;
|
|
1151
1166
|
this.saturationRange = opts.saturationRange;
|
|
1167
|
+
this.invertSaturation = opts.invertSaturation;
|
|
1152
1168
|
this.hueCenter = opts.hueCenter;
|
|
1153
1169
|
this.hueTolerance = opts.hueTolerance;
|
|
1170
|
+
this.invertHue = opts.invertHue;
|
|
1154
1171
|
const first = Shape.randomPoint(w, h);
|
|
1155
1172
|
this.points = [first];
|
|
1156
1173
|
for (let i = 1; i < sides; i++) {
|
|
@@ -1222,12 +1239,15 @@ function makeRect(opts) {
|
|
|
1222
1239
|
static {
|
|
1223
1240
|
__name(this, "Rect");
|
|
1224
1241
|
}
|
|
1225
|
-
static _rectOpts = { widthRange, heightRange, aspectRatio, rotatable, mutationScale, tonalRange: opts?.tonalRange, saturationRange: opts?.saturationRange, hueCenter: opts?.hueCenter, hueTolerance: opts?.hueTolerance };
|
|
1242
|
+
static _rectOpts = { widthRange, heightRange, aspectRatio, rotatable, mutationScale, tonalRange: opts?.tonalRange, invertTonal: opts?.invertTonal, saturationRange: opts?.saturationRange, invertSaturation: opts?.invertSaturation, hueCenter: opts?.hueCenter, hueTolerance: opts?.hueTolerance, invertHue: opts?.invertHue };
|
|
1226
1243
|
static _shapeSpec = { f: "rect", o: Rect._rectOpts };
|
|
1227
1244
|
tonalRange;
|
|
1245
|
+
invertTonal;
|
|
1228
1246
|
saturationRange;
|
|
1247
|
+
invertSaturation;
|
|
1229
1248
|
hueCenter;
|
|
1230
1249
|
hueTolerance;
|
|
1250
|
+
invertHue;
|
|
1231
1251
|
center;
|
|
1232
1252
|
hw;
|
|
1233
1253
|
hh;
|
|
@@ -1235,9 +1255,12 @@ function makeRect(opts) {
|
|
|
1235
1255
|
constructor(w, h) {
|
|
1236
1256
|
super(w, h);
|
|
1237
1257
|
this.tonalRange = opts?.tonalRange;
|
|
1258
|
+
this.invertTonal = opts?.invertTonal;
|
|
1238
1259
|
this.saturationRange = opts?.saturationRange;
|
|
1260
|
+
this.invertSaturation = opts?.invertSaturation;
|
|
1239
1261
|
this.hueCenter = opts?.hueCenter;
|
|
1240
1262
|
this.hueTolerance = opts?.hueTolerance;
|
|
1263
|
+
this.invertHue = opts?.invertHue;
|
|
1241
1264
|
this.center = Shape.randomPoint(w, h);
|
|
1242
1265
|
this.hw = widthRange[0] + ~~(Math.random() * (widthRange[1] - widthRange[0]));
|
|
1243
1266
|
if (aspectRatio !== void 0) {
|
|
@@ -1350,20 +1373,26 @@ function makeCircle(opts) {
|
|
|
1350
1373
|
static {
|
|
1351
1374
|
__name(this, "MadeCircle");
|
|
1352
1375
|
}
|
|
1353
|
-
static _circleOpts = { sizeRange, mutationScale, tonalRange: opts?.tonalRange, saturationRange: opts?.saturationRange, hueCenter: opts?.hueCenter, hueTolerance: opts?.hueTolerance };
|
|
1376
|
+
static _circleOpts = { sizeRange, mutationScale, tonalRange: opts?.tonalRange, invertTonal: opts?.invertTonal, saturationRange: opts?.saturationRange, invertSaturation: opts?.invertSaturation, hueCenter: opts?.hueCenter, hueTolerance: opts?.hueTolerance, invertHue: opts?.invertHue };
|
|
1354
1377
|
static _shapeSpec = { f: "circle", o: MadeCircle._circleOpts };
|
|
1355
1378
|
tonalRange;
|
|
1379
|
+
invertTonal;
|
|
1356
1380
|
saturationRange;
|
|
1381
|
+
invertSaturation;
|
|
1357
1382
|
hueCenter;
|
|
1358
1383
|
hueTolerance;
|
|
1384
|
+
invertHue;
|
|
1359
1385
|
center;
|
|
1360
1386
|
r;
|
|
1361
1387
|
constructor(w, h) {
|
|
1362
1388
|
super(w, h);
|
|
1363
1389
|
this.tonalRange = opts?.tonalRange;
|
|
1390
|
+
this.invertTonal = opts?.invertTonal;
|
|
1364
1391
|
this.saturationRange = opts?.saturationRange;
|
|
1392
|
+
this.invertSaturation = opts?.invertSaturation;
|
|
1365
1393
|
this.hueCenter = opts?.hueCenter;
|
|
1366
1394
|
this.hueTolerance = opts?.hueTolerance;
|
|
1395
|
+
this.invertHue = opts?.invertHue;
|
|
1367
1396
|
this.center = Shape.randomPoint(w, h);
|
|
1368
1397
|
this.r = Math.max(1, sizeRange[0] + ~~(Math.random() * (sizeRange[1] - sizeRange[0])));
|
|
1369
1398
|
this.computeBbox();
|
|
@@ -1424,21 +1453,27 @@ function makeEllipse(opts) {
|
|
|
1424
1453
|
static {
|
|
1425
1454
|
__name(this, "MadeEllipse");
|
|
1426
1455
|
}
|
|
1427
|
-
static _ellipseOpts = { rxRange, ryRange, aspectRatio, mutationScale, tonalRange: opts?.tonalRange, saturationRange: opts?.saturationRange, hueCenter: opts?.hueCenter, hueTolerance: opts?.hueTolerance };
|
|
1456
|
+
static _ellipseOpts = { rxRange, ryRange, aspectRatio, mutationScale, tonalRange: opts?.tonalRange, invertTonal: opts?.invertTonal, saturationRange: opts?.saturationRange, invertSaturation: opts?.invertSaturation, hueCenter: opts?.hueCenter, hueTolerance: opts?.hueTolerance, invertHue: opts?.invertHue };
|
|
1428
1457
|
static _shapeSpec = { f: "ellipse", o: MadeEllipse._ellipseOpts };
|
|
1429
1458
|
tonalRange;
|
|
1459
|
+
invertTonal;
|
|
1430
1460
|
saturationRange;
|
|
1461
|
+
invertSaturation;
|
|
1431
1462
|
hueCenter;
|
|
1432
1463
|
hueTolerance;
|
|
1464
|
+
invertHue;
|
|
1433
1465
|
center;
|
|
1434
1466
|
rx;
|
|
1435
1467
|
ry;
|
|
1436
1468
|
constructor(w, h) {
|
|
1437
1469
|
super(w, h);
|
|
1438
1470
|
this.tonalRange = opts?.tonalRange;
|
|
1471
|
+
this.invertTonal = opts?.invertTonal;
|
|
1439
1472
|
this.saturationRange = opts?.saturationRange;
|
|
1473
|
+
this.invertSaturation = opts?.invertSaturation;
|
|
1440
1474
|
this.hueCenter = opts?.hueCenter;
|
|
1441
1475
|
this.hueTolerance = opts?.hueTolerance;
|
|
1476
|
+
this.invertHue = opts?.invertHue;
|
|
1442
1477
|
this.center = Shape.randomPoint(w, h);
|
|
1443
1478
|
this.rx = Math.max(1, rxRange[0] + ~~(Math.random() * (rxRange[1] - rxRange[0])));
|
|
1444
1479
|
this.ry = aspectRatio !== void 0 ? Math.max(1, Math.round(this.rx / aspectRatio)) : Math.max(1, ryRange[0] + ~~(Math.random() * (ryRange[1] - ryRange[0])));
|
|
@@ -1510,20 +1545,26 @@ function makeGlyph(opts) {
|
|
|
1510
1545
|
static {
|
|
1511
1546
|
__name(this, "MadeGlyph");
|
|
1512
1547
|
}
|
|
1513
|
-
static _glyphOpts = { char, fontFamily, sizeRange, mutationScale, tonalRange: opts?.tonalRange, saturationRange: opts?.saturationRange, hueCenter: opts?.hueCenter, hueTolerance: opts?.hueTolerance };
|
|
1548
|
+
static _glyphOpts = { char, fontFamily, sizeRange, mutationScale, tonalRange: opts?.tonalRange, invertTonal: opts?.invertTonal, saturationRange: opts?.saturationRange, invertSaturation: opts?.invertSaturation, hueCenter: opts?.hueCenter, hueTolerance: opts?.hueTolerance, invertHue: opts?.invertHue };
|
|
1514
1549
|
static _shapeSpec = { f: "glyph", o: MadeGlyph._glyphOpts };
|
|
1515
1550
|
tonalRange;
|
|
1551
|
+
invertTonal;
|
|
1516
1552
|
saturationRange;
|
|
1553
|
+
invertSaturation;
|
|
1517
1554
|
hueCenter;
|
|
1518
1555
|
hueTolerance;
|
|
1556
|
+
invertHue;
|
|
1519
1557
|
center;
|
|
1520
1558
|
fontSize;
|
|
1521
1559
|
constructor(w, h) {
|
|
1522
1560
|
super(w, h);
|
|
1523
1561
|
this.tonalRange = opts?.tonalRange;
|
|
1562
|
+
this.invertTonal = opts?.invertTonal;
|
|
1524
1563
|
this.saturationRange = opts?.saturationRange;
|
|
1564
|
+
this.invertSaturation = opts?.invertSaturation;
|
|
1525
1565
|
this.hueCenter = opts?.hueCenter;
|
|
1526
1566
|
this.hueTolerance = opts?.hueTolerance;
|
|
1567
|
+
this.invertHue = opts?.invertHue;
|
|
1527
1568
|
this.center = Shape.randomPoint(w, h);
|
|
1528
1569
|
this.fontSize = Math.max(sizeRange[0], sizeRange[0] + ~~(Math.random() * (sizeRange[1] - sizeRange[0])));
|
|
1529
1570
|
this.computeBbox();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@slithy/prim-lib",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Core engine for primitive-based image reconstruction.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -13,14 +13,24 @@
|
|
|
13
13
|
"dist"
|
|
14
14
|
],
|
|
15
15
|
"sideEffects": false,
|
|
16
|
+
"scripts": {
|
|
17
|
+
"clean": "rm -rf dist",
|
|
18
|
+
"prepack": "rm -rf dist && tsup src/index.ts --format esm --dts --keep-names",
|
|
19
|
+
"build": "rm -rf dist && tsup src/index.ts --format esm --dts --keep-names",
|
|
20
|
+
"dev": "tsup src/index.ts --format esm --watch --keep-names",
|
|
21
|
+
"typecheck": "tsc --noEmit",
|
|
22
|
+
"lint": "eslint .",
|
|
23
|
+
"test": "vitest run",
|
|
24
|
+
"test:watch": "vitest"
|
|
25
|
+
},
|
|
16
26
|
"devDependencies": {
|
|
27
|
+
"@slithy/eslint-config": "workspace:*",
|
|
28
|
+
"@slithy/tsconfig": "workspace:*",
|
|
17
29
|
"@vitest/coverage-v8": "^4.1.2",
|
|
18
30
|
"jsdom": "^29.0.1",
|
|
19
31
|
"tsup": "^8",
|
|
20
32
|
"typescript": "^5",
|
|
21
|
-
"vitest": "^4.1.2"
|
|
22
|
-
"@slithy/eslint-config": "0.0.0",
|
|
23
|
-
"@slithy/tsconfig": "0.0.0"
|
|
33
|
+
"vitest": "^4.1.2"
|
|
24
34
|
},
|
|
25
35
|
"author": {
|
|
26
36
|
"name": "Matthew Campagna",
|
|
@@ -41,14 +51,5 @@
|
|
|
41
51
|
},
|
|
42
52
|
"publishConfig": {
|
|
43
53
|
"access": "public"
|
|
44
|
-
},
|
|
45
|
-
"scripts": {
|
|
46
|
-
"clean": "rm -rf dist",
|
|
47
|
-
"build": "rm -rf dist && tsup src/index.ts --format esm --dts --keep-names",
|
|
48
|
-
"dev": "tsup src/index.ts --format esm --watch --keep-names",
|
|
49
|
-
"typecheck": "tsc --noEmit",
|
|
50
|
-
"lint": "eslint .",
|
|
51
|
-
"test": "vitest run",
|
|
52
|
-
"test:watch": "vitest"
|
|
53
54
|
}
|
|
54
|
-
}
|
|
55
|
+
}
|