Dev.to WebDev ๐Ÿ›  Dev ๐Ÿ‘ 0 ๐Ÿ“– 7 min read

How Korean naming houses use birth elements, and how I built a simplified version in the browser

I'm the developer of this small free tool, so I'll say that up front. It is a Korean name generator that reads the Five Elements in a birthday and suggests three names with Hanja. This post covers the naming idea behind

I'm the developer of this small free tool, so I'll say that up front. It is a Korean name generator that reads the Five Elements in a birthday and suggests three names with Hanja. This post covers the naming idea behind it and the parts that were fun to build. It is for entertainment, and it is a simplified version of the traditional practice.

Try it here if you want to follow along: Korean Name Generator. It is free, needs no sign-up, and runs in your browser.

How naming houses use birth elements

In Korea, some families visit a naming house (์ž‘๋ช…์†Œ) before choosing a baby's name. The people there start from the baby's saju (์‚ฌ์ฃผ), the "four pillars" of birth year, month, day and hour. Each pillar is two characters, a heavenly stem and an earthly branch, and every character maps to one of five elements: wood, fire, earth, metal, water.

Count the elements across the pillars and you usually get an uneven spread. One element may be absent or thin. The common idea is to pick a name whose characters carry that thin element, so the name "fills the gap".

Names in Korea are usually written in Hangul but also have a Hanja spelling. Each Hanja carries a meaning, and many have a radical that points to an element. ๆž— (forest) has the wood radical. ๆฑŸ (river) has the water radical. ้Žฌ (bright) has the metal radical. This is called ์ž์›์˜คํ–‰ (resource element). So the loop is simple to state:

  1. Compute the pillars from the birthday.
  2. Count the five elements.
  3. Find the weak one.
  4. Choose Hanja whose radical belongs to that element.
  5. Check that the sound also works.

Naming houses weigh many more things: strokes, the family's generation character, the parents' wishes, and a judgment about which element helps the person most (์šฉ์‹ ). I do none of that last part. I only fill the thinnest element, and the page says so.

Step 1: Counting the elements

The calendar math (converting a Gregorian date to pillars) is shared with another small tool of mine, so the name logic starts from the counts. If the birth hour is unknown, the hour pillar is empty and the count uses six characters instead of eight.

The weak-element rule is short:

/* Missing element = an element counted 0; otherwise the smallest count.
   Ties: first the element that feeds the Day Master (์ธ์„ฑ), then woodโ†’fireโ†’earthโ†’metalโ†’water. */
function missingElement(c,dmElem){
  var min=Math.min.apply(null,c),tied=[];
  for(var k=0;k<5;k++)if(c[k]===min)tied.push(k);
  var mom=parentOf(dmElem);
  return tied.indexOf(mom)>=0?mom:tied[0];
}

The tie-break matters because ties happen often with only six to eight characters. I let the element that feeds the Day Master win, since that is a common reading of what supports the person, and then a fixed order so the answer is stable. This is a design decision, not a ground truth. The result page shows the five counts as bars so you can see what the tool saw.

Step 2: Unknown birth time

Most people outside Korea do not know their birth hour. I made "unknown" the default instead of forcing a guess. With the hour missing, the tool counts six characters and shows a small badge: adding the hour can change the result. That is honest about what the input supports, and it keeps the form short.

Step 3: Sound elements, and where schools disagree

Hanja radicals give the "meaning element" of each character. Korean naming also looks at the initial consonant of each syllable, the ๋ฐœ์Œ์˜คํ–‰ (sound element). Here the schools do not agree.

The mapping I use follows the ์šดํ•ด๋ณธ reading, the majority convention in naming practice:

  • ใ„ฑ ใ…‹: wood
  • ใ„ด ใ„ท ใ„น ใ…Œ: fire
  • ใ…‡ ใ…Ž: earth
  • ใ…… ใ…ˆ ใ…Š: metal
  • ใ… ใ…‚ ใ…: water

The ํ•ด๋ก€๋ณธ reading swaps ใ…‡ ใ…Ž and ใ… ใ…‚. I did not try to settle that. I picked the majority convention, and the About section of the page states that another reading exists. If you know this area better than I do, I would like to hear which side you would pick and why.

In code the table is a pair of arrays indexed by the Hangul initial, decoded from the Unicode syllable block:

