<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: WordForge</title>
    <description>The latest articles on DEV Community by WordForge (@wordforge_jp).</description>
    <link>https://dev.to/wordforge_jp</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4208634%2Fc54767ef-5178-42e2-8d97-6d76e1be0013.png</url>
      <title>DEV Community: WordForge</title>
      <link>https://dev.to/wordforge_jp</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/wordforge_jp"/>
    <language>en</language>
    <item>
      <title>Scoring English word rarity by frequency alone squashes advanced words into one tier: a test with 70 words from our production API</title>
      <dc:creator>WordForge</dc:creator>
      <pubDate>Mon, 26 Oct 2026 11:59:04 +0000</pubDate>
      <link>https://dev.to/wordforge_jp/scoring-english-word-rarity-by-frequency-alone-squashes-advanced-words-into-one-tier-a-test-with-18gk</link>
      <guid>https://dev.to/wordforge_jp/scoring-english-word-rarity-by-frequency-alone-squashes-advanced-words-into-one-tier-a-test-with-18gk</guid>
      <description>&lt;p&gt;Hi, I'm &lt;strong&gt;Hatsuki&lt;/strong&gt;. I'm building &lt;strong&gt;WordForge&lt;/strong&gt;, a browser game where you build English words from letter tiles and battle with them as cards.&lt;/p&gt;

&lt;p&gt;Every word you play gets one of six rarity tiers: &lt;strong&gt;N / C / R / SR / UR / LG&lt;/strong&gt;. Rarer words score more, from 1x for N up to 8x for LG. The lookup checks an inflection table first, then a CEFR level list, then word frequency (a Zipf score).&lt;/p&gt;

&lt;p&gt;This post isn't about how that pipeline works. It answers one question: &lt;strong&gt;what happens if you skip the CEFR list and rank difficulty by frequency alone?&lt;/strong&gt; I ran 70 real words through the production API to find out. If you're building a word game or a learning app and want to estimate word difficulty automatically, I hope this helps.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I did
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Hand-picked 70 English words, from very basic to very advanced (roughly CEFR A1 to C2). The picks are my own.&lt;/li&gt;
&lt;li&gt;Sent each word to the production dictionary endpoint &lt;code&gt;POST /api/dictionary/lookup&lt;/code&gt; and recorded the &lt;code&gt;rarity&lt;/code&gt; the game actually assigns, plus the &lt;code&gt;frequency&lt;/code&gt; (Zipf score).&lt;/li&gt;
&lt;li&gt;Ran the same Zipf scores through a &lt;strong&gt;frequency-only rule&lt;/strong&gt; to get a hypothetical rarity.&lt;/li&gt;
&lt;li&gt;Compared the two.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://word-forge.replit.app/api/dictionary/lookup &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'content-type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"word":"ubiquitous","direction":"en-ja"}'&lt;/span&gt;
&lt;span class="c"&gt;# =&amp;gt; {"definitionJa":"至る所にある","frequency":3.42,"rarity":"super_rare", ...}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(&lt;code&gt;definitionJa&lt;/code&gt; is the Japanese gloss, because the game is aimed at learners in Japan.)&lt;/p&gt;

&lt;p&gt;The frequency-only rule:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Zipf&lt;/th&gt;
&lt;th&gt;≥ 5&lt;/th&gt;
&lt;th&gt;≥ 4&lt;/th&gt;
&lt;th&gt;≥ 2.5&lt;/th&gt;
&lt;th&gt;≥ 1.35&lt;/th&gt;
&lt;th&gt;≥ 1.12&lt;/th&gt;
&lt;th&gt;below&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Rarity&lt;/td&gt;
&lt;td&gt;N&lt;/td&gt;
&lt;td&gt;C&lt;/td&gt;
&lt;td&gt;R&lt;/td&gt;
&lt;td&gt;SR&lt;/td&gt;
&lt;td&gt;UR&lt;/td&gt;
&lt;td&gt;LG&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A Zipf score of 0 (no data) maps to N, and words of 3 letters or fewer are capped at SR.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Frequency-only baseline used for the comparison&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;rarityByFrequency&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;word&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;zipf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;zipf&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;N&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// no data: likely a typo or a made-up word&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="nx"&gt;zipf&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;N&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nx"&gt;zipf&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;C&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nx"&gt;zipf&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mf"&gt;2.5&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;R&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nx"&gt;zipf&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mf"&gt;1.35&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SR&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nx"&gt;zipf&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mf"&gt;1.12&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;UR&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;LG&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;word&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;UR&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;LG&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SR&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Result: 42 of 70 words changed tier
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Words&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Same tier in both&lt;/td&gt;
&lt;td&gt;28&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Actual tier higher (pushed up by the CEFR list, etc.)&lt;/td&gt;
&lt;td&gt;41&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Actual tier lower&lt;/td&gt;
&lt;td&gt;1 (&lt;code&gt;apple&lt;/code&gt;: C by frequency, N in the game)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;With frequency alone, almost every advanced word lands in R (Zipf 2.5 to 4).&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Word&lt;/th&gt;
&lt;th&gt;Zipf&lt;/th&gt;
&lt;th&gt;Frequency only&lt;/th&gt;
&lt;th&gt;Actual&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;aesthetic&lt;/td&gt;
&lt;td&gt;4.02&lt;/td&gt;
&lt;td&gt;C&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;LG&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;quintessential&lt;/td&gt;
&lt;td&gt;3.03&lt;/td&gt;
&lt;td&gt;R&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;LG&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;juxtaposition&lt;/td&gt;
&lt;td&gt;2.96&lt;/td&gt;
&lt;td&gt;R&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;LG&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;sycophant&lt;/td&gt;
&lt;td&gt;2.20&lt;/td&gt;
&lt;td&gt;SR&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;LG&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;resilient&lt;/td&gt;
&lt;td&gt;3.50&lt;/td&gt;
&lt;td&gt;R&lt;/td&gt;
&lt;td&gt;UR&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ephemeral&lt;/td&gt;
&lt;td&gt;2.99&lt;/td&gt;
&lt;td&gt;R&lt;/td&gt;
&lt;td&gt;UR&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;mundane&lt;/td&gt;
&lt;td&gt;3.43&lt;/td&gt;
&lt;td&gt;R&lt;/td&gt;
&lt;td&gt;UR&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ubiquitous&lt;/td&gt;
&lt;td&gt;3.42&lt;/td&gt;
&lt;td&gt;R&lt;/td&gt;
&lt;td&gt;SR&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;integrity&lt;/td&gt;
&lt;td&gt;4.22&lt;/td&gt;
&lt;td&gt;C&lt;/td&gt;
&lt;td&gt;SR&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;sustainable&lt;/td&gt;
&lt;td&gt;4.19&lt;/td&gt;
&lt;td&gt;C&lt;/td&gt;
&lt;td&gt;R&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Almost all of the upper-intermediate and advanced vocabulary sits inside the Zipf 2.5 to 4 band. So under a frequency-only rule you get &lt;strong&gt;lots of R and almost no SR, UR or LG&lt;/strong&gt;. In game terms, knowing hard words doesn't pay off.&lt;/p&gt;

