Made Up Words

by Obsidian TTRPG Community
5
4
3
2
1
Score: 42/100

Description

A dictionary for the words you've made up. Look up your invented vocabulary in your Obsidian vault — across multiple languages, with hover tooltips and a side-panel lexicon.

Reviews

No reviews yet.

Stats

4
stars
1,132
downloads
0
forks
2
days
2
days
2
days
6
total PRs
1
open PRs
4
closed PRs
1
merged PRs
14
total issues
4
open issues
10
closed issues
26
commits

Latest Version

3 days ago

Changelog

Made Up Words v0.21.1 — Community review fixes

A maintenance release. Nothing about the plugin behaves differently; this clears the four errors the Obsidian community-plugin automated review raised against 0.21.0 so the listing can pass its checks.

What the review flagged

The committed lockfile was out of date, which failed both the dependency check and the build verification. It has been regenerated. While fixing it, @codemirror/state and @codemirror/view were pinned to the exact versions Obsidian 1.13.0 declares as peer dependencies (6.5.0 and 6.38.6) — the previous version ranges asked for releases above those pins, so a clean npm install only succeeded by overriding peer dependencies. A clean install is now warning-free.

Two lint rules were being suppressed inline. Version 0.4 of eslint-plugin-obsidianmd no longer permits eslint-disable comments for obsidianmd/* or @typescript-eslint/no-deprecated rules, and requires a written justification on any directive comment that remains. All thirteen directive comments are gone — none of them were annotated to keep them:

  • The caret-position fallback used for Obsidian builds older than 1.13.0 now reaches caretRangeFromPoint through a locally declared type, so the call no longer resolves to the deprecated Document member. The fallback behaviour is unchanged, and support back to minAppVersion 1.7.2 is unchanged.
  • The Remove language button now calls setDestructive() on Obsidian versions that have it and setWarning() on versions that do not, rather than always calling the deprecated setWarning().
  • The rest were for the sentence-case rule on strings it reads incorrectly: the e.g. … placeholders in the word, name and entry modals, and the + Word, + Name and ↑↓ Swap direction buttons, where the rule counts a leading glyph as the first word. The wording of those labels has not changed. The rule now runs at its own default severity, so it reports them as warnings instead of being silenced.

Also in this release

  • Releases now publish GitHub artifact attestations for main.js and styles.css, so anyone can cryptographically verify that the files attached to a release were built from this repository. This was a recommendation rather than an error, but it is worth having.
  • The release workflow installs with npm ci, so a stale lockfile fails the build in future instead of passing quietly.

Installing / updating

Download main.js, manifest.json, and styles.css from this release and copy them into .obsidian/plugins/made-up-words/ in your vault, then reload the plugin (or restart Obsidian). Settings and dictionaries are preserved.

README file from

Github

Made Up Words

A dictionary for the words you've made up — characters, places, invented vocabulary, conlangs — living inside your Obsidian vault.

Version License: MIT

Pre-1.0 / early release. The plugin is usable and actively developed, but expect rough edges and the occasional breaking change. Feedback and bug reports are very welcome — see Filing feedback. Changes between versions are tracked in CHANGELOG.md.


What this plugin is, honestly

This is a dictionary-and-lookup tool, not a translator. Real translation between languages requires grammar, register, social context, and discourse-level decisions that no plugin can make for you. Languages aren't ciphers for English — they encode information English doesn't, and lose information English does encode. A plugin that pretends otherwise will be useful for the "English with different sounds" case (most fantasy worldbuilding) and actively misleading for serious conlanging work.

Made Up Words takes a deliberately honest approach. It does three things:

  1. Stores your dictionary as a folder of markdown notes with structured frontmatter, and indexes them for fast lookup. Each invented word gets its own note.

  2. Looks words up. When you highlight or hover a word in any note, it shows you what the dictionary knows — all the matching senses, not a single "best" guess. Inflected forms are recognised when you've defined rules for them.

  3. Generates phonological placeholders via a deterministic cypher engine. This is for inventing new words and names in your language's sound style — not for translating sentences. The plugin labels cypher output clearly so you know it's a placeholder, not a translation.

This positions Made Up Words as a tool for both casual worldbuilding ("I need a fantasy name that fits") and serious linguistic conlanging (where the dictionary is the only real translation surface and the cypher is mostly irrelevant).


Two modes of use

Mode A: Flavour conlang (English with different sounds)

You want your fantasy world to feel different but you don't intend to design real grammar. Use the cypher engine to define sound substitutions, save a handful of named characters and places as dictionary entries, and the plugin will transliterate prose for you. The "transliterate" output in the translator tab does what you want — though it's still not real translation; it's English with substituted phonemes.

This is the use case most worldbuilders have. The plugin works well here.

Mode B: Linguistic conlanging

You're designing a real language with morphology, syntax, register choices, and lexicon that doesn't map 1:1 to English. The cypher is largely irrelevant for you. What the plugin offers:

  • A structured dictionary with metadata (POS, IPA, etymology, semantic notes)
  • Multi-sense English-to-conlang lookup (the plugin won't pick a "best" sense — you do)
  • Inflection rule definitions that recognise inflected forms on hover and predict paradigms
  • Phrase / fixed-expression / compound entries with optional parts decomposition
  • A names registry for proper nouns
  • A "Look up word" command that shows all dictionary candidates with their metadata

What the plugin doesn't do, and won't try to do:

  • Translate sentences. There is no fluent output mode. The translator tab's gloss mode shows you word-by-word lookups so you can see what the dictionary knows; the assembly into grammatical conlang is your job.
  • Encode politeness/honorifics, evidentiality, topic-comment structure, or other features that require context the dictionary doesn't carry. You can record these in entry notes, but the plugin doesn't generate them.
  • Handle non-affixational morphology (ablaut, Semitic root templates, reduplication). The inflection matcher is affix-only.

Features

Side panel

Click the book-open icon in the left ribbon (or run Made Up Words: Open panel) to open the panel on the right. Three tabs:

Selection — auto-updates as you highlight text in any note. For single-word selections that resolve to a dictionary entry, it switches to a "word details" view showing the entry plus its predicted inflected forms.

Translator — a free-form input box. Type something and see how the plugin looks it up. Two modes:

  • Gloss (default) — shows word-by-word breakdown. Each word is a card showing what kind of match it is (dictionary, inflected, phrase, cypher placeholder, no match) plus all matching candidates. This is the honest representation: it does not assemble fluent translation.
  • Transliterate — flat substitution output, with dictionary words shown in plain colour and cypher placeholders shown italicised in orange. Useful for the flavour-conlang case; labelled honestly for the linguistic-conlang case.

Dictionary — browse, search, filter, and sort all entries. Names filter, part-of-speech filter, search by definition or category. Click any entry to open its note.

Hover lookups

By default, hover tooltips require holding Shift while pointing at a word — this keeps them out of the way during normal reading. Change this in Settings → Made Up Words → Hover modifier key (options: None, Shift, Alt, Ctrl/Cmd). Setting it to "None" restores the old always-on behaviour. Note: after pressing or releasing the modifier, move the mouse slightly to refresh the tooltip state.

Hover resolves in a fixed order, and your conlang always wins over English:

  1. Multi-word phrase → the phrase entry
  2. Direct dictionary entry → full metadata (every sense, if the spelling is a homograph)
  3. Hardcoded declared form → the lemma plus its label ("kalath = plural of kala")
  4. Rule-derived inflected form → same, via your inflection rules
  5. English word a definition matches → all candidates listed, plugin doesn't pick
  6. Nothing matched → cypher transformation, labelled as "cypher only"

Steps 1–4 are the conlang direction; steps 5–6 are the English direction. If a word resolves as any of 1–4, the English direction is never consulted — so a made-up word that happens to look like English is read as your word, not as English.

Both directions can be turned off independently under Settings → Hover tooltips:

  • Show your words' meanings — the conlang direction (steps 1–4).
  • Show English to conlang translations — the English direction (steps 5–6). Turn this off if your made-up words are still being mistaken for English. It also disables the cypher preview, since that transformation treats the hovered text as English too.

Turning both off disables hover entirely. Hover can also be switched off per language in each language card.

"Look up word" command

Select a word in any note and run Made Up Words: Look up word (all senses) (or assign a hotkey). A modal opens with every possible match: direct entries, inflected forms, English-direction candidates, and a cypher placeholder if applicable. Each candidate shows its metadata. Click to open the entry's note.

This is the workflow if you want explicit control over which sense you use in a given context.

Inflection rules

Configure suffix/prefix rules per language in Settings. Each rule:

  • has a label ("plural", "past tense", "genitive", etc.)
  • specifies pattern, strip, and add fields (for simple chops or respellings)
  • can be POS-conditioned so a noun-plural rule doesn't fire on verbs
  • can have its own description for hover education

Six presets ship out of the box: None, Minimal, Indo-European basic, Indo-European full, Agglutinative starter, Analytic. Apply a preset to load a curated starter set, then edit the affixes.

Rules are bidirectional: they recognise inflected forms during lookup AND predict the inflected forms of a word when you view its details.

Names registry

Proper nouns get special handling. The "+ Name" button in the panel header opens a creation modal that supports two paths: type the name freely, or derive it from English via the cypher (which the modal makes explicit, not implicit). Names are stored verbatim so they're locked even if cypher rules change.

Categories (character, place, faction, artifact, event, title, other) are filterable in the browser and each has hover-tooltip explanations.

Phrases and compounds

Multi-word entries work via the word: frontmatter override. Compounds can declare parts: to list their constituent conlang words; the word-details view then shows each part's meaning with click-through to that part's entry.

Education tooltips

About 30 common inflection category labels (plural, past, genitive, comparative, evidential, etc.) have built-in hover explanations to help users learn linguistic vocabulary. Custom labels can have their own descriptions on each rule.


Installation

This plugin is not yet in the Obsidian community plugin browser, so install it manually from the GitHub releases.

  1. Go to the Releases page and download main.js, manifest.json, and styles.css from the latest release (they're attached as individual assets, and also bundled in the release .zip).
  2. In your vault, navigate to .obsidian/plugins/ (this folder may be hidden — on macOS press Cmd+Shift+. in Finder; on Windows enable "Show hidden files"; on Linux press Ctrl+H).
  3. Create a folder called made-up-words inside it.
  4. Copy the three files into that folder, so you have .obsidian/plugins/made-up-words/main.js (and manifest.json, styles.css).
  5. In Obsidian: Settings → Community plugins. Enable community plugins if you haven't, then click the refresh icon, find Made Up Words, and toggle it on.

If the plugin doesn't appear, restart Obsidian.

Updating: download the three files from the newer release and overwrite the old ones. Your settings and dictionary are stored separately and are preserved; any settings-format changes migrate automatically on load.


First-time setup

The plugin ships with one pre-configured example language at folder Made Up Words/Example. You can either edit this in Settings → Made Up Words to point at a folder you actually use, or add a new language. The dictionary folder doesn't need to exist yet.

  1. Open the panel (book-open icon in the left ribbon).
  2. The panel header shows your active language and entry count.
  3. Open any note, type some English, highlight a word.
  4. Try the Translator tab to see how looking up text feels.
  5. Click Save to dictionary to commit a word. You'll be prompted for the part of speech.
  6. Click + Name in the panel header to create proper nouns.

To customise: open Settings → Made Up Words. Cypher rules in sheets, inflection rules with presets, per-language dictionary folder paths.


Dictionary entry format

A dictionary entry is a single markdown file. The filename is the conlang word by default; frontmatter can override this for phrase entries and homographs.

---
definition: water
language: Example
partOfSpeech: noun
ipa: /ˈka.la/
etymology: from proto-form *kal-
---

# kala

Used for fresh water specifically. The sea is *drennith*.

Only definition is required. Supported frontmatter fields:

Field Purpose
definition English translation. Comma- or semicolon-separated values index as separate English senses.
language Which language this entry belongs to.
partOfSpeech Used by inflection rules and the browser. Common values: noun, verb, adjective, adverb, pronoun, proper-noun, preposition, conjunction, interjection.
ipa Pronunciation.
etymology Origin / derivation notes.
word Overrides the filename as the surface form. Needed for phrase entries with spaces, and for homographs — several files can declare the same word (see multi-sense entries below).
parts YAML list or comma-separated string of conlang words this compound decomposes into.
aliases Alternate surface forms that resolve to this same entry.
forms Hardcoded inflected forms — a declension or conjugation table for this entry (see below).
inflectAs Extra part(s) of speech to match POS-filtered inflection rules under (see below).
nameCategory For proper nouns: character, place, faction, artifact, event, title, other.

Multi-sense entries (homographs): if a word has genuinely different senses (e.g. English "see" = visual perception vs. understanding), create separate dictionary entries — one for each sense. Two files can't share a name, so give each file a distinct name and declare the shared spelling with the word: override:

# File: kala (verb).md
---
word: kala
definition: to walk, to stroll
partOfSpeech: verb
---
# File: kala (noun).md
---
word: kala
definition: guitar
partOfSpeech: noun
---

Both entries index under kala — hovering it in a note shows every sense in one tooltip, and lookups return all of them. The add-word commands handle this automatically: creating a word that already exists with a different meaning writes a new word (partOfSpeech).md sense file instead of failing, while re-adding an existing meaning just opens the existing entry.

Comma-separating in the definition only helps if you want one entry to match multiple English keys with effectively the same meaning ("water, liquid").


Cypher rules (Mode A use case)

In Settings → Made Up Words → any language, configure cypher sheets. Each sheet is a list of input→output substitution rules with a type:

  • word — matches only when bordered by non-letters on both sides
  • prefix — matches at the start of a word
  • suffix — matches at the end of a word
  • default — matches anywhere

Rules within a sheet: longest match wins, then word > prefix > suffix > default. Sheets run top-to-bottom with each sheet's output feeding the next. Put whole-word substitutions at the top, before sound-change sheets.

Honest framing: the cypher is a tool for generating words in your language's phonological style. It is not a translation engine and the plugin no longer pretends it is. Output is clearly labelled as cypher fallback throughout the UI.


Inflection rules (Mode B use case)

In Settings → Made Up Words → any language → Inflection rules. Each rule has:

  • Label — the inflection's name ("plural", "past", "genitive")
  • Position — suffix or prefix
  • Pattern — the affix string
  • Strip — what to remove (usually same as pattern)
  • Add — what to put back (for respellings like English -ies → -y; usually empty)
  • POS filter — comma-separated parts of speech this rule applies to
  • Description — your own tooltip explanation (overrides built-in for known labels)

Rules are tried in order. First one whose reconstructed lemma exists in the dictionary wins, so unrelated words won't get false-matched.

Limitations: affixation only. No infixes, ablaut, reduplication, or root templates. If your conlang has those, the inflection matcher will miss them — record them in entry notes instead.

Hardcoded forms (forms:)

Rules are pattern-based, and every real language has words that break the pattern. Declare those forms directly on the entry:

---
definition: water
partOfSpeech: noun
forms:
  - "plural: kalath"
  - "genitive: kalen"
  - "dative: kalim, kalum"
---
  • The canonical shape is a YAML list of "label: form" strings, because Obsidian's property editor renders a list of text natively. A YAML map (forms: {plural: kalath}) and a single comma-separated string also work.
  • Several forms can share a label — dative: kalim, kalum declares two datives.
  • A form with no label gets the label variant, which behaves like an alias but is honestly labelled.

Declared forms are recognised everywhere a rule-derived form is: hovering one shows "kalath = plural of kala", it highlights, and clicking opens the lemma's note. They're also rendered as a Declared forms table in the side panel, and (optionally) in the hover tooltip — toggle that under Settings → Word matching → Show declared forms in hover tooltip.

Two priority rules:

  • A declared form beats whatever an inflection rule would derive. That's the point — an irregular is exactly the case the rules get wrong.
  • Declaring a label suppresses the same-named rule for that entry only, so a hardcoded past: went won't sit next to a predicted goed. Other labels are untouched.

A real headword always outranks another word's declared form, so declaring a form that collides with an existing word won't shadow it.

Borrowing another part of speech's rules (inflectAs:)

If a word inflects like a different part of speech, say so instead of duplicating every rule:

---
definition: they
partOfSpeech: pronoun
inflectAs: noun
---

This entry now matches rules filtered to noun as well as rules filtered to pronoun — it's additive, so any pronoun-specific rules you already wrote keep working. Comma-separate for more than one (inflectAs: noun, adjective).


Commands

In the command palette under "Made Up Words:":

  • Open panel
  • Look up word (all senses) — opens the lookup modal with all candidates. The honest workflow for serious linguistic work.
  • Translate selection to primary language (preview) — shows a notice with the transliterated output
  • Translate selection to primary language and replace — commits the transliterated output, wrapping the original in <abbr title="..."> so it shows on hover in reading mode
  • Translate selection to English (preview)
  • Add selection to dictionary — opens the save-to-dictionary modal
  • Add a name (proper noun)
  • Reload dictionary

Assign hotkeys to the commands you use most.


What's deliberately not in this plugin

  • Auto-translation of sentences. This was the central feedback we received from a linguistic-conlanger tester, and we agreed with it. Languages encode information English doesn't (and vice versa); pretending otherwise produces wrong output dressed up as right output.
  • Politeness levels, register, evidentiality, topic/focus particles, honorifics. These are real and important features of many languages; they're context-dependent and the dictionary doesn't carry the context. Record them in entry notes.
  • Quick-insert autocomplete while typing (roadmap, not built)
  • Coverage view showing what semantic domains your dictionary covers (roadmap)
  • Sound-change cascades (Lexurgy-style ordered phonological rules with conditioning)
  • Phonotactic validation / word generation
  • Custom script / orthography rendering
  • Interlinear gloss code blocks for entry notes
  • Cross-language relationships (proto → daughter)

Known limitations

These are current rough edges rather than deliberate scope choices:

  • Inflection handles affixation only — prefixes and suffixes. No infixes, ablaut (vowel mutation), reduplication, or root-and-pattern morphology. If your language relies on these, the inflection matcher will miss them; record forms as separate entries instead.
  • Reverse cypher is approximate. Substitution rules can collide, so conlang→English cypher fallback is best-effort. Dictionary entries are always exact; the cypher is the fallback.
  • Large dictionaries are untested. Performance with several thousand entries hasn't been measured. If you have a large lexicon and hit slowness, please file an issue with rough numbers.
  • One note per conlang word. The plugin doesn't support a "one note per concept, translations in frontmatter" layout. Multi-language vaults use one note per word per language.

Filing feedback

Bug reports and feedback are very welcome — please open a GitHub issue. This is an early release and real-world use is exactly what it needs.

Most useful kinds of feedback:

  • Workflow friction — moments where you knew what you wanted to do but the plugin made it hard
  • Wrong defaults — places where the plugin assumes too much or too little
  • Honesty failures — places where the UI implies more capability than the plugin actually has (these matter; the plugin tries hard to be honest about its limits)
  • Bugs — anything that crashes, fails silently, or produces wrong output

When filing a bug, it helps to include: your Obsidian version, what you did, what you expected, and what happened instead. For errors, open the developer console with Ctrl+Shift+I (Cmd+Opt+I on Mac) — plugin errors appear there with a [Made Up Words] prefix, and pasting them into the issue speeds things up a lot.

Feature requests are welcome too, though note the known limitations and the deliberately-omitted items are intentional design choices rather than oversights — though if enough people want one, that's useful signal.


Contributing

The plugin is written in TypeScript and built with esbuild. To work on it:

npm install
node esbuild.config.mjs production   # one-off build
node esbuild.config.mjs              # watch mode for development

The test suites are plain TypeScript compiled to CommonJS and run with Node — see the test-*.ts files. They have no test-runner dependency, so they run anywhere Node does.

The source is organised into focused modules: cypher.ts (substitution engine), dictionary.ts (the index and loader), gloss.ts (lookup model), inflection.ts (morphology), phrases.ts (multi-word matching), panel.ts (the side panel UI), main.ts (plugin lifecycle and hover), and several modal files. Shared string helpers live in word-tokens.ts.


Credits

  • FanLang by Mick Boere — the cypher engine algorithm is directly inspired by FanLang's read-and-replace model.
  • The conlanger testers who pushed back on auto-translation — the lookup-first design exists because of that feedback. The framing of "the plugin doesn't pick a best sense for you — language doesn't work that way" came directly from their critique.
  • Lexurgy, Vulgarlang, LanguaGen, Awkwords — the broader conlanging ecosystem informs what this plugin tries to do and what it deliberately doesn't try to replace.
  • Leipzig glossing rules — the .LABEL notation in gloss output.