@logomarks/core 0.1.2 → 0.1.4

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 CHANGED
@@ -5,6 +5,18 @@ All notable changes to `@logomarks/core` are documented here.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.1.4] — 2026-11-06
9
+
10
+ ### Fixed
11
+
12
+ - The generated `fit.mjs` fits several files each in place. Given exactly two files it used to take the second as the output and write the first one's fit into it, so the second mark was lost. A file's fit now goes to another file only with `-o out.svg`, or when the second path doesn't exist yet (`in.svg out.svg`, as before). `--help` prints the usage (it used to crash), and an unknown option, a missing path or `-o` with several inputs exits 2 with the reason.
13
+
14
+ ## [0.1.3] — 2026-11-06
15
+
16
+ ### Fixed
17
+
18
+ - `letterSignatures()` counts a pixel as ink only above half coverage (8-bit alpha 128 and up, as `holecheck.mjs` did): with Float32 coverage, an alpha of 127 rounded past `127 / 255` and counted, which moved letter scores by about a hundredth and could reorder near matches.
19
+
8
20
  ## [0.1.2] — 2026-11-06
9
21
 
10
22
  ### Changed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@logomarks/core",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "Geometry, SVG reading, fitting, analysis and similarity for logomarks on a 512 grid: the kit the Logomarks set is drawn with (shapes, real booleans, strokes, tracks, iso solids, badges, letter skeletons), one SVG path parser, the 448 fit, speck and shape-tag analysis, outline signatures, and the industry-symbol parts.",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -96,7 +96,8 @@ function cropped(a, R, N) {
96
96
 
97
97
  /**
98
98
  * A mark's letter signatures from its coverage at LETTER.render: its holes (null when it has none) and its ink, each
99
- * cropped to its box at LETTER.size.
99
+ * cropped to its box at LETTER.size. A pixel is ink when it is more than half covered (8-bit alpha 128 and up, as
100
+ * holecheck read it), whether the coverage is a Float32Array or a Float64Array.
100
101
  *
101
102
  * @param {Float32Array} alpha Coverage 0–1, `render` × `render`.
102
103
  * @param {number} [R] Its side (128).
@@ -105,7 +106,8 @@ function cropped(a, R, N) {
105
106
  */
106
107
  export function letterSignatures(alpha, R = LETTER.render, N = LETTER.size) {
107
108
  const ink = new Uint8Array(R * R);
108
- for (let i = 0; i < ink.length; i++) ink[i] = alpha[i] > 127 / 255 ? 1 : 0;
109
+ // > 0.5, not > 127 / 255: an alpha of 127 stored as Float32 rounds up past the double 127 / 255 and would count as ink
110
+ for (let i = 0; i < ink.length; i++) ink[i] = alpha[i] > 0.5 ? 1 : 0;
109
111
  const holes = cropped(holesOf(ink, R), R, N);
110
112
  return { holes: holes.some((v) => v > 0) ? holes : null, ink: cropped(ink, R, N) };
111
113
  }
@@ -41,8 +41,8 @@ const FIT_HEADER = `#!/usr/bin/env node
41
41
  // {{url}} · CC0 · no dependencies
42
42
  //
43
43
  // node fit.mjs mark.svg fit in place
44
- // node fit.mjs in.svg out.svg fit to a new file
45
- // node fit.mjs marks/ fit every .svg in a folder, in place
44
+ // node fit.mjs in.svg -o out.svg fit to another file (in.svg out.svg too, while out.svg doesn't exist)
45
+ // node fit.mjs a.svg b.svg marks/ fit each file, and every .svg in a folder, in place
46
46
  // node fit.mjs --check mark.svg marks/ only report; exits 1 if anything is off
47
47
  //
48
48
  // Reads <path d> (with fill-rule), <circle>, <ellipse>, <rect> and <polygon>; nested
@@ -58,16 +58,33 @@ import path from 'node:path';
58
58
  const FIT_MAIN = `
59
59
  // ---------- command line ----------
60
60
 
61
+ const USAGE = \`Usage: node fit.mjs [--check] <file.svg | folder>... [-o out.svg]
62
+ Fits each file in place (a folder: every .svg in it). -o writes one file's fit to another file;
63
+ so does a second path that doesn't exist yet (in.svg out.svg). --check only reports.\`;
64
+
65
+ /** Stops with a message and the usage. */
66
+ const fail = (msg) => { console.error(\`fit.mjs: \${msg}\\n\${USAGE}\`); process.exit(2); };
67
+
61
68
  const args = process.argv.slice(2);
62
- const checking = args[0] === '--check';
63
- if (checking) args.shift();
64
- if (!args.length) {
65
- console.log('Usage: node fit.mjs [--check] <file.svg | folder> [out.svg]');
66
- process.exit(1);
69
+ if (args.some((a) => a === '--help' || a === '-h')) { console.log(USAGE); process.exit(0); }
70
+ const checking = args.includes('--check');
71
+ let out = null;
72
+ const paths = [];
73
+ for (let i = 0; i < args.length; i++) {
74
+ if (args[i] === '--check') continue;
75
+ if (args[i] === '-o' || args[i] === '--out') { out = args[++i] ?? fail(\`\${args[i - 1]} needs a file\`); continue; }
76
+ if (args[i].startsWith('-')) fail(\`unknown option \${args[i]}\`);
77
+ paths.push(args[i]);
78
+ }
79
+ if (!paths.length) fail('no file or folder given');
80
+ for (const p of paths) if (!fs.existsSync(p)) {
81
+ // in.svg out.svg: the second path names the file to write, as -o does
82
+ if (!checking && !out && paths.length === 2 && p === paths[1] && p.endsWith('.svg')) out = paths.pop();
83
+ else fail(\`\${p} doesn't exist\`);
67
84
  }
85
+ if (out && (checking || paths.length !== 1 || fs.statSync(paths[0]).isDirectory())) fail('-o takes one .svg file to fit, without --check');
68
86
  const files = [];
69
- const out = !checking && args.length === 2 && !fs.statSync(args[0]).isDirectory() && args[1].endsWith('.svg') ? args.pop() : null;
70
- for (const a of args) {
87
+ for (const a of paths) {
71
88
  if (fs.statSync(a).isDirectory()) for (const f of fs.readdirSync(a)) { if (f.endsWith('.svg')) files.push(path.join(a, f)); }
72
89
  else files.push(a);
73
90
  }