portmanteauly
v0.3.0
Published
Generate natural portmanteau words from 2-3 English words using rule-based multi-strategy blending
Maintainers
Readme
Portmanteauly
Generate natural portmanteau words from 2-3 English words using rule-based multi-strategy blending.
portmanteau (n.): a word blending the sounds and meanings of two others — smoke + fog = smog, breakfast + lunch = brunch
Features
- 🎯 Multi-Strategy Generation: Combines overlap detection, syllable blending, and ratio-based slicing
- 📊 Smart Scoring: Ranks candidates by n-gram frequency + consonant/vowel pattern naturalness
- ⚡ Fast & Deterministic: Rule-based (no AI/LLM), generates results in <100ms
- 🎲 Random Mode: Get creative inspiration from built-in 3000+ word list
- 🛠️ CLI + Library: Use from terminal or integrate into your code
- 📘 TypeScript: Full type definitions included
- 🔌 Zero Config: Works out of the box, no setup required
Installation
npm install portmanteaulyOr use directly with npx:
npx portmanteauly smoke fogCLI Usage
Basic Usage
# Blend two words
portmanteauly smoke fog
# Output:
# smog
# smok
# smof
# Blend three words
portmanteauly breakfast lunch dinnerRandom Mode
# Generate from random 2 words
portmanteauly --random
# Generate from random 3 words
portmanteauly --random --words 3Options
# Get more results
portmanteauly smoke fog --count 5
# Limit word length
portmanteauly smoke fog --max-length 8
# Show scores and source words
portmanteauly smoke fog --verbose
# Output:
# smog (score: 0.92, from: smoke + fog)
# smok (score: 0.78, from: smoke + fog)
# smof (score: 0.65, from: smoke + fog)
# Combine options
portmanteauly --random --words 3 --count 10 --max-length 12 --verboseHelp
portmanteauly --help
portmanteauly --versionAPI Usage
Basic Example
import { generate, generateRandom } from 'portmanteauly';
// Generate from specific words
const results = generate(['smoke', 'fog']);
console.log(results);
// [
// { word: 'smog', score: 0.92, sources: ['smoke', 'fog'] },
// { word: 'smok', score: 0.78, sources: ['smoke', 'fog'] },
// { word: 'smof', score: 0.65, sources: ['smoke', 'fog'] }
// ]
// With options
const limited = generate(['breakfast', 'lunch'], {
count: 5,
maxLength: 10,
});Random Generation
import { generateRandom } from 'portmanteauly';
// Random 2-word blend
const random = generateRandom();
// Random 3-word blend
const random3 = generateRandom({ words: 3, count: 5 });Error Handling
import { generate } from 'portmanteauly';
try {
const results = generate(['word1', 'word2']);
} catch (error) {
if (error.name === 'PortmanteauError') {
console.error('Generation failed:', error.message);
}
}API Reference
generate(words, options?)
Generate portmanteau words from input words.
Parameters:
| Parameter | Type | Required | Description |
| ------------------- | ---------- | -------- | ---------------------------------------- |
| words | string[] | Yes | Input words (2-3 words) |
| options.count | number | No | Number of results to return (default: 3) |
| options.maxLength | number | No | Maximum word length (default: unlimited) |
Returns: PortmanteauResult[]
Throws: PortmanteauError if input is invalid (e.g., < 2 or > 3 words)
generateRandom(options?)
Generate portmanteau words from random words in the built-in list.
Parameters:
| Parameter | Type | Required | Description |
| ------------------- | -------- | -------- | ------------------------------------------- |
| options.words | number | No | Number of random words (2 or 3, default: 2) |
| options.count | number | No | Number of results to return (default: 3) |
| options.maxLength | number | No | Maximum word length (default: unlimited) |
Returns: PortmanteauResult[]
Throws: PortmanteauError if generation fails after retries
PortmanteauResult
Result object returned by generation functions.
interface PortmanteauResult {
word: string; // Generated portmanteau word
score: number; // Overall quality score (0-1)
sources: string[]; // Original input words
}Score Interpretation:
0.8-1.0: Excellent — highly natural and pronounceable0.6-0.8: Good — decent blend with minor awkwardness0.4-0.6: Fair — usable but less natural0.0-0.4: Poor — awkward pronunciation or structure
GenerateOptions
Options for generate() function.
interface GenerateOptions {
count?: number; // Number of results (default: 3)
maxLength?: number; // Max word length (default: unlimited)
}RandomOptions
Options for generateRandom() function.
interface RandomOptions extends GenerateOptions {
words?: number; // Number of random words: 2 or 3 (default: 2)
}PortmanteauError
Custom error class for generation errors.
class PortmanteauError extends Error {
name: 'PortmanteauError';
}CLI Reference
Command Syntax
portmanteauly [word1] [word2] [word3] [options]
portmanteauly --random [options]Options
| Option | Alias | Type | Description |
| ------------------ | ----- | -------- | ---------------------------------------- |
| --count <n> | -c | number | Number of results (default: 3) |
| --max-length <n> | -l | number | Maximum word length (default: unlimited) |
| --verbose | -v | flag | Show scores and source words |
| --random | -r | flag | Generate from random words |
| --words <2\|3> | -w | number | Number of random words (default: 2) |
| --help | -h | flag | Show help message |
| --version | | flag | Show version number |
Exit Codes
| Code | Description | | ---- | ---------------------------------- | | 0 | Success | | 1 | Invalid input or generation failed | | 2 | Internal error |
How It Works
Portmanteauly uses three generation strategies:
Overlap Strategy: Finds common character sequences where word endings meet beginnings
- smoke + fog → smog (overlap: "o")
Syllable Strategy: Splits words by syllables and combines head + tail
- break·fast + lunch → brunch (brea + unch)
Slice Strategy: Cuts words at various ratios (40-60%) and joins them
- motor + hotel → motel (mot + el)
Each candidate is scored based on:
- Overlap length: Longer overlaps score higher
- Phonetic naturalness: Consonant/vowel patterns + n-gram frequency
- Compression ratio: Balanced shortening of original words
- Existing word penalty: Real English words score slightly lower
Examples
# Technology
$ portmanteauly web log
blog
weblog
welog
# Food
$ portmanteauly spoon fork
spork
spoon
foon
# Animals
$ portmanteauly lion tiger
liger
lioner
tion
# Random creativity
$ portmanteauly --random --verbose
flamazing (score: 0.84, from: flame + amazing)Requirements
- Node.js 18 or higher
- No external runtime dependencies
Tech Stack
- Language: TypeScript (strict mode)
- Module System: ESM only
- Runtime: Node.js 18+
- Build: tsup
- Test: Vitest
- Dependencies: Zero runtime dependencies (planned)
Development
# Install dependencies
pnpm install
# Run tests
pnpm test
# Run tests with coverage
pnpm test:coverage
# Build
pnpm build
# Lint
pnpm lint
# Format
pnpm format
# Type check
pnpm typecheck
# Benchmark
pnpm benchLimitations
- English only: Syllable and phonetic rules are optimized for English
- Max 3 words: Only supports 2-3 input words (not 4+)
- Rule-based: No AI/LLM — results depend on algorithmic strategies
Roadmap
- [ ] Add more generation strategies
- [ ] Support custom word lists
- [ ] Add language support (Spanish, French, etc.)
- [ ] Web UI playground
- [ ] Semantic similarity scoring
Contributing
Contributions are welcome! Please feel free to submit issues or pull requests.
License
MIT © Daniel Kyojun Ku
Made with ❤️ by developers, for developers
