[{"data":1,"prerenderedAt":356},["ShallowReactive",2],{"content-/blog/mispelr":3,"authors":339},{"article":4,"surround":327},{"id":5,"title":6,"author":7,"body":8,"date":305,"dateUpdated":306,"description":307,"excerpt":306,"extension":308,"headline":309,"meta":310,"navigation":181,"path":312,"seo":313,"socialImage":314,"stem":320,"tags":321,"__hash__":326},"blog/blog/mispelr.md","Mispelr, Unfrogotten","Michael Paulukonis",{"type":9,"value":10,"toc":303},"minimark",[11,23,34,37,78,81,101,119,250,264,278,299],[12,13,14,15,22],"p",{},"I had completely forgotten I wrote mispelr. It surfaced while I was working on ",[16,17,21],"a",{"href":18,"rel":19},"https://github.com/MichaelPaulukonis/textgen-monorepo/tree/main/apps/poeticalbot",[20],"nofollow","PoeticalBot",", which uses it to misspell poems, and there it was, a browser toy from 2015 that takes perfectly good text and ruins it.",[12,24,25],{},[16,26,29],{"href":27,"rel":28},"https://michaelpaulukonis.github.io/mispelr/",[20],[30,31],"img",{"alt":32,"src":33},"The mispelr playground: input text, six method buttons, a chance slider set to 50%, and the respelled output with changed words highlighted","/media/blog/mispelr/playground.png",[12,35,36],{},"It has six ways to do the ruining:",[38,39,40,48,54,60,66,72],"ul",{},[41,42,43,47],"li",{},[44,45,46],"code",{},"maledict"," swaps in real-world misspellings from a dictionary of common typos",[41,49,50,53],{},[44,51,52],{},"awfowell"," doubles (sometimes triples) vowels",[41,55,56,59],{},[44,57,58],{},"constonantSorrow"," does the same to consonants",[41,61,62,65],{},[44,63,64],{},"maxmister"," transposes two adjacent letters, never the first (\"Teh qucik bronw fxo\")",[41,67,68,71],{},[44,69,70],{},"homophilia"," swaps in homophones",[41,73,74,77],{},[44,75,76],{},"random"," mixes the others, word by word",[12,79,80],{},"It did what I wanted, but I was never completely happy with it. Every word went through the respeller once, and some came back unchanged, but how much of a sentence got mangled depended on the method and the dice and it was usually too much. There was no way to set it. And TBH, it was more annoying than anything else. Which was disappointing, since it did what I wanted. But eating a gallon of ice-cream in one go is not fun.",[12,82,83,84,89,90,95,96,100],{},"So I brought it back up to speed. It lives in ",[16,85,88],{"href":86,"rel":87},"https://github.com/MichaelPaulukonis/textgen-monorepo/tree/main/libs/mispelr",[20],"textgen-monorepo"," now, next to PoeticalBot. It's on npm as ",[16,91,94],{"href":92,"rel":93},"https://www.npmjs.com/package/node-mispelr",[20],"node-mispelr",". And the old Bootstrap page is a new ",[16,97,99],{"href":27,"rel":98},[20],"playground"," (that's it up top).",[12,102,103,104,107,108,111,112,115,116,118],{},"Tuning it with percentages made a big difference. ",[44,105,106],{},"respell"," takes a ",[44,109,110],{},"chance"," option - the share of words to misspell, 0 to 1. It also takes an ",[44,113,114],{},"rng",", so pass a seeded generator and the output is replayable: same seed, same text, same method, same misspelled poem. And each word's misspelling is fixed by the seed; ",[44,117,110],{}," only picks which ones get used. Raise it from 10% to 60% and the 10% typos are still there, with more added around them.",[120,121,126],"pre",{"className":122,"code":123,"language":124,"meta":125,"style":125},"language-js shiki shiki-themes github-light github-dark","const seedrandom = require('seedrandom')\nconst text =\n  'The quick brown fox jumps over the lazy dog, and their friends were there too.'\n\nmispelr.respell(text, 'random', { rng: seedrandom('fox'), chance: 0.1 })\nmispelr.respell(text, 'random', { rng: seedrandom('fox'), chance: 0.6 })\n// the second keeps every misspelling from the first, and adds more\n","js","",[44,127,128,159,170,176,183,217,243],{"__ignoreMap":125},[129,130,133,137,141,144,148,152,156],"span",{"class":131,"line":132},"line",1,[129,134,136],{"class":135},"szBVR","const",[129,138,140],{"class":139},"sj4cs"," seedrandom",[129,142,143],{"class":135}," =",[129,145,147],{"class":146},"sScJk"," require",[129,149,151],{"class":150},"sVt8B","(",[129,153,155],{"class":154},"sZZnC","'seedrandom'",[129,157,158],{"class":150},")\n",[129,160,162,164,167],{"class":131,"line":161},2,[129,163,136],{"class":135},[129,165,166],{"class":139}," text",[129,168,169],{"class":135}," =\n",[129,171,173],{"class":131,"line":172},3,[129,174,175],{"class":154},"  'The quick brown fox jumps over the lazy dog, and their friends were there too.'\n",[129,177,179],{"class":131,"line":178},4,[129,180,182],{"emptyLinePlaceholder":181},true,"\n",[129,184,186,189,191,194,197,200,203,205,208,211,214],{"class":131,"line":185},5,[129,187,188],{"class":150},"mispelr.",[129,190,106],{"class":146},[129,192,193],{"class":150},"(text, ",[129,195,196],{"class":154},"'random'",[129,198,199],{"class":150},", { rng: ",[129,201,202],{"class":146},"seedrandom",[129,204,151],{"class":150},[129,206,207],{"class":154},"'fox'",[129,209,210],{"class":150},"), chance: ",[129,212,213],{"class":139},"0.1",[129,215,216],{"class":150}," })\n",[129,218,220,222,224,226,228,230,232,234,236,238,241],{"class":131,"line":219},6,[129,221,188],{"class":150},[129,223,106],{"class":146},[129,225,193],{"class":150},[129,227,196],{"class":154},[129,229,199],{"class":150},[129,231,202],{"class":146},[129,233,151],{"class":150},[129,235,207],{"class":154},[129,237,210],{"class":150},[129,239,240],{"class":139},"0.6",[129,242,216],{"class":150},[129,244,246],{"class":131,"line":245},7,[129,247,249],{"class":248},"sJ8bj","// the second keeps every misspelling from the first, and adds more\n",[12,251,252,254,255,257,258,260,261,263],{},[44,253,110],{}," isn't always exact. ",[44,256,46],{}," and ",[44,259,70],{}," pass through any word they don't have an entry for, and ",[44,262,64],{}," skips anything under three letters, so the remaining words make up the difference as far as they can.",[12,265,266,267,270,271,274,275,277],{},"Extending the README also turned up a bug that had been sitting in the data for eleven years. A few rows in the homophone list were written as prose - ",[44,268,269],{},"there,their,and they're",", ",[44,272,273],{},"to,too,and two"," - and the conversion script kept the \"and\". So ",[44,276,70],{}," turned \"their\" into \"and they're\". I'd seen it in the playground but not chased it. Generating examples from real seeded output put it right in front of me. Fixed in 0.1.1.",[38,279,280,286,292],{},[41,281,282,283],{},"Playground: ",[16,284,27],{"href":27,"rel":285},[20],[41,287,288,289],{},"npm: ",[16,290,94],{"href":92,"rel":291},[20],[41,293,294,295],{},"Source: ",[16,296,298],{"href":86,"rel":297},[20],"textgen-monorepo/libs/mispelr",[300,301,302],"style",{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":125,"searchDepth":161,"depth":161,"links":304},[],"2026-11-02T00:00:00.000Z",null,"I forgot I'd written mispelr, a 2015 toy that misspells text on purpose.","md","A machine for misspelling",{"authorUrl":311},"https://michael.paulukonis.github.io/","/blog/mispelr",{"title":6,"description":307},{"src":315,"mime":316,"width":317,"height":318,"alt":319},"/media/blog/mispelr/mispelr.thumb.png","image/png",512,332,"The mispelr playground - method buttons, a chance slider at 50%, and respelled output with changed words in blue","blog/mispelr",[322,323,324,325],"generative-text","npm","poeticalbot","spelling and grammar","IkqytFLiWVsK5Zo65P2MN6tRGTm-RXS3Qlmroyi4B98",[328,334],{"title":329,"path":330,"stem":331,"headline":332,"description":333,"excerpt":306,"children":-1},"painting with words","/blog/imagetexter","blog/imagetexter","imagetexter - painting with words","ASCII text-painter using whole words instead of letters, impressionistic and legible at once",{"title":335,"path":336,"stem":337,"headline":335,"description":338,"excerpt":306,"children":-1},"Nova Zombie Simulator","/blog/nova-zombie-simulator","blog/nova-zombie-simulator","A p5.js zombie game made with Anthony, where you play the main zombie instead of fighting it.",{"id":340,"avatar":306,"bio":306,"extension":341,"meta":342,"name":306,"social":306,"stem":354,"__hash__":355},"authors/authors.json","json",{"path":343,"Sample Author":344,"body":351,"title":353},"/authors",{"@context":345,"@type":346,"@id":347,"name":7,"alternateName":7,"nationality":348,"gender":349,"jobTitle":350,"url":347},"http://www.schema.org","Person","https://michaelpaulukonis.github.io/","American","male","Senior Software Engineer, full-stack dev, backend-focus",{"Sample Author":352},{"@context":345,"@type":346,"@id":347,"name":7,"alternateName":7,"nationality":348,"gender":349,"jobTitle":350,"url":347},"Authors","authors","gDLa0t2oQBqkm4ZjFHa3UMLJv3dsBGcc4djngSH_b-Q",1793633066489]