Skip to content

Latest commit

 

History

History
143 lines (134 loc) · 60.2 KB

File metadata and controls

143 lines (134 loc) · 60.2 KB

Changelog

vNext (2026--)

  • Every word pool is wider, by roughly a third. Around a thousand nouns were added per language, so each of the nine now holds between 3,400 and 3,900 across the twenty-nine themes, and no theme sits below sixty. The thin ones gained the most: nature, space, time, color and tech were the pools a batch of ten repeated itself in. Every added word is levelled the way the rest are, so vocabulary: 'basic' still draws only the everyday ones. New animals, plants and creatures carry the traits a verb asks for, so a sparrow added today takes off and a jellyfish swims.

  • Two people in one story no longer share a name. A name was drawn without regard for the names the paragraph already carried, so visit and chat — the two stories with a second person in them — wrote the hero meeting somebody with the hero's own name about once in a thousand results. A drawn name is now one nobody in that result carries.

  • Four themes join the twenty-five. toy holds what a childhood is made of (팽이, Kite, けん玉), sound what a language calls its noises (바스락, Rustle, ざわめき), person people by age, kinship and character rather than by trade (꼬마, Neighbor, 双子), and furniture what a room is furnished with (요람, Hammock, 座布団). Each is a generator of its own — randToy, randSound, randPerson and randFurniture — and each is filled in all nine languages. Words that were already in the pools moved rather than being copied: the top and the dice left object, the wardrobe and the bookshelf left product, and the whisper left concept. A sentence takes them the way it takes their neighbours, so a toy and a piece of furniture do what a thing does, a sound does what a song does, and somebody in a story can be a stranger as well as a locksmith.

  • A paragraph describes each noun once. 어수선한 저기압이 살랑살랑 잦아들어요. … 신비한 저기압이 슬며시 사라져요. was one low-pressure front described twice. A noun a story pinned was remembered and a noun it drew afresh was not, so a story whose steps drew the same weather twice put a modifier in front of it twice. Every noun a result has described is now carried through the whole of it, and one that comes round again is written bare.

  • Two words a result could say twice. A Japanese sentence could close on こだました, which is the plain past of こだまする and the polite past of a verb nobody has, so a paragraph at one speech level read as one at another; the verb is 反響する now. And a homecoming no longer opens on a word a sentence opens on — 드디어 집이다! after a sentence that opened on 드디어 said it twice, and Chinese, Vietnamese and Spanish each had the same pair.

  • A sentence with a person in it keeps the language's own floor. A name is one word and no article, so a Chinese sentence about one could come back as 彤找。 — three characters, where sentenceLengthRange('zh') says the language writes four. The name still narrows the top of the budget, which is what stops a shape being chosen for a length only a noun phrase could reach; the bottom is measured against the language's nouns whoever stands in the subject. The narrowing had also been dead in the JavaScript package, where every noun slot shared one entry, so a shape there was chosen against noun lengths a name never writes.

  • A story never comes back one sentence long. A telling that had paid for a two-clause sentence and had nothing left to trim but the two clauses themselves kept both, and sentences: 4 came back with five about once in ten thousand. The planner now gives up the join and trims one of its clauses when nothing else stands alone.

  • vocabulary says how common the words have to be. The pools hold apple and thallium, 의사 and 통메장이, and a draw over all of them came back with a specialist's word about as often as an everyday one. Every noun of every language now carries a level — basic for the everyday words nearly every speaker uses, rare for the ones a specialist or a dictionary would know, common for what is left — and randWord, randNickname and randSentence take vocabulary: 'basic' | 'common' | 'full', each level holding the ones below it. The default is 'full' for randWord and randNickname, which is the pools as they were, and 'common' for randSentence: a sentence is read, and a paragraph about a glassblower and thallium was what the whole pool wrote. Around a third of each language's nouns are basic and a fifth rare; the lists are per language and about that language's own words, and every theme keeps a handful of basic words.

  • Coming home is said in the language's own words. “집에 도달했습니다.” was grammar and nobody says it. A line that reports coming home now draws from SentenceLanguageData.homecomings다녀왔어, ただいま, 我回来了, I'm home, ya estoy en casa, ich bin zurück, я дома — by speech level, in every language, since an idiom needs no first person.

  • Dialogue with something in it, and more than one turn of it. A line was a feeling — “만족스러워.”, “엄청 활기차네!” — and a paragraph held one. A person now reports almost anything they just did, where they did it and to what (“부엌에서 열쇠를 찾았어!”, “시장에 가서 빵을 샀어.” — a two-clause sentence is one line when both clauses are the hero's to tell), says what they see somebody else doing (“새가 날아가네!”, and thinks it rather than says it when it is about the person beside them), and asks that person how they are, in the second person, in all nine languages (“배고파?”, “Are you tired?”, ¿Estás cansado?, Bist du müde?) — SentenceLanguageData.listener is the new field. An answer now fits what it answers rather than fitting anything: replies is sorted by ReplyCueagree for a remark, cheer for good news, care for somebody tired or hungry, wonder for more of what was reported, answer for a question — and in a scene of speech the hero goes on after being answered, so an exchange runs for several lines. A line that reports carries something beside its verb (“찾았어.” is no longer a line), and a line names no time of day but keeps its place and its manner.

  • A manner goes with the doing. 정중히 깨어나요, 사뿐사뿐 외쳐요 and slept briskly were what a manner pool sorted by noun class alone allowed. ModifierGroup.fields names the verb fields a group of manners goes with — how somebody moves, handles a thing, looks or thinks, hesitates, is with somebody else, feels while they do it — and the Korean and English manners are sorted into them; a group that names no field fits any doing, which is what the other seven languages' groups still do. Korean's causal connectives lose 그러므로, 따라서, 그리하여 and 그러니까, which are a proof's and an argument's, and gain 그바람에 and 그덕에.

  • A paragraph is no longer the same story every time. Four stories join the fifteen: chat (two people meet and talk — the story with the most lines in it), watch (the hero sits down somewhere and watches what happens around them), shelter (the weather turns while the hero is out) and sketch (nothing happens to anybody; a place is described, and the things in it do what they do). Most stories now have somebody else in them — the person met, a stallholder, a bird on a fence, the weather — who does something of their own, written as what they are and never by a name.

  • Whether anybody speaks is drawn per result, and what they say is more than how they feel. A paragraph is narrated all the way through, quotes a line or two, or carries a short exchange. A person says what is true of them or what they just did (“열쇠를 찾았어요!”, “I found the key!”), remarks on the thing in front of them or the place around them in the third person, which every language can write (“사과가 참 달다!”, «El hospital es precioso.»), and is answered with one of the language's own replies (“그러게.”, “Really?”), which take the place of an optional step. Every line of one result is said at one speech level, and an answer carries no phrase in SentenceDetail.phrases.

  • No more one-word sentences. 놀아요., 울어. and 냄새맡는다. were a third of a Korean paragraph. A sentence that drops its subject now takes a shape with something beside its predicate, and a state sentence has somewhere to grow: every language declares a shape with a degree in front of the state (무척 피곤하다, is very tired) and one with a time, and degree is a SentenceSlot a caller can ask for.

  • The hero shows what is true of them. express verbs are split by what they show, so the hero laughs after the meal and sighs after losing the key rather than sneezing after either; a meal now leaves the hero pleased as well as full. A story says when about one sentence in four and never twice running, and a step is padded in a second time only if it can happen twice — nobody comes home twice.

  • Two to three times the predicates and adverbials, in every language. The verbs were widened; what stands around them was not. Nine states described everything a hero could be, thirteen modifier groups shared a hundred adjectives between them, and two manner groups held thirty-odd adverbs — so three sentences said 조용히 twice and called two different baskets 작은. Across the nine languages the states go from 652 entries to 1,475, the modifiers from 1,010 to 2,340, the manners from 341 to 963, the time adverbials from 291 to 855, the connectives from 144 to 301 and the interjections from 112 to 222. German's connectives stay at four, because only a coordinating conjunction can open a German clause without moving the finite verb.

  • More verbs where the pools were thinnest. Korean goes from 740 to 848, German from 520 to 588 and Russian from 512 to 618. Korean grew in every field a story reads — rising, going, arriving, moving, expressing, talking, playing, searching, finding, meeting, making and drinking; German and Russian are held down by their own grammar, which wants one word in the second position (bricht auf is no verb this generator can write) and a past ending on л or лся for the gender agreement to reach it.

  • Half again as many nouns in the five languages that had fewest. Vietnamese, Spanish, Italian, German and Russian held around 1,550 nouns each where Korean, English, Japanese and Chinese hold around 2,730, so a theme could be forty words deep and a paragraph came back to the same one. They hold 2,277 to 2,422 now, every one of the twenty-five themes wider, and the adjectives and actions pools a nickname is built from went from 1,182 and 1,001 to 1,997 and 1,500 across all nine. With them comes the grammar that keeps them honest: the new birds, fish, insects and reptiles are listed as flier, swimmer and crawler so a sardine does not run, the new spellbooks, chalices and sceptres are lifeless, tides, parallaxes and dwarf stars are placeless, and an astronaut and a telescope moved out of space, which the sentence data reads as the place class.

  • nicknameLengthRange widened where the pools did. It reports what a language can produce, and English reaches 33 characters now rather than 31 — Straightening is longer than any action the pool held — and Chinese 9 rather than 8, because 毛茸茸 and eleven more ABB adjectives are three characters where every other Chinese adjective is two. nicknameLengthRange('en', ' ') is [3, 35].

  • Four to six times the verbs, in every language. The pools were a hundred or two per language — sits, lies down, leans and three more for everything a hero does when they rest — so a paragraph of three sentences reached for the same verb twice. Every field of every language is wider now: Korean goes from 210 verbs to 740, English to 914, Japanese to 828, Chinese to 1,235, Vietnamese to 1,356, Spanish and Italian past 1,050, and German and Russian, whose nominative-only shapes take no object, from under 100 to 520. With them come groups every language was missing: what a time of day, the weather and a match each do, what only something made of metal and wood does (it rusts, rattles, jams), what a song does (it rings out, dies away), what is forged and what is sewn, and what a dish does that a drink does not (it sizzles and goes stale; a drink fizzes and goes flat).

  • A Korean adjective asks with -니 on its stem. 작으니?, 어두우니? and 덧없으니? were written where 작니?, 어둡니? and 덧없니? are the question — -으니 is the connective, not the ending — and the verbs had it right all along. The whole Korean paradigm is now spelt by one helper out of a stem and its 해체 form, so the ending is written once.

  • A sentence happens somewhere. nature and space are the place class beside place itself, so The kindness lingered in the lightyear, crawled in the strange comet and at the beautiful meridian were what the class allowed. The seven languages with a place shape now list the nouns of those themes that are no place — a wave, a comet, a lightyear, 파도, 광년, 流星 — under the new placeless trait, and no place or destination is drawn from them.

  • A place takes the preposition it takes. Every English place frame writes in, which is how slides in the balcony and at the quay written as in the quay came out. SentenceLanguageData.placeHeads lists, by preposition, the places where in is the wrong word — on a bridge, at a station, under a sky — and the head is swapped after the noun is drawn. English declares the lists; the other eight write one head for every place, and keep it.

  • A verb may ask of its object what it asks of its subject. VerbGroup.objectTraits and objectWithout are the object's subjectTraits and subjectWithout, and English lists its food as liquid and raw: sips and simmers take a liquid, chews takes none, roasts and slices take something raw. roasted the curry, chewed the fresh syrup and sliced the curry are what one cook group and one eat group allowed; they are three of each now.

  • An amount of money stands beside a verb that handles one. It went with every verb whose object may be an idea, which is how Helena remembers 5,000 dollars and 신수가 500,000원을 기억했어 came out; it now goes with what is found, taken, carried, hidden or lost.

  • A word of a creature theme that is no creature does nothing. myth holds spells and amulets beside dragons and elves, and 마력이 브랜디를 움켜쥐고 and The patient charm chooses the gouge were what the class alone allowed. Every language now lists them under the new lifeless trait, and a lifeless noun takes no verb and no state, so a sentence about a myth is about the creatures.

  • Three more fields, and two stories that need them. lose (loses, drops), meet (meets, greets — takes a person) and talk (chats, with nobody named) join the verb fields, and mishap and visit join the stories: the hero loses what they carried and looks for it, finding it or not; the hero goes to see somebody and they talk. Every language writes talk; lose and meet need an object, so German and Russian tell neither story, and Spanish — whose meet would need the personal a in front of a person — tells no visit.

  • A person in a story sometimes speaks for themselves. A state sentence about a person is now and then a line they say or think rather than a sentence the story narrates — “배고파.”, ‘I am tired.’, 「くたくたです!」 — quoted, in the first person, at a level a person speaks at, never the first sentence and never more than twice in one result. SentenceLanguageData.speech is what the language writes for the first person: nothing in Korean and Japanese, and Tôi, I with am for English; Spanish, Italian, German and Russian would have to conjugate and declare none, so their stories stay narrated, as does every story about an animal.

  • A story may have a second thing, and may move on. Every object phrase of a story was the one thing it is about, and every place was the one it went to, so a paragraph was a cat and a tunnel and nothing else. A story may now name a prop — a tool taken up before the making in craft, something looked at on the stall in errand and picnic, in the room in idle, on the way in stroll and search — drawn from the classes and themes the story allows and written by steps the story can do without. And stroll, outing, search and picnic may go elsewhere partway through, after which that place is the story's. A prop is never the item's noun, and the item never the prop's.

  • A story ends where it ends, and there are five more of them. Seven of the eight stories closed on the hero lying down or falling asleep, so every paragraph ended the same way. A closer is now drawn from what the story allows — a laugh, a thought, a place changing, a rest where a rest is earned — and chores, stash, idle, waking and picnic join the eight: a day at home, a thing carried somewhere and hidden, a hero at a loose end, a place that wakes before the hero does, and a meal eaten where it was found. Out of the house, a telling may also put the hero moving about or the place changing between the steps.

  • A noun is described once, and an object named once is referred to. A story's thing and place took a fresh modifier at every mention, so 반듯한 소쿠리 … 소중한 소쿠리 … 예쁜 소쿠리 was one basket described three ways, and a joined sentence wrote 소시지를 끓여서 소시지를 삼켰다. A noun the result has described is written bare from then on, and the object the sentence before named is referred to rather than named again: left out in Korean, Japanese, Chinese and Vietnamese, it in English, его / её in Russian, a clitic in front of the verb in Spanish and Italian (la comió). The second clause of a joined sentence always refers, a whole sentence about as often as it names its subject again, and German — which declares no object pronoun — names the noun. SentenceLanguageData.objectPronouns is the new field.

  • Added rand_sentence, which generates whole sentences rather than a name or a handle — 여우가 사과를 먹는다., The brave lion runs quietly., Ein blauer Wal schwimmt. All nine languages, and each one writes its own grammar: the particle a Korean noun asks for (사자가 beside 사슴이), the article an Italian noun opens on (l'orso, lo scoglio, il gatto), the second position a German verb never gives up (Am Morgen schläft ein Wolf.).

  • The words of one sentence belong together, and a verb is what decides it. Each group of verbs names the noun classes that can be its subject and its object, and the nouns are drawn from those alone — so 여우가 사과를 먹는다 comes out and nothing eats an idea. No tag was added to any noun: THEME_CLASS reads the classes off the twenty-five themes, which already say what a word is.

  • A language declares the shapes its grammar can carry, the way it already declares a nickname's. German has no object shape and Russian no place, because both would put the noun in a case its own ending has to change for; asking for one falls back to the closest shape the language does have, and with language="all" the ones that can answer are preferred.

  • rand_sentence takes shape for how much the sentence says ("simple", "detailed", "complex"), slots for which parts it carries beside the subject, and include for words it has to contain — include=["brave", "lion", "quietly"] places all three, choosing for brave between the predicate and the modifier by which one leaves room for the adverb.

  • SentenceDetail reports the phrases in order, what each one does, the language and the subject's theme. The particles are not in phrases, so joining them back does not reproduce the sentence.

  • sentence_length_range reports every length a language's sentences can take, and RAND_SENTENCE_LENGTH_MAX is the ceiling min_length / max_length are clamped to. Its own constant rather than RAND_LENGTH_MAX: a sentence is many words where a name, a word and a nickname are at most three, and a ceiling of 40 would cut most of them in half.

  • rand_sentence meets min_length and max_length rather than coming close to them. Every phrase had been budgeted against pools it does not draw from — the verb pools of every group where one sentence uses one group, the nouns of every theme where one phrase draws from one — so each phrase claimed less than its share and a narrow range was missed about once in forty. The themes and the predicate are settled before any phrase is drawn now, and a required word, an invented one and a modifier in the form it agrees in are all measured as what they will actually be.

  • rand_sentence takes sentences, which puts more than one sentence in one result — rand_sentence(sentences=3) is one string holding three of them, and count still says how many strings come back. They are about the same thing rather than three separate draws: the first sentence's subject is the topic, and every sentence after it names that noun again, stands a pronoun where it was, or draws a fresh noun of the same class, opening on a connective about as often as not. min_length and max_length describe the whole string, shared out across the sentences before any of them is drawn. SentenceDetail gained sentences, one entry per sentence, and RAND_SENTENCE_LENGTH_MAX is now a ceiling per sentence rather than per result.

  • rand_sentence takes include_name, which writes a generated person's name where a sentence has room for one — Emma runs quietly., 민준이 조용히 달린다., Celeste è affamata. It narrows the subject to the themes that name people so the sentence has somewhere to put one, and a theme you named yourself still wins, so theme="animal" stays about a lion and carries no name. The name is a bare given name — no article, no modifier, and Korean's particle chosen from its own last character the way any other word's is — and it carries the gender it was drawn for, which is the one thing the generator could not read off it, since a name is in none of the word pools. SentenceDetail gained names, and a named subject reports theme=None.

  • rand_sentence takes type, so a sentence can ask something as well as say it — "statement", "question", "exclamation" and "trailing", one of them, a sequence of them, or "all", decided per sentence. SentenceDetail gained types.

  • What is not asked for is drawn: type is every one of the six, style a level per result, and include_name a coin flip per result. Both drawn options are settled per result rather than per sentence, and a drawn kind is chosen against the room the sentence has — a question is a different shape and a quoted line pays for its marks out of the same budget. A word include named holds its place against a name, a word required into a counted subject keeps its own theme, and a name in a sentence is drawn unsteered, because a length range is what makes rand_name stretch a CJK given name or write a second one.

  • A paragraph keeps its scene, its person and its register: a place and an object the result has put on the page are what a later sentence writes for those slots, a named topic is only ever named again or stood a pronoun for, and the result keeps to the register it opened in. A name never stands in a counted phrase, because 서호 3명 counts somebody's name.

  • "dialogue" and "thought" join SentenceType, and both wrap a sentence in the language's own quotation marks. What is quoted is drawn per line rather than fixed — somebody speaking is as often asking as telling. SentenceQuote and the quote argument override which pair of marks is used.

  • The marks are per language and not close to universal: Japanese writes 「」 and 『』, German opens low and closes high („…“), and Spanish, Italian and Russian reach for guillemets first. Left out on purpose: a speech tag, which would need a verb of speaking no language's pools hold.

  • A question is a shape, not a mark bolted onto a statement. SentenceFrame.mood says what a shape is for, and the four languages whose grammar actually moves declare their own: English writes Does the lion run?, German Läuft ein Wolf?, and Korean changes the ending on the predicate itself. Japanese, Chinese and Vietnamese add a tag — , , không — which is SentenceFrame.tag. Spanish, Italian and Russian declare no question shape at all and get their statement shapes back: ¿El león corre?

  • terminator became terminators, one mark per type, with openers beside it for Spanish, which marks both ends. VerbGroup and StateGroup gained forms, index-aligned with words — which is what lets include="달린다" come out as 달리니?. interjections are what an exclamation opens on, and nothing else.

  • SentenceStyle and the style argument are the speech level the sentence is written at: "plain" (해라체), "casual" (해체), "polite" (해요체) and "formal" (합쇼체). None draws one per result. PredicateForm gained "exclamation", "casual", "formal" and "formalQuestion", and each level falls back along its own chain to the plain statement the words already are. A form pool entry may list its endings with | between them and one is drawn, so 달리니|달리나|달리는가 is one verb written three ways while the pool stays index-aligned with words. An exclamation now uses 해라체's own -구나 / -네 / -군 rather than a statement with a mark after it, and a quoted line is said at a level a person actually speaks at. The other seven languages declare no level and write the same sentence at every one of them.

  • The adverbial pools are about twice the size, and Russian and German gained the shapes their word order leaves room for: Russian from six to nine, German to fourteen, both by letting an adverb or a time open the clause. Neither gained a case its nouns would have to change their own ending for.

  • SentenceSlot gains "quantity" and "money", and SentenceNumeral says how a language writes a number. A quantity is a noun phrase with a number and the counter its kind takes (사과 12개, 12 con mèo); an amount is a number and what the language counts money in (100,000원, 12,000 dollars).

  • SentenceSlot gains "date" and "clock", and SentenceCalendar says how a language writes them: a template per language, month names for the five that use them, and the copula that equates a subject to one. Either can stand as an adverbial or as what the sentence equates its subject to, and the second of those is a copular shape — the only one with neither a verb nor a state in it. The copula is a predicate like any other, taking the form the level and the mood ask for, and CopulaSide says which side of the phrase it is written on. Russian declares no calendar, because it equates with a dash and a dash does not change for a question.

  • Four languages count, and it is the four with a classifier: English, Spanish and Italian would need a plural, and what a plural rule produces from these pools is 12 sadnesses and 12 bacons, because most of these nouns cannot be counted at all. German and Russian do neither, because an amount stands where an object does and both would need a case their nouns change their own ending for.

  • SentenceNumeral.gap is what stands between the digits and what they count. Korean attaches both the counter and the currency to the number — 6개, 300,000원 — as does Japanese and Chinese; Vietnamese, English, Spanish and Italian keep the space. Its own field rather than the language's space, because Korean writes a space everywhere else and still attaches this one.

  • The option reaches the person-name pools, so a program that imports rand_sentence at all carries them. It does not weaken the rule that a nickname is never built from a person name: that is still true, and this is a sentence you asked for.

  • What a language writes for that pronoun is its own, in the data rather than in the generator. English writes it; Korean, Japanese, Chinese, Spanish and Italian write nothing at all, which is what they actually do in a second sentence about the same thing; German and Russian pick by the noun's gender. pronounless is what a language says when its written pronoun cannot stand for a class — English he and she need a gender a job noun does not carry, and 그것, それ, and are inanimate — and a sentence about one names the topic again instead. German's connectives are the coordinating ones alone, because anything else would move its finite verb, which is a shape the frames write.

  • rand_nickname takes slots, which picks the shape rather than leaving it to the frame weights. It names what a shape may put beside the noun, and a shape qualifies when it uses at least one of them — so slots="action" is 웃는사자, slots="part" is 고양이꼬리, slots="none" is the bare noun, and slots=("adjective", "action") asks for a modifier and leaves the kind to chance. A language with no such shape answers with the closest it has, the way a length range too narrow for one already does, and with language="all" the ones that can answer are preferred over the ones that cannot.

  • NicknameDetail gained slots, which reports what each word of words does at the same index: ("adjective", "noun") for 멋진사자. Additive, so nothing that read the detail before has to change.

  • rand_modifier takes kind, which picks between a word for what the value is like and one for what it is doing — rand_modifier(language="ko", kind="action") is 웃는 rather than 멋진. "all", the default, puts both pools in play, which is what it did before.

  • WordSlot, WordSlotOption and ModifierKind are public types now. WordSlot was internal to the datasets; slots and kind are what brought it out.

  • Dropped 104 entries that were a base word with a qualifier stuck on it. A compound earns a place only when it names something the base word does not, and these named the same thing: 민들레꽃 beside 민들레, 杜鹃花 beside 杜鹃, 銀河系 beside 銀河, lá khô and nước ấm beside and nước, мостик beside мост. Every language had its own shape of it — a Korean or Japanese classifier suffix, a Chinese , a Vietnamese state in front of the noun, a Russian diminutive — and tools/parity could not see any of it, because all three packages held the same redundant entry and so agreed. What a base word already answers is now written once. Words that name a different thing stay: 밧줄, 리본 and are three objects, 彗星 is not , and Kneecap is not Knee.

  • Settled the English pools on American spelling — Check, Installment, Ardor, Fervor, Rancor, Harborside, Miter, Miterbox, Pajamas, Plow, Whiskey, Tunneling, Ocher and Bister. They had been a mix of both, which is two conventions rather than one.

  • Rewrote the two pools that had been padded rather than filled. Vietnamese time held eight counting phrases (một ngày, mười ngày) and the full early/mid/late grid over four seasons; fifteen of them are now words a nickname can carry (quá khứ, thế kỷ, giao thừa, rằm). Russian color was half adjectives, which Russian does not nominalise the way Spanish does, so nineteen of them are now colour nouns (кармин, багрянец, синева, смальта).

  • Corrected nineteen more entries the same review missed the first time, found by comparing every pool against itself rather than against the other packages. Seven Korean entries were transliterations cut to the four-character ceiling — 미노타우 for 미노타우로스, 폴터가이 for 폴터가이스트 — and are replaced by creatures whose Korean names fit (반인반수, 물귀신). Four more were invented compounds (유령체, 골렘체, 부적물, 이무기용). The English pools held three words twice in one theme under two spellings (Omelet beside Omelette, Snowplow beside Snowplough, Slipper beside Slippers) and three that are not words (Dusking, Daybreaking, Longingness).

  • A noun with no singular now takes a plural modifier. WordGender gained p — the language's default plural — and fp for a language whose plural inflects for gender as well, so ножницы reads тихие ножницы rather than тихий ножницы, and Spanish writes gafas doradas beside celos dorados. Twenty-three entries across Russian, Spanish, Italian and German were tagged with it; every one of them had been carrying a singular gender it has no singular for.

  • randModifier agrees with the value it decorates. It looks the value up in the language's pools, so rand_modifier("luna", language="es") is luna dorada and rand_modifier("Katze", language="de") is blaue Katze; before this it attached the base form whatever the noun was. A value the pools do not hold has no gender to agree with and still gets the base form.

  • Fixed the German modifiers whose stem loses an e: edel and sauer beside a noun are edle and saure, not edele and sauere.

  • Corrected 69 word-pool entries across all nine languages, found by reading every theme against the language rather than against the other packages. The pools held words that were not nouns (вечереет is a verb, polar and отборочный are adjectives), entries cut short or misspelled (tổng kiểm for a checksum, tiramisu for tiramisù), three mistagged genders (der Graphit, la vodka, год is masculine), nine duplicates the disjoint-theme check could not see because the two spellings differ (除湿器 beside 除湿機, trà atiso beside trà atisô), and coinages invented to fill a theme where the language uses a different word — the German network terms (Torweg, Startlader, Rückrollung) and the Japanese ones, which had been ported from the Korean pools by substituting kanji for words Japanese writes in katakana (駆動子, 実行器, 保存庫). Two entries were removed for what they mean rather than what they are: Vietnamese mây mưa is an idiom for sex, and Korean 뚫어뻥 began as a brand name.

  • Added Russian, and with it every language the name generator knows now has word pools: rand_word, the twenty-five themed generators, rand_modifier and rand_nickname all take the same nine codes rand_name does. Russian declines like German — синий кит, синяя рыба, синее небо — including the reflexive participles, whose ending sits behind a -ся the other rules cannot reach.

  • Added German, which is the first language to decline a modifier that stands in front of its noun: blauer Wal, blaue Katze, blaues Haus. rand_nickname draws the noun ahead of its turn so the gender is in hand before the modifier is chosen. language="de" across all twenty-five themes, around 1,600 nouns with their gender, 110 words for what a noun is like and 91 for what it is doing.

  • Added Italian, on the same agreement the Spanish pools brought in — language="it" across all twenty-five themes, around 1,600 nouns with their gender, 111 words for what a noun is like and 96 for what it is doing.

  • Added Spanish to the word pools, and with it the agreement a language that inflects needs. language="es" reaches all twenty-five themes: around 1,600 nouns, 116 words for what a noun is like and 100 for what it is doing. A noun carries its gender (gato:m luna:f) and agreement lists the endings a modifier changes, so gato dorado and luna dorada both come out right without either form being stored twice.

  • Added Vietnamese to the word pools, so rand_word, the twenty-five themed generators, rand_modifier and rand_nickname all take language="vi". Around 1,650 nouns, 120 words for what a noun is like and 110 for what it is doing. Vietnamese was left out until now because its modifier follows the noun (mèo xanh) and its possessive runs the other way (đuôi mèo); the frames a language declares carry both, so no setting had to be invented for it. rand_modifier reads the same frames and attaches on the side the language uses.

  • Added eight more word themes, and a generator for each: weather, space, time, emotion, body, clothing, tool and drinkrand_weather, rand_space, rand_time, rand_emotion, rand_body, rand_clothing, rand_tool and rand_drink. Twenty-five themes now, and around 700 more nouns per language.

  • Five of them are finer cuts of themes that already existed, so the words moved rather than being copied — nature handed the rain to weather and the moon to space, concept handed the seasons to time and the feelings to emotion, object handed the hammer to tool, and food handed the coffee to drink. A word still belongs to exactly one theme, which is what keeps the reported theme unambiguous; rand_nature and rand_concept return a narrower slice than they did.

  • realism now decides which themes theme="all" spans in rand_nickname. color, finance and tech are words a modifier cannot sit in front of without the result reading as a joke — BraveInvoice, 멋진대출 — so at the default realism="real" a nickname spans the other fourteen, and "mixed" or "invented" puts them back. Naming one of them still works at any realism; only what "all" means changed.

  • Added three word themes and a generator for each: color (rand_color), finance (rand_finance) and tech (rand_tech). That is seventeen themes rather than fourteen, and around 260 more nouns per language — colours from Crimson to Ocher, the vocabulary of money from Ledger to Escrow, and of computing from Server to Subnet. WORD_THEMES and WordTheme list them, and rand_word(theme="color") reaches them like any other.

  • Replaced 263 more word-pool entries that were grammatical compounds nobody uses. The Japanese pools held most of them: food alone had 44, where 棒麺麭, 三日月麭 and 環麭 were attempts at baguette, croissant and bagel written with — they are バゲット, クロワッサン and ベーグル now. object, gem, product and music were the same story, and Korean place and nature had a run of real words with a redundant syllable bolted on (대로변, 햇살빛, 등대탑). Chinese needed the fewest. Every replacement is a word the language actually has, none collides with another theme, and all of them fit the lengths the pools already held, so no length range moved.

  • Three English entries went with them: Landrover was a trademark, and Ricecooker and Pressurepot were two words run together.

  • Fixed 66 entries across the Japanese, Chinese and Korean word pools that were not words. Most were a real word with its tail cut off to fit the pool's own character limit: 丸太小 for 丸太小屋, 音部記 for 音部記号, 提拉米 for the front of 提拉米苏, 海市 for the front of 海市蜃楼, and Korean job titles such as 공인중개 and 고생물학 missing their suffix. The Japanese place pool held the worst of it and was gone through entry by entry — 玄関間, 待合間, 硝子室, 農家地 and 納屋庭 were not Japanese at all, and 門楼 was the Chinese word order for 楼門. Where the full form would not fit the language's existing word lengths, a different real word took the slot, so word_length_range and nickname_length_range report what they did before.

  • Breaking: style is realism, and it takes "real", "mixed" or "invented" instead of an int from 0 to 100. style=0 becomes realism="real" (still the default, so it can be dropped), style=100 becomes realism="invented", and anything in between becomes "mixed". The decision was always a coin flip per part, so the numbers between 0, 50 and 100 promised a precision that was not there. The new type is exported as RandRealism.

  • Nicknames are built from shapes the language itself declares, which adds two of them. A word for what the noun is doing now takes the front slot on its own (웃는사자, StudyingFox, 踊るキツネ, 奔跑的狮子), and Korean, Japanese and Chinese gained a possessive shape (사자의눈물, ライオンの涙, 狮子的眼泪). Japanese and Chinese had no two-noun shape at all before, because a bare compound does not read in either; through の and 的 it does.

  • Breaking: NicknameDetail.words holds the words and nothing else, so joining them no longer reproduces nickname where a shape put a particle between two of them — 사자의눈물 reports ("사자", "눈물"). Read nickname for the finished string.

  • nickname_length_range widened again for the two languages that gained a shape: "zh" is (2, 8) rather than (2, 5), and "ja" (1, 14) rather than (1, 11).

  • The words a nickname or rand_modifier puts in front of a noun are split by what they say about it, and the half that says what the noun is doing grew from a handful to a pool of its own. English went from 214 decorating words to 318, Korean from 192 to 293, Japanese from 163 to 260 and Chinese from 164 to 265, so rand_modifier("Fox") now reaches StudyingFox as readily as MistyFox. Nothing about either function's surface changed.

  • nickname_length_range moved with those pools: "ko" is (1, 13) rather than (1, 12) and "en" is (3, 31) rather than (3, 30), because the longest action word is longer than the longest adjective. A caller who pinned max_length to the old number keeps the nicknames it allowed.

  • Every word theme holds roughly twice the words it did. All fourteen gained at least fifty entries per language, so the smallest pools are no longer the ones that shape the output: sport went from 46 to about 115, vehicle from 43 to about 113, and product from 36 to about 105. Each language now draws from around 1,900 nouns rather than 900, which roughly doubles what rand_word, the fourteen themed generators and rand_nickname can produce.

  • The person-name pools grew with them. The seven languages that had around 45 entries per pool now hold roughly twice that — Italian, German, Spanish and Russian sit near 95 for each of given names and surnames, Vietnamese near 80, and Japanese and Chinese surnames at 95 with their given names at about 75. English and Korean, already the largest, gained too: English is near 235 per pool and Korean holds 272 male and 259 female given names. Russian patronymics went from 18 to 48, and the CJK syllable pools that build invented names grew alongside. Around 3,750 name parts in total, up from about 2,200.

  • Fixed the Italian surname De Luca, which was two surnames. The pools separate entries by whitespace and spell a space inside one as _, and this entry was written with a real space — so rand_name(language="it") could hand back Marco De or Marco Luca. It is one surname now.

  • An invented word now carries a gender, so the article and the modifier beside it agree. rand_sentence(language="es", realism="invented") wrote Hoy, nuedeiguion tiembla. with no article at all and Chauquuel denso with the adjective in whatever form the pool stored, because gender was read out of noun_gender, which holds the pool words and nothing else. gender_rules is what a language now says about a word it has never seen — ordered (ending, gender) rules, the shape agreement and the articles already have. rand_modifier reads them too, so rand_modifier("casa", language="es") is casa cálida.

  • An invented word is written the way the pool it stands in for is written. German capitalizes its nouns and nothing else, so it writes them capitalized in the pool rather than setting capitalize — and rand_word(language="de", realism="invented") came back mütert beside the Klugheit of the pools.

  • An invented word is the length it was asked for. It used to be drawn at random and re-rolled until something fit, which missed a third of the exact lengths English, Spanish, Italian, German and Russian were given: the shortest and the longest word a template can spell need every piece to come out that way at once. Each piece is now chosen from the lengths that leave the rest of the word able to land in the range, so only the lengths a template cannot spell at all come back wrong.

  • rand_name keeps max_length. A range no draw landed inside was answered by padding the name with a whole extra given name, so rand_name(language="de", include_surname=False, min_length=10, max_length=10) handed back Cornelia Claudia — sixteen characters for a ten-character ask. Padding stops at the maximum now, and a range the twelve draws all missed is answered by drawing each part from the lengths that can still reach it: that call writes Maximilian, and rand_name(language="en", max_length=10) writes Fiona Reed. Where the pools cannot reach the range at all, the name comes back short of the minimum rather than past the maximum — max_length is the bound a field limit or a column width is holding to.

  • name_length_range reports what the pools actually hold. length_spec was a typical span rather than a measured one — en declared given names of four to eight characters over a pool that runs from three to ten — so the default range called real names too long and the generator spent its twelve draws re-rolling them away. Every language's spans are measured now, the joiner moved out of them and into name_length_range itself, and a test holds both to the pools. The reported ranges move with it: name_length_range("en") is (7, 21) rather than (8, 16), name_length_range("en", False) (3, 10) rather than (4, 8), and name_length_range("ko") (2, 3) rather than (3, 3) — Korean writes two-syllable names like 김솔, which given_len_weights has always asked for and the range had been shutting out. A caller who pinned min_length / max_length themselves sees nothing change.

  • A paragraph reads as a paragraph. Every kind of sentence was one in six and a run of the same one was likely on top of that, so rand_sentence(sentences=10) came out as ten questions, ten exclamations with an interjection in front of each, or ten quoted lines with nobody answering. The kinds are weighted now — a statement is far and away the most likely, a line somebody says next, a question or an exclamation rarest — and a kind or a mark the sentence before it already used is worth less each time it comes round again.

  • A scene of speech has prose in it. A quoted register used to be quoted lines and nothing else, which is one person saying ten things in a row. It carries statements between the lines now, and what it may not carry is a narrated question, which would be a third voice in a scene that has two. The narrated register is unchanged: prose about a line never becomes one.

  • A paragraph stops repeating itself. A person is named and then left alone rather than named in half the sentences; a verb group is spent before it starts over, so four lines no longer close on 식습니다 three times; a fresh subject usually comes from the topic's own theme rather than from anywhere in its class; and no two sentences of one result open on the same connective or interjection, nor two in a row on anything much.

  • A name is the one subject English can say he about. pronounless kept he and she away from every person, which is right for the locksmith — nothing says which of the two — and wrong for Philip. English declares both now, a name carries its gender in every language rather than only where words agree, and a pronounless class can take a gendered pronoun when it has a gender to choose by. A language that writes none is unchanged: Korean drops the subject rather than saying 그것 about somebody.

  • A connective claims something, and the claim has to be true. 그러므로 금빛 하이볼이 식죠? after a sentence about a pretzel is a consequence of nothing. Every connective is now tagged by what it says about the sentence in front of it — one more thing, time passed, against that, because of that — and only the last of those can be false, so it is written only where the two sentences are about the same thing and this one tells rather than asks. A language declares the kinds it can write: German has none for time passed, because an adverb in the first position moves its finite verb.

  • rand_sentence takes tense"present" or "past", drawn per result when left out, so a paragraph is told in one tense from start to end. Every language writes the past the way its own grammar does, out of forms the pools hold rather than a rule guessing at them: The lion ran. and Did the lion run?; 달렸다, 달렸어요 and 走った at every speech level; Берёза тянулась agreeing with its subject; Spanish and Italian keeping an adjective and moving the copula (era, estaba); Chinese after the verb and Vietnamese đã before it. A word include named in its statement form is translated into the past by its position, the way it already was into a question, and the time adverbials follow: yesterday opens a past sentence and tomorrow a present one. SentenceDetail gained tense.

  • A result of several sentences tells a story. sentences=3 used to be three sentences about the same noun, and it is now one sequence of things that happen to one hero, in an order that holds together: 낙타가 터미널로 갔다. 고요한 터미널에서 신선한 냉면을 봤다. 냉면을 꺼내고 집에 다다랐다. 한낮에 냉면을 먹었다. Eight stories — errand, meal, search, outing, craft, stroll, evening, passage — are written out as steps, each saying what has to be true of the hero before it and what is true after, so nobody eats before they have something to eat and a hero who went out comes home before going to sleep. The verb of each sentence comes from the field its step names, the thing and the place stay the same throughout, home is home, and the day only moves forward. story names one; left out, it is drawn from the stories the language can tell about the subject asked for, and German and Russian, which carry no object, tell the four with nothing in the hero's hands. SentenceDetail gained story, and its theme is the hero's.

  • Two neighbouring steps are sometimes one sentence, the second clause written without its subject: 사원에서 멈춰서고 천천히 집에 들어섰다, The broker heads back to the cottage and leans warily. Each language declares how it joins two clauses — Korean's -고, Japanese's -て, and, y, и, ,然后 — and German declares nothing. The join is paid for out of the length range like everything else, so a narrow range writes two sentences where a wide one writes one.

  • A modifier is chosen for the noun it describes. The modifiers and the manners are grouped by the kind of noun they fit, and a group may narrow itself to themes, so a drink is hot or fragrant, a mechanic is patient, and 맑은 정비사 and the patient tea are gone. A place quietens slowly and nobody quietens keenly.

  • destination is a new SentenceSlot: where the subject is going. Only a verb that goes somewhere takes one (heads to, 향한다, 들어선다), so leaves to the market never comes out; it is drawn from the place theme alone, so nobody walks to Pluto; and Korean chooses / 으로 by the word in front the way it already chose / . German and Russian declare no destination shape, for the same reason they declare no object and no place.

  • A story that lands outside min_length / max_length is told again, and the closest telling is kept. The sentences are drawn one after another against a range shared out between them, and a run of short ones left the last a gap no shape could fill — three Korean sentences at forty to sixty characters fell short once in a hundred and twenty.

  • A caller who names type gets those kinds, "all" included; a story told on its own terms is prose, and writes statements with an exclamation or a trailing end where a step allows one.

  • Korean reads as prose, not as somebody looking for a nod. 해체 and 해요체 asked and told with the same pool, and half the statements closed on -지 or -죠 — an ending that invites the listener to agree. A statement now closes on 달려 and 달려요, and the two endings are drawn only in a question, through the new casualQuestion and politeQuestion forms.

  • A sentence says when once. 잠시후 한낮에 약국이 밝아왔다 opened on a temporal connective and named a time as well; a sentence that opens on one carries no time now, and the second clause of a joined sentence inherits that from its first. 한낮에 and 정오에 were two phases of the day and are one, so the day no longer stands still between them; the same duplicate went out of the English, Japanese, Chinese, Vietnamese and Spanish pools.

  • A story never speaks of a habit. 요즘 수의사가 마당으로 내려간다 put a habit in a story of one afternoon. every day, sometimes, these days and their kin moved into SentenceTimes.habitual, which a sentence on its own still draws from and a story never does.

  • A story names its place every other line, at most. 운동장으로 달려가서 운동장에서 날아오른다. 운동장에서 기웃거린다. 운동장에서 뒹군다. A clause that follows one that named the place leaves it out, so the place is one place without being said in every sentence.

  • Korean data: 날아오른다 is a creature's alone, a person no longer flies; 기댄다 needs something to lean on and left the resting verbs; 조립한다 and 깎는다 take an object, a tool or a vehicle and no longer a song; 잘익은 left the food modifiers and 가느다란 the body ones.

  • The sentence after an opening scene keeps the story's nouns. evening opens on the place changing, and the hero's first sentence after it drew a fresh destination with a modifier on it — 넓은 광장에 다다르고 where 집에 was the step — because the nouns a story pins travelled only with a topic to follow. They reach the first sentence about the hero now.

  • A class too wide is narrowed to themes on the subject's side too. subjectThemes on a verb group or a state group is what objectThemes was for the object: 익는다 is a thing food does and a drink does not, 울린다 and 잦아든다 are a song's and a spoon's are 흔들린다 and 굴러간다, 깊어진다 is a season's and not a match's, 맵다 is a dish's, 짙다 a colour's and 어렵다 a thought's. Korean's groups are split along those lines, with a group of what a song does and is, of what an event is and of what a colour is added, and the holdable-object verbs — look, find, take, carry, hide, make, tend, sell, buy — no longer take a song. A theme narrowed out of one group is accepted by another of the same field, and the suite asserts it.

  • A noun may carry a trait, and a verb may ask for one. Both a fish and a sparrow are animal, and no theme tells them apart; 우럭이 날아오른다 was the result. A language now lists which of its nouns are a flier, a swimmer or a crawler in SentenceLanguageData.traits, and a verb group asks for one with subjectTraits or rules some out with subjectWithout: 날아오른다 takes a flier, 헤엄친다 a swimmer, 기어간다 a crawler, and 달린다 and 걷는다 take anything that neither swims nor crawls. A noun listed nowhere has no trait and passes any group that asks for none, so the lists name the exceptions. The check reaches the subject a later sentence stands a pronoun for or drops, because a fish left unsaid is still a fish, and the suites walk every noun of every theme to assert none lost a field. Every language carries the lists, and every language's one move group is now five: legs, anything, swim, fly and crawl, so the newt crawls, ein Reiher flog and дельфин плыл come out of the same rule as the Korean.

1.1.0 (2026-09-02)

  • Breaking: random_name and random_nickname are now rand_name and rand_nickname. The old names are gone; there are no aliases.
  • Breaking: random_name_details and random_nickname_details are gone entirely. rand_name and rand_nickname take output="detail" instead and return the same list[NameDetail] / list[NicknameDetail], with @overload carrying the return type so a checker knows which one it got.
  • Breaking: the fourteen nickname themes are their own generators now. rand_word takes a theme, and rand_animal, rand_object, rand_nature, rand_plant, rand_gem, rand_concept, rand_myth, rand_job, rand_music, rand_place, rand_food, rand_sport, rand_vehicle and rand_product are that generator with the theme already chosen. word_length_range reports what the pools hold, and rand_nickname draws from those pools rather than owning them.
  • Breaking: NicknameLanguage, NicknameLanguageOption, NicknameTheme, NicknameThemeOption, NICKNAME_LANGUAGES and NICKNAME_THEMES are WordLanguage, WordLanguageOption, WordTheme, WordThemeOption, WORD_LANGUAGES and WORD_THEMES. They describe the words, and the words are no longer only a nickname's business.
  • Breaking: three groups of nickname arguments are gone, all for one reason — decorating a string was never a thing about nicknames. unique_suffix, unique_suffix_length, unique_suffix_separator and unique_suffix_charset are rand_suffix; include_modifier is rand_modifier; and base_word is rand_modifier on a word you already have, which also takes with it the one argument whose default was None rather than "all"language now defaults to "all" like every other one. NicknameDetail.suffix, NICKNAME_SUFFIX_LENGTH_MAX and NICKNAME_SUFFIX_CHARSET go too, nickname_length_range loses its include_modifier argument, and min_length / max_length now describe the whole nickname with nothing excluded from them.
  • Breaking: NAME_COUNT_MAX, NAME_LENGTH_MIN / MAX, NICKNAME_COUNT_MAX and NICKNAME_LENGTH_MIN / MAX are RAND_COUNT_MAX and RAND_LENGTH_MIN / MAX, one set for every generator. The name length bound goes from 30 to 40 as a result.
  • Breaking: the randino.affix package is randino.decorate, which is what the three functions in it now do between them. Everything it holds is still re-exported from randino itself, which is where it is meant to be imported from.
  • Added the decorators. rand_suffix and rand_prefix attach a random token to a str, or to every str in a list — a fresh one per value — with length, separator and charset; rand_modifier attaches a word out of the pools instead, so rand_modifier("Owl") is "MistyOwl", and picks the language off the value's own script when none is given. All three work with no value at all, handing back the token or the word they would have attached: rand_suffix() is "nVtRC".
  • Added AFFIX_LENGTH_DEFAULT, AFFIX_LENGTH_MAX, AFFIX_SEPARATOR_DEFAULT and AFFIX_CHARSET, the bounds and defaults rand_suffix and rand_prefix are clamped to.
  • Added RandOutput for the new output argument, and WordDetail, which rand_word(output="detail") returns.
  • count, style, min_length / max_length, starts_with, unique and output are the same arguments on every generator now, resolved and applied in one place rather than once per generator. Nothing about them changed from the outside; a new generator gets all of them by construction.

1.0.0

2026-09-01

  • The first release of the Python package, ported from the JavaScript one.
  • random_name and random_name_details generate person names in 9 languages, with the English pronunciation of each.
  • random_nickname and random_nickname_details generate nicknames in 4 languages across 14 themes.
  • name_length_range, name_supports_middle_name, name_supports_roman and nickname_length_range report what a language can produce before you ask it to.
  • No dependencies. Requires Python 3.10 or newer, and ships a py.typed marker.