var CHO=["ใ„ฑ","ใ„ฒ","ใ„ด","ใ„ท","ใ„ธ","ใ„น","ใ…","ใ…‚","ใ…ƒ","ใ……","ใ…†","ใ…‡","ใ…ˆ","ใ…‰","ใ…Š","ใ…‹","ใ…Œ","ใ…","ใ…Ž"];
var CHO_ELEM=[0,0,1,1,1,1,4,4,4,3,3,2,3,3,3,0,1,4,2];
function jamo(s){var c=s.charCodeAt(0)-0xAC00;return {cho:Math.floor(c/588),jung:Math.floor(c%588/28),jong:c%28};}

A Hangul syllable is 0xAC00 + (initial * 588) + (vowel * 28) + final, so no lookup table of syllables is needed. The tool then prefers name pairs where neighboring sounds feed each other (wood to fire to earth to metal to water) and penalizes pairs where one controls the other.

Step 4: How I chose the Hanja table

A name generator is only as good as its character list, and Hanja is a large field. I wanted a small table I can defend instead of a scrape.

  • Source: the Unicode Unihan database (version 18.0.0), which is public. I used the radical field (kRSUnicode) for the element, the Korean reading field (kHangul) for the sound, and kDefinition as a reference for English meanings.
  • Name-use filter: Korea restricts which Hanja may be used in registered names. Unihan marks these in kKoreanName (additional characters, by announcement year) and kKoreanEducationHanja (the 1,800 education characters). I only kept characters found in one of those two fields.
  • Radicals only when clear: wood (ๆœจ, ่‰น, ็ซน, ็ฆพ), fire (็ซ, ็ฌ), earth (ๅœŸ, ๅฑฑ, ็”ฐ), metal (้‡‘, ็މ), water (ๆฐด, ๆฐต, ้›จ, ๅ†ซ). Radicals like ๆ—ฅ, ็Ÿณ and ๆ‰Œ are argued over, so I left them out instead of picking a side quietly.
  • Common syllables first: I started from syllables people use in given names, which keeps results from looking odd.

The final table has 264 characters: 55 wood, 33 fire, 38 earth, 72 metal, 66 water. Each row looks like this:

{"hanja":"่“ฎ","hangul":"์—ฐ","element":0,"basis":"่‰น","meaning":"lotus","tags":"F","src":"edu"}

basis is the radical, so the result card can say why a character was chosen. tags marks a typical gender feel (F, M or N for neutral), which is how the optional "female / male / either" input filters the list. The file header says it is generated by a script, so I fix the candidate list there and regenerate instead of editing rows by hand.

The English glosses are short and based on the Unihan definitions. Some are loose. If one looks wrong to you, tell me.

Step 5: Avoiding famous names

If someone's birthday produces the full name of a well-known singer or actor, that is awkward and a bit misleading. So there is a list of widely known full names (names only, taken from public wikis, no photos or descriptions). Any surname plus given-name combination that matches the list is skipped:

if(isFamous(full))return;

Step 6: Same birthday, same names

Random output has a problem for sharing: refresh and the names change. I wanted the same birthday to give the same three names every time, so the generator seeds its random numbers from the input. A hash turns the input string into a seed, and a small generator makes the sequence:

var rnd=rng(seedOf([inp.y,inp.m,inp.d,hb,g,inp.surname||"auto"].join("|")));

seedOf is FNV-1a and rng is mulberry32, both a few lines. Candidates are shuffled with this seeded random source, then sorted by a score (common names and natural syllable positions score higher, sound clashes score lower), and each Hangul name keeps its highest-scoring Hanja pair. Because every step is deterministic, you and a friend with the same input see the same result. There is no hidden state.

Step 7: Nothing leaves the browser

There is no server-side calculation. The pillars, the picking, the romanization and the share-card drawing all run in your browser. The birthday is not put in the URL, local storage or cookies. The page does send one small anonymous beacon with an event name (such as "view") and the referrer, so I can see whether anyone opens it. The birthday is not part of it.

Romanization follows the Revised Romanization of Korean for given names, syllable by syllable, with a hyphen only where letters could be misread. Surnames use the common spellings (Kim, Lee, Park) instead of the formal forms (Gim, I, Bak), because that is how people write them.

Limits, again

  • It is for entertainment. It is a simplified version of Korean naming practice, not professional advice.
  • It does not judge which element suits a person most. It fills the thinnest one.
  • Sound-element schools differ, and I used one of them.
  • The Hanja table is small on purpose, so many valid names are not in it.

The page is available in English, Japanese, Spanish, Portuguese and Indonesian, using the same engine and table.

If you want to look at your own result, here is the tool again: devjar.dev/lab/korean-name. Feedback on the character meanings or the sound-element choice is welcome in the comments.

I also make a saju app for Android: Starlit Alley.

This post was written with AI assistance.

๐Ÿ“ฐ Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes โ€” full credit and traffic to the original publisher.