lettras 0.0.0-stage → 0.2.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/LICENSE ADDED
@@ -0,0 +1,25 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Artificialss
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this
6
+ software and associated documentation files (the "Software"), to deal in the Software
7
+ without restriction, including without limitation the rights to use, copy, modify, merge,
8
+ publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
9
+ to whom the Software is furnished to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all copies or
12
+ substantial portions of the Software.
13
+
14
+ EXCEPTION: This license does NOT cover the compiled Lettras engine in `npm/engine/`.
15
+ That directory is proprietary and is governed solely by `engine/LICENSE`.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
18
+ INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
19
+ PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
20
+ FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
21
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22
+ DEALINGS IN THE SOFTWARE.
23
+
24
+ ----------------------------------------------------------------------------------------
25
+ The compiled engine in `engine/` is NOT MIT. See `engine/LICENSE`.
package/README.md CHANGED
@@ -1,3 +1,58 @@
1
- # Temporary Holding Version
1
+ # lettras
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Word-search generator for **Spanish, English, Portuguese, French, German and Italian**, with native accented letters
4
+ kept as one cell each. Runs locally (WebAssembly): no network, no API key. Library and CLI.
5
+
6
+ ```bash
7
+ npm install lettras
8
+ ```
9
+
10
+ ```js
11
+ import { generate, render } from 'lettras';
12
+
13
+ const puzzle = generate({ words: ['gato', 'perro', 'piña'], rows: 9, cols: 12, position: 'mixed', seed: 8 });
14
+ console.log(render(puzzle));
15
+ puzzle.grid; // string[][], one letter per cell, '-' for empty cells
16
+ puzzle.placements; // where each word is hidden: start (r, c), step (dr, dc), length
17
+ puzzle.unplaced; // words that did not fit
18
+ ```
19
+
20
+ ```js
21
+ import { generate, fill, render } from 'lettras';
22
+
23
+ const puzzle = generate({ words: ['gato', 'perro', 'piña'], rows: 9, cols: 12, position: 'mixed', seed: 8 });
24
+ const done = fill(puzzle, { lang: 'es', accents: true }); // random letters in the empty cells
25
+ console.log(done.grid.map((row) => row.join(' ')).join('\n'));
26
+ ```
27
+
28
+ ```bash
29
+ npx lettras --words gato,perro,piña --rows 9 --cols 12 --position mixed --random --accents on
30
+ ```
31
+
32
+ ## Options
33
+
34
+ | Option | Values |
35
+ | --- | --- |
36
+ | `words`, `rows`, `cols` | Word list and grid size (rectangular grids are fine). |
37
+ | `position` | `horizontal`, `vertical` or `mixed` (all 8 directions). |
38
+ | `difficulty` | 1–4, used when `position` is not set. |
39
+ | `clustering` | 0 words apart · 1 words crossing · default 0.5. |
40
+ | `seed` | Same input and seed give the same grid. |
41
+ | `lang` | `es` (default) `en` `pt` `fr` `de` `it`. |
42
+ | `classicMode` | Strip accents in the grid. |
43
+ | `fill` | Empty-cell character, default `-`. |
44
+
45
+ `generate` leaves empty cells as `-`. **`fill(puzzleOrGrid, { lang, accents, seed })`** completes them: letters follow the
46
+ language's letter frequency, `accents: false` limits them to A-Z, and without a `seed` every call is different. Passing the
47
+ puzzle (instead of a bare matrix) also protects its words from accidental extra copies. CLI: `--random` and `--accents on|off`.
48
+
49
+ CLI flags mirror these: `--words a,b,c --rows N --cols N --position P --difficulty N --clustering N --seed N --lang xx
50
+ --classic --fill C`, plus `--json`, `--solution` and `--stdin`.
51
+
52
+ `generate` throws on invalid input (for example zero rows). Words that cannot be placed are listed in `unplaced`;
53
+ words that are refused (spaces, digits, duplicates) are listed in `rejected` with a reason.
54
+
55
+ ## License
56
+
57
+ Wrapper, CLI and types: MIT. The compiled engine in `engine/` is proprietary: use it unmodified through this package;
58
+ see `engine/LICENSE`. Source and issues: <https://github.com/Artificialss/lettras-sdk>.
package/bin/lettras.js ADDED
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env node
2
+ // lettras --words sol,luna,mar --rows 8 --cols 8 [--position horizontal|vertical|mixed] [--seed 7]
3
+ // [--difficulty 1-4] [--clustering 0-1] [--lang es] [--classic] [--fill -] [--random] [--accents on|off]
4
+ // [--json] [--solution]
5
+ // or: echo '{"words":["sol"],"rows":6,"cols":6}' | lettras --stdin
6
+ import { readFileSync } from 'node:fs';
7
+ import { generate, renderPuzzle } from '../engine/index.js';
8
+ import { fill } from '../src/index.js';
9
+
10
+ const HELP = `lettras: word-search generator
11
+
12
+ lettras --words sol,luna,mar --rows 8 --cols 8 [options]
13
+
14
+ --words a,b,c word bank (comma separated)
15
+ --rows N --cols N grid size (rectangular allowed)
16
+ --position P horizontal | vertical | mixed (mixed = all 8 directions)
17
+ --difficulty 1-4 directions when --position is not set
18
+ --clustering 0-1 0 = words apart, 1 = words crossing (default 0.5)
19
+ --seed N same seed, same grid
20
+ --lang xx es en pt fr de it
21
+ --classic strip accents in the grid
22
+ --fill C empty-cell character (default -)
23
+ --random fill the empty cells with random letters
24
+ --accents on|off with --random: use the language's accented letters (default on; off with --classic)
25
+ --json print the JSON result
26
+ --solution show only the hidden words
27
+ --stdin read the JSON input from stdin`;
28
+
29
+ function parse(argv) {
30
+ const flags = new Set(['classic', 'json', 'solution', 'stdin', 'help', 'random']);
31
+ const opts = {};
32
+ for (let i = 0; i < argv.length; i++) {
33
+ const a = argv[i];
34
+ if (!a.startsWith('--')) throw new Error(`unexpected argument: ${a}`);
35
+ const key = a.slice(2);
36
+ if (flags.has(key)) opts[key] = true;
37
+ else if (i + 1 < argv.length) opts[key] = argv[++i];
38
+ else throw new Error(`missing value for --${key}`);
39
+ }
40
+ return opts;
41
+ }
42
+
43
+ function main() {
44
+ const o = parse(process.argv.slice(2));
45
+ if (o.help) return console.log(HELP);
46
+ let input;
47
+ if (o.stdin) {
48
+ input = JSON.parse(readFileSync(0, 'utf8'));
49
+ } else {
50
+ if (!o.words || !o.rows) { console.log(HELP); process.exit(o.words || o.rows ? 2 : 0); }
51
+ input = {
52
+ words: o.words.split(',').map((w) => w.trim()).filter(Boolean),
53
+ rows: Number(o.rows),
54
+ cols: Number(o.cols ?? o.rows),
55
+ };
56
+ if (o.position) input.position = o.position;
57
+ if (o.difficulty) input.difficulty = Number(o.difficulty);
58
+ if (o.clustering) input.clustering = Number(o.clustering);
59
+ if (o.seed) input.seed = Number(o.seed);
60
+ if (o.lang) input.lang = o.lang;
61
+ if (o.classic) input.classicMode = true;
62
+ if (o.fill) input.fill = o.fill;
63
+ }
64
+ let outJson = generate(JSON.stringify(input));
65
+ let out = JSON.parse(outJson);
66
+ if (o.random) {
67
+ if (o.accents !== undefined && !['on', 'off'].includes(o.accents)) throw new Error('--accents must be on or off');
68
+ const accents = o.accents ? o.accents === 'on' : !input.classicMode;
69
+ const filled = fill(out, { lang: input.lang, accents, seed: input.seed });
70
+ out = { ...out, grid: filled.grid };
71
+ outJson = JSON.stringify(out);
72
+ }
73
+ if (o.json) return console.log(outJson);
74
+ if (o.solution) {
75
+ const hidden = new Set(out.placements.flatMap((p) => Array.from({ length: p.length }, (_, i) => `${p.r + p.dr * i},${p.c + p.dc * i}`)));
76
+ return console.log(out.grid.map((row, r) => row.map((ch, c) => (hidden.has(`${r},${c}`) ? ch : '·')).join(' ')).join('\n'));
77
+ }
78
+ console.log(renderPuzzle(outJson));
79
+ }
80
+
81
+ try { main(); } catch (e) { console.error(`lettras: ${e.message ?? e}`); process.exit(1); }
package/engine/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Lettras compiled engine: proprietary license
2
+
3
+ Copyright (c) 2026 Artificialss. All rights reserved.
4
+
5
+ This directory contains the compiled Lettras word-search engine (WebAssembly and the
6
+ generated loader code). It is NOT covered by the MIT license that applies to the rest of
7
+ this repository.
8
+
9
+ You may use this engine, unmodified and only as distributed in the `lettras` npm package
10
+ or this repository, to generate puzzles in your own applications, including commercial
11
+ ones, free of charge.
12
+
13
+ You may not, without written permission from Artificialss:
14
+ - copy, extract or redistribute the engine separately from the `lettras` package;
15
+ - modify it, or create derivative works of it;
16
+ - decompile, disassemble or otherwise attempt to derive its source code or algorithm;
17
+ - use it to build a competing puzzle-generation service or library.
18
+
19
+ THE ENGINE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND.
@@ -0,0 +1 @@
1
+ export * from './lettras_engine.js';