&lt;p&gt;Going the other way, the only word that reached LG on frequency alone was &lt;code&gt;defenestrate&lt;/code&gt; (to throw someone out of a window, Zipf 1.04). Words below Zipf 1.12 are so unusual that normal players basically never type them.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I learned
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Frequency measures exposure, not difficulty
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;aesthetic&lt;/code&gt; has a Zipf score of 4.02. You see it all the time on social media, but for a learner it's a hard word (around CEFR C2). &lt;code&gt;integrity&lt;/code&gt; is the same story: common in real text, but most junior-high students don't know it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For learner difficulty you need a second signal: the order in which learners actually acquire words.&lt;/strong&gt; In WordForge, the CEFR level list plays that role. Frequency is only the fallback for words the list doesn't cover.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Zero-frequency words are tricky
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;petrichor&lt;/code&gt; (the smell after rain) has essentially no frequency data (0), so the rule makes it N. I treat "no data" as "probably a typo or a made-up word" and give it N, but that punishes words that are well known yet rare in corpora. I plan to fix these with a hand-curated override table.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. The test also exposed translation-quality issues
&lt;/h3&gt;

&lt;p&gt;4 of the 70 words came back with a bad Japanese gloss:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Word&lt;/th&gt;
&lt;th&gt;Returned gloss (meaning)&lt;/th&gt;
&lt;th&gt;What it should be&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;wry&lt;/td&gt;
&lt;td&gt;泣く ("to cry")&lt;/td&gt;
&lt;td&gt;皮肉っぽい ("dryly mocking")&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gaunt&lt;/td&gt;
&lt;td&gt;(empty)&lt;/td&gt;
&lt;td&gt;やせこけた ("haggard, thin")&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;cynical&lt;/td&gt;
&lt;td&gt;キュニコス派 ("the Cynic school")&lt;/td&gt;
&lt;td&gt;皮肉な, 冷笑的な ("cynical")&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;lethargic&lt;/td&gt;
&lt;td&gt;嗜眠 ("lethargy", medical noun)&lt;/td&gt;
&lt;td&gt;無気力な ("sluggish, listless")&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;wry&lt;/code&gt; looks like it got confused with &lt;code&gt;cry&lt;/code&gt;. Because people use this to learn, I'm fixing these by hand. A language-education researcher also told me the game is good practice for spelling and recall, but that &lt;strong&gt;learning new meanings needs good translations and example sentences&lt;/strong&gt;. So adding example sentences and pronunciation is one of the goals of our crowdfunding campaign.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;If you rank difficulty by frequency alone, intermediate and advanced words collapse into the middle tier (41 of 70 words scored lower than they should).&lt;/li&gt;
&lt;li&gt;For learners, check a learning-order list (CEFR or similar) first, and use frequency only for words the list doesn't cover.&lt;/li&gt;
&lt;li&gt;Zero-frequency words and translation quality are hard to solve automatically. Plan for manual overrides.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;WordForge runs in the browser with no install and no sign-up (the UI is mostly Japanese, but the words are English). Try a few words and see what rarity they get:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://word-forge.replit.app/?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=dev01" rel="noopener noreferrer"&gt;https://word-forge.replit.app/?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=dev01&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'm also preparing a crowdfunding campaign on CAMPFIRE, a Japanese crowdfunding platform (under review; it will run until mid-January 2027). The goal is a classroom edition with a teacher dashboard, offered to 30 English schools at ¥1M and to 100 public schools for one year at ¥5M.&lt;/p&gt;

&lt;p&gt;Feedback and bug reports are very welcome: &lt;a href="mailto:yantatsuki@gmail.com"&gt;yantatsuki@gmail.com&lt;/a&gt; / X: @WordForgeJP&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: the level-based modes in the game are WordForge's own estimates and are not affiliated with any testing organization.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>gamedev</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
