@twardoch/namzy 1.0.19 → 1.0.21

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/src/mangle.ts CHANGED
@@ -1,92 +1,51 @@
1
1
  // this_file: src/mangle.ts
2
2
 
3
- /** Simple seeded mulberry32 RNG returns a function that yields [0,1) floats */
3
+ import { ROTATIONS, STEMS } from "./wordlist.js";
4
+
5
+ /** Seeded mulberry32 RNG — yields [0,1) floats. */
4
6
  export function mulberry32(seed: number): () => number {
5
7
  let s = seed >>> 0;
6
8
  return () => {
7
- s += 0x6d2b79f5;
9
+ s = (s + 0x6d2b79f5) >>> 0;
8
10
  let t = Math.imul(s ^ (s >>> 15), 1 | s);
9
11
  t ^= t + Math.imul(t ^ (t >>> 7), 61 | t);
10
12
  return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
11
13
  };
12
14
  }
13
15
 
14
- type RotationRule = readonly [from: string, to: string];
15
-
16
- export const ROTATION_RULES: readonly RotationRule[] = [
17
- ["c", "q"],
18
- ["f", "v"],
19
- ["k", "c"],
20
- ["q", "k"],
21
- ["s", "z"],
22
- ["z", "s"],
23
- ["v", "f"],
24
- ["w", "u"],
25
- ["b", "p"],
26
- ["p", "b"],
27
- ];
28
-
29
- const ALL_ROTATIONS = (1 << ROTATION_RULES.length) - 1;
30
-
31
- function rotationFor(lower: string, activeMask: number): string | undefined {
32
- for (let i = 0; i < ROTATION_RULES.length; i++) {
33
- if ((activeMask & (1 << i)) === 0) {
34
- continue;
35
- }
36
- const [from, to] = ROTATION_RULES[i];
37
- if (lower === from) {
38
- return to;
39
- }
40
- }
41
- return undefined;
16
+ function pick<T>(arr: readonly T[], rng: () => number): T {
17
+ return arr[Math.floor(rng() * arr.length)];
42
18
  }
43
19
 
44
- /** Choose 1..10 active consonant-rotation rules from the seeded RNG. */
45
- export function activeRotationMask(rng: () => number): number {
46
- const order = ROTATION_RULES.map((_, i) => i);
47
- const activeCount = 1 + Math.floor(rng() * ROTATION_RULES.length);
48
- for (let i = 0; i < activeCount; i++) {
49
- const swap = i + Math.floor(rng() * (order.length - i));
50
- [order[i], order[swap]] = [order[swap], order[i]];
51
- }
52
- return order.slice(0, activeCount).reduce((mask, i) => mask | (1 << i), 0);
20
+ const ROT_MAP = new Map<string, string>(ROTATIONS as readonly (readonly [string, string])[]);
21
+
22
+ function rotateAt(s: string, pos: number): string {
23
+ const ch = s[pos];
24
+ const lower = ch.toLowerCase();
25
+ const repl = ROT_MAP.get(lower);
26
+ if (repl === undefined) return s;
27
+ const out = ch === lower ? repl : repl.toUpperCase();
28
+ return s.slice(0, pos) + out + s.slice(pos + 1);
53
29
  }
54
30
 
55
- /** Consonant rotation. Case-preserving. Defaults to all rules for direct helper use. */
56
- export function mangle(s: string, activeMask = ALL_ROTATIONS): string {
57
- let out = "";
58
- for (const ch of s) {
59
- const lower = ch.toLowerCase();
60
- const repl = rotationFor(lower, activeMask);
61
- if (repl === undefined) {
62
- out += ch;
63
- } else {
64
- out += ch === lower ? repl : repl.toUpperCase();
65
- }
31
+ /** Apply 1 or 2 rotations on randomly selected positions of the compound. */
32
+ export function applyRotations(compound: string, rng: () => number): string {
33
+ if (compound.length === 0) return compound;
34
+ const passes = rng() < 0.5 ? 1 : 2;
35
+ let out = compound;
36
+ for (let i = 0; i < passes; i++) {
37
+ out = rotateAt(out, Math.floor(rng() * out.length));
66
38
  }
67
39
  return out;
68
40
  }
69
41
 
70
- const VOWELS = new Set(["a", "e", "i", "o", "u", "y"]);
42
+ function capitalize(s: string): string {
43
+ return s.length === 0 ? s : s[0].toUpperCase() + s.slice(1);
44
+ }
71
45
 
72
- /**
73
- * Fuse two lowercase words at a clean junction.
74
- * Drops the first char of `b` while it duplicates the tail of `a`,
75
- * or while the seam is vowel-vowel. Max two trims.
76
- */
77
- export function joinClean(a: string, b: string): string {
78
- const head = a;
79
- let tail = b;
80
- for (let i = 0; i < 2 && head.length > 0 && tail.length > 0; i++) {
81
- const last = head[head.length - 1].toLowerCase();
82
- const first = tail[0].toLowerCase();
83
- if (last === first) {
84
- tail = tail.slice(1);
85
- } else if (VOWELS.has(last) && VOWELS.has(first)) {
86
- tail = tail.slice(1);
87
- } else {
88
- break;
89
- }
90
- }
91
- return head + tail;
46
+ /** Build one name: any two stems, concatenated, lightly rotated, capitalized. */
47
+ export function buildName(rng: () => number): string {
48
+ const a = pick(STEMS, rng);
49
+ const b = pick(STEMS, rng);
50
+ return capitalize(applyRotations(a + b, rng));
92
51
  }
package/src/web.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  // this_file: src/web.ts
2
2
  // Browser entry point — exposes namzy.generate() on window.namzy.
3
3
 
4
- export { generate, mangle, joinClean, mulberry32, GEO, COMMON } from "./index.js";
4
+ export { generate, generateMany, applyRotations, buildName, mulberry32, STEMS, ROTATIONS } from "./index.js";
5
5
  export type { NamzyOptions } from "./index.js";
package/src/wordlist.ts CHANGED
@@ -1,175 +1,204 @@
1
- // Geographic names (A-Za-z only, no diacritics). Shared across all implementations.
2
- export const GEO: string[] = [
3
- "tokyo", "paris", "oslo", "berlin", "lagos", "lima",
4
- "boston", "vienna", "cairo", "kyoto", "dubai", "seoul",
5
- "milan", "tunis", "perth", "genoa", "porto", "bruges",
6
- "ghent", "brest", "ashford", "sofia", "riga", "lyon",
7
- "basel", "natal", "recife", "darwin", "hobart", "ashbury",
8
- "varna", "split", "kotor", "tirana", "skopje", "bitola",
9
- "plovdiv", "gabrovo", "ruse", "delhi", "rome", "athens",
10
- "nairobi", "bali", "havana", "lisbon", "bogota", "dakar",
11
- "quito", "vilnius", "vaduz", "bern", "accra", "kigali",
12
- "abuja", "bamako", "niamey", "lome", "prague", "dublin",
13
- "naples", "tulum", "tbilisi", "yerevan", "astana", "lusaka",
14
- "harare", "asmara", "manaus", "cuenca", "merida", "geneva",
15
- "zurich", "venice", "sydney", "denver", "austin", "phoenix",
16
- "tucson", "reno", "boise", "fargo", "tulsa", "tampa",
17
- "miami", "salem", "dover", "trenton", "helena", "juneau",
18
- "topeka", "albany", "amsterdam", "antwerp", "arusha", "aspen",
19
- "atlanta", "auckland", "baku", "bangkok", "barcelona", "ashgrove",
20
- "ashfield", "bergen", "bilbao", "bordeaux", "braga", "brisbane",
21
- "bristol", "brussels", "bucharest", "budapest", "calgary", "canberra",
22
- "cardiff", "casablanca", "chicago", "cologne", "colombo", "copenhagen",
23
- "cork", "dresden", "durban", "edinburgh", "florence", "frankfurt",
24
- "gdansk", "glasgow", "granada", "guangzhou", "hamburg", "hanoi",
25
- "helsinki", "houston", "jakarta", "krakow", "leipzig", "lille",
26
- "london", "luanda", "lucerne", "madrid", "malaga", "manila",
27
- "marrakesh", "marseille", "melbourne", "memphis", "montreal", "munich",
28
- "nagoya", "nantes", "napier", "nashville", "orlando", "osaka",
29
- "ottawa", "palermo", "panama", "phuket", "pisa", "poznan",
30
- "quebec", "reykjavik", "rotterdam", "sapporo", "sevilla", "shanghai",
31
- "stockholm", "suzhou", "swansea", "bayfield", "tallinn", "tangier",
32
- "thimphu", "toronto", "toulouse", "trieste", "valencia", "vancouver",
33
- "verona", "warsaw", "winnipeg", "wroclaw", "zagreb", "aarhus",
34
- "abidjan", "adelaide", "alger", "annaba", "ankara", "antalya",
35
- "arezzo", "asuncion", "avignon", "baltimore", "banjul", "belem",
36
- "bologna", "bremen", "cancun", "caracas", "cartagena", "catania",
37
- "charlotte", "chennai", "chiangmai", "cleveland", "cordoba", "curitiba",
38
- "cusco", "dallas", "dundee", "espoo", "fez", "freetown",
39
- "fukuoka", "funchal", "gothenburg", "guayaquil", "bayport", "halifax",
40
- "hamilton", "honolulu", "ibadan", "innsbruck", "izmir", "jaipur",
41
- "kampala", "kansas", "kathmandu", "kingston", "kinshasa", "koblenz",
42
- "kortrijk", "lahti", "lausanne", "leeds", "leuven", "liege",
43
- "liverpool", "ljubljana", "lodz", "luxor", "bayview", "madison",
44
- "malmo", "manchester", "mandalay", "maputo", "mendoza", "monterrey",
45
- "montevideo", "noumea", "nuremberg", "okinawa", "omaha", "padua",
46
- "penang", "portland", "pretoria", "rabat", "raleigh", "rennes",
47
- "richmond", "salzburg", "samarkand", "santander", "santiago", "sendai",
48
- "singapore", "skagen", "stavanger", "stuttgart", "surabaya", "suva",
49
- "tampere", "taranto", "tarragona", "tiruchirappalli", "trondheim", "utrecht",
50
- "valletta", "victoria", "vigo", "bergenfield", "bellevue", "bloomington",
51
- "boulder", "bozeman", "bradford", "brighton", "brookline", "cambridge",
52
- "carmel", "carson", "cedarpark", "chandler", "chico", "claremont",
53
- "clearwater", "concord", "corvallis", "dayton", "decatur", "denton",
54
- "duluth", "durham", "eugene", "everett", "fairbanks", "fairfield",
55
- "flagstaff", "fremont", "fresno", "frisco", "gainesville", "garland",
56
- "gilbert", "grandrapids", "greensboro", "greenville", "hartford", "hayward",
57
- "henderson", "holland", "irvine", "ithaca", "lancaster", "lansing",
58
- "lincoln", "lowell", "madisonville", "marion", "mesa", "miamibeach",
59
- "midland", "milford", "mobile", "modesto", "monterey", "moreno",
60
- "naperville", "newark", "newhaven", "newport", "norfolk", "norman",
61
- "oakland", "oceanside", "olympia", "orleans", "pasadena", "peoria",
62
- "plano", "pocatello", "pueblo", "redmond", "riverside", "rochester",
63
- "rockford", "roseville", "sacramento", "savannah", "scottsdale", "somerville",
64
- "spokane", "springfield", "stockton", "tacoma", "tempe", "torrance",
65
- "tuscaloosa", "waco", "waterloo", "westport", "wichita", "wilmington",
66
- "worcester", "yonkers", "york", "abilene", "akron", "annapolis",
67
- "appleton", "arlington", "ashland", "atherton", "auburn", "bakersfield",
68
- "bayonne", "benicia", "berkeley", "billings", "bloomfield", "bluffton",
69
- "boca", "bradenton", "brentwood", "burlington", "camden", "canton",
70
- "carlisle", "cheyenne", "chicopee", "clifton", "columbia", "columbus",
71
- "conway", "cranston", "davis", "daytona", "deland", "dentonville",
72
- "desmoines", "elgin", "elizabeth", "elkhart", "elmira", "erie",
73
- "eureka", "evansville", "everglades", "fallsburg", "fayetteville", "flint",
74
- "florissant", "fortwayne", "frederick", "fredericksburg", "gastonia", "georgetown",
75
- "glendale", "grandforks", "greenbay", "haverhill", "highpoint", "hollywood",
76
- "huntington", "huntsville", "independence", "jackson", "jacksonville", "joliet",
77
- "kenosha", "kettering", "knoxville", "laredo", "lawrence", "lexington",
78
- "livermore", "longmont", "lubbock", "macon", "malibu", "medford",
79
- "merced", "mesquite", "missoula", "moline", "murfreesboro", "napa",
80
- "newton", "niagara", "norwalk", "ocala", "ogden", "ontario",
81
- "orange", "oshkosh", "owensboro", "palmcoast", "pensacola", "pomona",
82
- "providence", "provo", "quincy", "racine", "redding", "renton",
83
- "roanoke", "rockville", "roswell", "roundrock", "salinas", "sanjose",
84
- "sanmateo", "santaana", "santafe", "santarosa", "sarasota", "schaumburg",
85
- "shreveport", "siouxcity", "southbend", "stcloud", "stillwater", "sunnyvale",
86
- "syracuse", "baywood",
1
+ // this_file: src/wordlist.ts
2
+ // AUTO-GENERATED by scripts/generate_data.py. Do not edit.
3
+
4
+ export const STEMS: readonly string[] = [
5
+ "paris", "tokyo", "milan", "rome", "oslo", "lima", "baku", "doha",
6
+ "kiev", "riga", "sofia", "kabul", "dakar", "cairo", "accra", "perth",
7
+ "miami", "boston", "dallas", "denver", "vegas", "omaha", "tulsa", "fargo",
8
+ "salem", "mobile", "tucson", "ottawa", "calgary", "dover", "leeds", "york",
9
+ "derby", "oxford", "bristol", "cardiff", "bath", "hull", "kent", "devon",
10
+ "essex", "berlin", "munich", "bremen", "bonn", "jena", "mainz", "madrid",
11
+ "sevilla", "malaga", "bilbao", "toledo", "oviedo", "lisbon", "porto", "faro",
12
+ "evora", "braga", "athens", "sparta", "rhodes", "crete", "naxos", "delos",
13
+ "rabat", "tangier", "oran", "tunis", "sana", "mecca", "jeddah", "aden",
14
+ "dubai", "manama", "beirut", "amman", "aleppo", "mosul", "basra", "shiraz",
15
+ "tabriz", "herat", "lahore", "dhaka", "mumbai", "delhi", "jaipur", "agra",
16
+ "chennai", "pune", "surat", "bhopal", "indore", "nagpur", "patna", "kandy",
17
+ "galle", "lhasa", "hanoi", "manila", "cebu", "davao", "jakarta", "bandung",
18
+ "medan", "penang", "melaka", "beijing", "wuhan", "harbin", "chengdu", "ningbo",
19
+ "xian", "dalian", "taipei", "seoul", "busan", "daegu", "sapporo", "sendai",
20
+ "nagoya", "kobe", "niigata", "sydney", "hobart", "darwin", "cairns", "mackay",
21
+ "alice", "auckland", "nelson", "napier", "cuzco", "quito", "bogota", "cali",
22
+ "caracas", "recife", "manaus", "natal", "asuncion", "santiago", "rosario", "havana",
23
+ "nassau", "panama", "leon", "merida", "oaxaca", "puebla", "cancun", "austin",
24
+ "houston", "phoenix", "fresno", "oakland", "raleigh", "durham", "nashville", "eugene",
25
+ "boise", "reno", "juneau", "wichita", "topeka", "lincoln", "helena", "pierre",
26
+ "dublin", "galway", "cork", "bergen", "tromso", "aarhus", "malmo", "turku",
27
+ "tampere", "kazan", "samara", "tomsk", "omsk", "perm", "minsk", "vilnius",
28
+ "tallinn", "warsaw", "krakow", "brno", "linz", "graz", "salzburg", "basel",
29
+ "geneva", "lyon", "nantes", "nice", "dijon", "reims", "lille", "rouen",
30
+ "nile", "amazon", "volga", "rhine", "danube", "seine", "thames", "tiber",
31
+ "tigris", "ganges", "indus", "mekong", "yukon", "hudson", "congo", "niger",
32
+ "zambezi", "orinoco", "parana", "douro", "tagus", "ebro", "loire", "elbe",
33
+ "oder", "vistula", "dnieper", "don", "ural", "lena", "ob", "amur",
34
+ "yangtze", "huang", "chao", "brahma", "yamuna", "kaveri", "jordan", "euphrates",
35
+ "orange", "limpopo", "senegal", "gambia", "okavango", "murray", "darling", "colorado",
36
+ "snake", "platte", "ohio", "missouri", "illinois", "arkansas", "red", "brazos",
37
+ "pecos", "rio", "gila", "salmon", "willamette", "sacramento", "klamath", "fraser",
38
+ "churchill", "peace", "mackenzie", "liard", "skeena", "thompson", "saskatchewan", "athabasca",
39
+ "saint", "lawrence", "saguenay", "copper", "kobuk", "noatak", "yampa", "green",
40
+ "roanoke", "savannah", "neuse", "cape", "pearl", "alabama", "tombigbee", "chattahoochee",
41
+ "suwannee", "santee", "broad", "oconee", "black", "tar", "peedee", "yadkin",
42
+ "catawba", "cumberland", "tennessee", "kanawha", "shenandoah", "james", "potomac", "susquehanna",
43
+ "delaware", "connecticut", "penobscot", "kennebec", "androscoggin", "merrimack", "housatonic", "genesee",
44
+ "mohawk", "oswego", "niagara", "maumee", "wabash", "cuyahoga", "muskingum", "scioto",
45
+ "licking", "barren", "rock", "fox", "sangamon", "iowa", "cedar", "des",
46
+ "moines", "wapsipinicon", "skunk", "chariton", "grand", "gasconade", "meramec", "current",
47
+ "eleven", "white", "cache", "buffalo", "neosho", "verdigris", "cimarron", "washita",
48
+ "canadian", "salt", "nueces", "frio", "llano", "san", "sabine", "trinity",
49
+ "neches", "lavaca", "guadalupe", "medina", "concho", "po", "arno", "tevere",
50
+ "adige", "taro", "ticino", "oglio", "adda", "mincio", "piave", "brenta",
51
+ "ems", "weser", "saale", "havel", "spree", "main", "neckar", "lech",
52
+ "isar", "inn", "drava", "sava", "morava", "tisza", "prut", "siret",
53
+ "olt", "mures", "somes", "argesh", "struma", "maritsa", "vardar", "drin",
54
+ "tay", "clyde", "azure", "amber", "coral", "indigo", "ivory", "jade",
55
+ "lilac", "mauve", "ochre", "olive", "ruby", "saffron", "scarlet", "sepia",
56
+ "teal", "violet", "umber", "vermilion", "plum", "cobalt", "cyan", "magenta",
57
+ "crimson", "maroon", "navy", "beige", "linen", "mint", "peach", "rose",
58
+ "sand", "sky", "slate", "snow", "tan", "wine", "bronze", "gold",
59
+ "silver", "brass", "cherry", "chestnut", "hazel", "honey", "lemon", "lime",
60
+ "cream", "cocoa", "coffee", "mocha", "russet", "sage", "taupe", "burgundy",
61
+ "claret", "emerald", "fern", "flax", "ginger", "grape", "khaki", "orchid",
62
+ "orchard", "fuchsia", "magnolia", "chartreuse", "moss", "myrtle", "pumpkin", "raspberry",
63
+ "rust", "seagreen", "seashell", "sienna", "sorrel", "spruce", "squash", "tangerine",
64
+ "thistle", "topaz", "turquoise", "viridian", "wheat", "zaffre", "puce", "mulberry",
65
+ "damask", "carmine", "cerise", "garnet", "hyacinth", "jasmine", "lavender", "melon",
66
+ "mustard", "nutmeg", "paprika", "periwinkle", "persimmon", "pewter", "pomegranate", "poppy",
67
+ "quince", "rosewood", "ruche", "saddle", "sangria", "seafoam", "shamrock", "smoke",
68
+ "spearmint", "sterling", "sunflower", "terra", "tomato", "vanilla", "veronica", "wisteria",
69
+ "xanadu", "zinnia", "absinthe", "alabaster", "apricot", "aqua", "aquamarine", "asparagus",
70
+ "avocado", "azalea", "bistre", "bittersweet", "blush", "bordeaux", "brick", "buff",
71
+ "bumblebee", "butter", "byzantium", "canary", "cardinal", "celadon", "celeste", "chambray",
72
+ "chamois", "cinnabar", "citrine", "clover", "coquelicot", "daffodil", "dandelion", "eggshell",
73
+ "electric", "firebrick", "flame", "glaucous", "goldenrod", "gunmetal", "heliotrope", "iceberg",
74
+ "icterine", "isabelline", "imperial", "jet", "juniper", "lemonade", "mahogany", "malachite",
75
+ "mango", "midnight", "moonbeam", "morello", "nutbrown", "obsidian", "opal", "opaline",
76
+ "oyster", "paisley", "papaya", "pastel", "pink", "pistachio", "platinum", "porcelain",
77
+ "primrose", "prussian", "quartz", "quicksilver", "rouge", "sable", "sapphire", "seal",
78
+ "shadow", "starlight", "sunset", "thunder", "umbra", "walnut", "brave", "bright",
79
+ "calm", "clever", "cool", "deep", "eager", "fair", "fine", "glad",
80
+ "happy", "keen", "kind", "lively", "merry", "neat", "noble", "proud",
81
+ "quick", "quiet", "swift", "warm", "wise", "witty", "young", "zest",
82
+ "jolly", "lucky", "mighty", "smart", "snappy", "spry", "sunny", "super",
83
+ "tidy", "true", "vivid", "wild", "zippy", "able", "active", "alert",
84
+ "ample", "apt", "artful", "balmy", "bold", "breezy", "brisk", "chic",
85
+ "chill", "cosy", "crisp", "dapper", "dashing", "dazzling", "deft", "divine",
86
+ "dreamy", "dynamic", "earnest", "easy", "elated", "elegant", "epic", "exact",
87
+ "fancy", "fluent", "fresh", "friendly", "funky", "gallant", "gentle", "gifted",
88
+ "glossy", "graceful", "hardy", "hearty", "honest", "hopeful", "humble", "jaunty",
89
+ "jazzy", "jovial", "joyful", "jubilant", "lavish", "legit", "liberal", "light",
90
+ "limber", "lithe", "lovely", "loyal", "lucid", "lush", "magic", "mellow",
91
+ "mild", "modest", "nifty", "nimble", "nimbly", "notable", "peppy", "perky",
92
+ "placid", "plucky", "plush", "polished", "polite", "posh", "prime", "pristine",
93
+ "prompt", "pure", "quaint", "quirky", "radiant", "rapid", "rare", "regal",
94
+ "reliable", "robust", "rosy", "royal", "rugged", "sassy", "savvy", "serene",
95
+ "sharp", "shiny", "silky", "sincere", "sleek", "slick", "smooth", "snug",
96
+ "solid", "sparkly", "spirited", "splendid", "spotless", "spunky", "stable", "stately",
97
+ "steady", "stellar", "stoic", "strong", "stunning", "stylish", "suave", "subtle",
98
+ "sturdy", "supple", "svelte", "tactful", "tender", "thrifty", "timeless", "top",
99
+ "tough", "tranquil", "trendy", "trusty", "upbeat", "valiant", "velvet", "warmhearted",
100
+ "welcoming", "worthy", "zealous", "ace", "adept", "agile", "airy", "ardent",
101
+ "astute", "beaming", "benign", "bonny", "buoyant", "candid", "charming", "cheery",
102
+ "chipper", "choice", "classic", "clean", "cogent", "comfy", "cordial", "cosmic",
103
+ "cute", "daring", "dauntless", "harbor", "haven", "cove", "glade", "meadow",
104
+ "grove", "summit", "ridge", "peak", "canyon", "vista", "oasis", "sanctum",
105
+ "atrium", "plaza", "forum", "agora", "portal", "beacon", "torch", "ember",
106
+ "spark", "prism", "orbit", "comet", "nebula", "pulsar", "quasar", "zenith",
107
+ "apex", "crown", "laurel", "medal", "trophy", "gem", "jewel", "charm",
108
+ "token", "coin", "badge", "crest", "emblem", "sigil", "banner", "pennant",
109
+ "arrow", "anchor", "compass", "keystone", "cornerstone", "pillar", "lantern", "lighthouse",
110
+ "keep", "tower", "castle", "bastion", "citadel", "fortress", "manor", "cottage",
111
+ "cabin", "lodge", "chalet", "villa", "palace", "temple", "shrine", "altar",
112
+ "chapel", "cathedral", "basilica", "garden", "grotto", "fountain", "spring", "brook",
113
+ "creek", "falls", "rapids", "tide", "wave", "swell", "shell", "reef",
114
+ "port", "pier", "dock", "wharf", "marina", "island", "isle", "archipelago",
115
+ "atoll", "cliff", "bluff", "mesa", "plateau", "valley", "vale", "dale",
116
+ "fen", "heath", "moor", "savanna", "prairie", "tundra", "delta", "lagoon",
117
+ "estuary", "fjord", "strait", "sound", "channel", "bay", "gulf", "inlet",
118
+ "lakeshore", "beach", "dune", "cinder", "pumice", "basalt", "granite", "crystal",
119
+ "agate", "onyx", "zircon", "spinel", "beryl", "peridot", "tourmaline", "jasper",
120
+ "moonstone", "sunstone", "bloodstone", "amethyst", "lapis", "carnelian", "chalcedony", "tigereye",
121
+ "hematite", "meadowlark", "falcon", "eagle", "hawk", "swan", "crane", "heron",
122
+ "robin", "wren", "finch", "sparrow", "sunbeam", "dawn", "dusk", "twilight",
123
+ "moonlight", "aurora", "rainbow", "zephyr", "breeze", "gale", "storm", "lightning",
124
+ "whirlwind", "tempest", "meridian", "solstice", "equinox", "talisman", "amulet", "scepter",
125
+ "chalice", "goblet", "flute", "lyre", "harp", "drum", "bell", "chime",
126
+ "echo", "soar", "glide", "drift", "float", "flow", "leap", "dash",
127
+ "sprint", "march", "wander", "roam", "explore", "voyage", "venture", "journey",
128
+ "travel", "embark", "launch", "begin", "start", "ignite", "kindle", "awaken",
129
+ "arise", "rise", "climb", "ascend", "conquer", "triumph", "flourish", "thrive",
130
+ "prosper", "bloom", "blossom", "flower", "grow", "expand", "evolve", "elevate",
131
+ "empower", "energize", "inspire", "uplift", "cherish", "nurture", "foster", "shelter",
132
+ "guard", "protect", "uphold", "support", "sustain", "balance", "harmonize", "align",
133
+ "tune", "compose", "craft", "fashion", "forge", "sculpt", "shape", "mold",
134
+ "weave", "thread", "knit", "stitch", "braid", "binds", "build", "raise",
135
+ "rear", "render", "discover", "unveil", "reveal", "disclose", "unfold", "open",
136
+ "share", "spread", "broadcast", "gather", "collect", "compile", "assemble", "unite",
137
+ "bond", "join", "meld", "merge", "blend", "fuse", "synthesize", "integrate",
138
+ "connect", "link", "bridge", "converge", "rally", "succeed", "achieve", "attain",
139
+ "master", "prevail", "excel", "shine", "glow", "gleam", "glimmer", "sparkle",
140
+ "radiate", "beam", "flash", "flutter", "dart", "dive", "surge", "swirl",
141
+ "spin", "twirl", "pivot", "hover", "linger", "pirouette", "swoop", "swivel",
142
+ "cascade", "tumble", "vault", "bound", "bounce", "skip", "prance", "gambol",
143
+ "caper", "romp", "frolic", "cavort", "dance", "sway", "glisten", "shimmer",
144
+ "scintillate", "twinkle", "dazzle", "illuminate", "brighten", "amplify", "boost", "charge",
145
+ "fortify", "embolden", "enliven", "enchant", "captivate", "beguile", "mesmerize", "delight",
146
+ "gladden", "enrich", "endow", "grant", "gift", "bestow", "yield", "deliver",
147
+ "produce", "furnish", "supply", "provide", "cultivate", "plant", "sow", "reap",
148
+ "harvest", "till", "tend", "mind", "heal", "mend", "renew", "restore",
149
+ "revive", "refresh", "rejuvenate", "quicken", "hasten", "propel", "thrust", "guide",
150
+ "steer", "navigate", "course", "chart", "map", "ada", "alex", "amy",
151
+ "ana", "avi", "ben", "bea", "cam", "dan", "dee", "eli",
152
+ "emma", "eva", "finn", "gus", "hugo", "ian", "iris", "ivan",
153
+ "jane", "juno", "kai", "kit", "liam", "lila", "luca", "lyra",
154
+ "maya", "mia", "milo", "nia", "noah", "nora", "oli", "omar",
155
+ "otto", "piper", "quinn", "rex", "ron", "sam", "sara", "seth",
156
+ "theo", "tom", "uma", "vera", "vic", "will", "xander", "yael",
157
+ "yuki", "zane", "zara", "alma", "anya", "beau", "cole", "cora",
158
+ "dane", "dora", "elsa", "enzo", "erin", "esme", "gabe", "gina",
159
+ "hank", "iggy", "inez", "ivy", "jack", "joel", "kade", "kara",
160
+ "kira", "kyle", "lana", "lars", "leah", "lily", "luna", "mack",
161
+ "maeve", "mads", "matt", "myra", "nash", "neil", "niko", "odin",
162
+ "oren", "orin", "pax", "pete", "raj", "rena", "rhys", "riya",
163
+ "rosa", "ruth", "ryan", "ryla", "shay", "simon", "sloan", "stef",
164
+ "tara", "teo", "tess", "thane", "tilda", "toby", "vance", "vita",
165
+ "vlad", "walt", "wes", "xenia", "yves", "zeke", "zion", "abe",
166
+ "alan", "amir", "andi", "arden", "aria", "ariel", "arlo", "asher",
167
+ "aster", "atticus", "august", "beck", "beth", "blake", "blanche", "bo",
168
+ "bridget", "bruno", "cael", "cain", "cal", "calla", "callie", "camilo",
169
+ "cara", "casey", "cass", "cato", "cecily", "celia", "celine", "cesar",
170
+ "chase", "clio", "colt", "cooper", "corin", "cyrus", "daisy", "dalia",
171
+ "dario", "darby", "dax", "desmond", "dexter", "diana", "dimitri", "dina",
172
+ "dom", "drew", "dru", "dylan", "eden", "edith", "elena", "elias",
173
+ "eliza", "elif", "ellis", "emery", "emil", "eric", "estes", "evan",
174
+ "ewan", "ezra",
87
175
  ];
88
176
 
89
- // Common words (A-Za-z only, no diacritics). Shared across all implementations.
90
- export const COMMON: string[] = [
91
- "river", "stone", "ember", "frost", "harbor", "willow",
92
- "copper", "marble", "anchor", "lantern", "cedar", "falcon",
93
- "coral", "dagger", "flint", "grove", "haven", "iron",
94
- "jasper", "kelp", "larch", "mast", "nettle", "oak",
95
- "pine", "quill", "reed", "sage", "thorn", "umber",
96
- "vale", "wren", "yarrow", "zenith", "amber", "birch",
97
- "cliff", "drift", "forge", "glade", "mesa", "canyon",
98
- "basin", "fern", "gale", "peak", "ridge", "shore",
99
- "tide", "bluff", "brook", "crest", "delta", "glen",
100
- "helm", "inlet", "jetty", "knoll", "loft", "moor",
101
- "notch", "orbit", "prism", "thunder", "silver", "meadow",
102
- "basalt", "summit", "valley", "bridge", "beacon", "ranger",
103
- "timber", "clover", "pebble", "ripple", "canopy", "chimney",
104
- "cinder", "comet", "ferret", "glider", "jaguar", "kernel",
105
- "lancer", "mortar", "nebula", "osprey", "patrol", "quartz",
106
- "rafter", "sparrow", "granite", "hazel", "kindle", "laurel",
107
- "mossy", "nimble", "ochre", "russet", "sable", "vapor",
108
- "wicker", "cobalt", "dune", "hollow", "ivy", "juniper",
109
- "linden", "mist", "oyster", "acorn", "anvil", "apron",
110
- "arrow", "ash", "atlas", "autumn", "badge", "banner",
111
- "beryl", "blossom", "boulder", "bramble", "brass", "breeze",
112
- "briar", "bronze", "brooklet", "buckle", "burl", "cairn",
113
- "candle", "canvas", "cavern", "chalk", "charm", "citrine",
114
- "cloud", "cloverleaf", "cobaltcore", "compass", "copperleaf", "cradle",
115
- "cricket", "crystal", "daisy", "dale", "dawn", "deerden",
116
- "desert", "dew", "diamond", "dovetail", "dragonfly", "dream",
117
- "drifter", "dunecrest", "dusk", "echo", "elm", "fernleaf",
118
- "firefly", "fjord", "flame", "flower", "flume", "forest",
119
- "foxglove", "garden", "garnet", "geode", "glacier", "glimmer",
120
- "goldfinch", "gravel", "greenwood", "griffin", "harborlight", "hearth",
121
- "heather", "heron", "hill", "honey", "horizon", "icicle",
122
- "ivory", "jewel", "kestrel", "lagoon", "laurelwood", "leaf",
123
- "lighthouse", "lilac", "lotus", "meadowlark", "moon", "moss",
124
- "myrtle", "nectar", "nightingale", "obsidian", "olive", "opal",
125
- "orchard", "otter", "pebblebrook", "petal", "plume", "prairie",
126
- "rain", "raven", "redwood", "reef", "ribbon", "root",
127
- "rose", "ruby", "sail", "salt", "sapphire", "scarlet",
128
- "seabird", "sequoia", "shadow", "shale", "shell", "shimmer",
129
- "skylark", "slate", "smoke", "snow", "sparrowhawk", "spindle",
130
- "spirit", "spring", "spruce", "star", "starlight", "storm",
131
- "stream", "sunbeam", "sunset", "sycamore", "talon", "thicket",
132
- "thistle", "thunderhead", "tidepool", "topaz", "trail", "valleyfield",
133
- "velvet", "violet", "walnut", "waterfall", "wave", "wind",
134
- "winter", "wolfram", "woodland", "zephyr", "ashwood", "bell",
135
- "bird", "bloom", "branch", "bright", "brookside", "camp",
136
- "campfire", "castle", "chime", "clay", "cloudbank", "coast",
137
- "copperwood", "creek", "crown", "emberfall", "field", "firestone",
138
- "flag", "fog", "fox", "gardenia", "gate", "glow",
139
- "grass", "grovewood", "harborstone", "hilltop", "honeycomb", "island",
140
- "kestrelwing", "lake", "leafwing", "marigold", "moonstone", "morning",
141
- "acacia", "alpine", "amulet", "apple", "apricot", "arcade",
142
- "arcadia", "archer", "argent", "armor", "asters", "aster",
143
- "aurora", "awning", "badger", "bamboo", "barley", "basil",
144
- "basket", "bayberry", "beech", "bellflower", "berry", "billet",
145
- "biscuit", "blackbird", "bluebell", "bluejay", "bonnet", "bough",
146
- "braid", "bread", "brick", "bridle", "brocade", "buckthorn",
147
- "burrow", "buttercup", "cabochon", "campion", "canary", "caraway",
148
- "catkin", "celeriac", "cello", "chanter", "chanticleer", "chestnut",
149
- "citadel", "clementine", "cloverfield", "cobble", "codex", "columbine",
150
- "corduroy", "cornflower", "courier", "coventry", "cove", "cowbell",
151
- "crocus", "curlew", "cypress", "damask", "daffodil", "dandelion",
152
- "dewdrop", "distaff", "driftwood", "eider", "elder", "elderberry",
153
- "elfin", "emerald", "enamel", "equinox", "faience", "feather",
154
- "fennel", "fiddle", "finch", "fir", "firwood", "flax",
155
- "floret", "flute", "freesia", "frostline", "gable", "galax",
156
- "garland", "gentian", "ginger", "gingham", "glenwood", "gosling",
157
- "grain", "grebe", "halcyon", "hazelnut", "headland", "heliotrope",
158
- "holly", "holystone", "honeydew", "hornbeam", "hyacinth", "inkwood",
159
- "iris", "ironwood", "jasmine", "jennet", "jonquil", "kettle",
160
- "kingsley", "laburnum", "lace", "ladle", "larkspur", "lavender",
161
- "leather", "ledger", "lemongrass", "linnet", "lodestar", "loquat",
162
- "lyre", "magnolia", "mandolin", "maple", "mariner", "marmot",
163
- "mayflower", "meadowrun", "merlin", "mica", "milkweed", "millet",
164
- "minnow", "mint", "mirabelle", "moonbeam", "moonrise", "moorland",
165
- "mulberry", "nimbus", "nuthatch", "oatfield", "olivewood", "onyx",
166
- "oriole", "oxbow", "pansy", "parchment", "partridge", "pear",
167
- "pearwood", "pelican", "pepper", "peridot", "pewter", "pheasant",
168
- "pimpernel", "pipit", "pistachio", "poplar", "porcelain", "primrose",
169
- "quail", "quince", "quincewood", "rainbird", "rainstone", "reedbed",
170
- "reedling", "rook", "rosemary", "rowan", "saddle", "saffron",
171
- "sandalwood", "satin", "sawgrass", "scallop", "seafoam", "seedling",
172
- "selkie", "shepherd", "shoal", "silk", "silverbell", "skylight",
173
- "snowdrop", "songbird", "sorrel", "spindlewood", "spindleberry", "sprucewood",
174
- "starling", "stonecrop",
177
+ export const ROTATIONS: readonly (readonly [string, string])[] = [
178
+ ["a", "e"],
179
+ ["e", "i"],
180
+ ["i", "y"],
181
+ ["o", "u"],
182
+ ["u", "o"],
183
+ ["y", "i"],
184
+ ["b", "p"],
185
+ ["c", "k"],
186
+ ["d", "t"],
187
+ ["f", "v"],
188
+ ["g", "j"],
189
+ ["h", "x"],
190
+ ["j", "y"],
191
+ ["k", "c"],
192
+ ["l", "r"],
193
+ ["m", "n"],
194
+ ["n", "m"],
195
+ ["p", "b"],
196
+ ["q", "k"],
197
+ ["r", "l"],
198
+ ["s", "z"],
199
+ ["t", "d"],
200
+ ["v", "f"],
201
+ ["w", "v"],
202
+ ["x", "z"],
203
+ ["z", "s"],
175
204
  ];