An Area Unit Converter With 15 Units — Including Four Different Sizes of Japanese Tatami
A Japanese real-estate listing will describe the same apartment in square meters,
tsubo, andjō(tatami mats). Those three numbers should be consistent, but the jō isn't one size — it's four, depending on region. While writing this tool I also discovered that "1 tsubo = exactly 400/121 m²" is the legal definition, not an approximation, and the reason involves a Meiji-era conversion between French meters and Japanese shaku.
Japanese real estate uses three overlapping area systems at once. A single apartment listing might say "62 m² / 18.75 坪 / 12 畳 (Kyōma)". Converting among them by hand is tedious, and the tatami unit has a trap: a "6-jō room" is 26% larger in Kyoto than in a Tokyo housing project. Same unit name, same building, completely different floor area. I needed a tool that showed all 15 relevant units side-by-side.
🔗 Live demo: https://sen.ltd/portfolio/area-units/
📦 GitHub: https://github.com/sen-ltd/area-units
15 units total:
- Metric: cm², m², a (are), ha (hectare), km²
- Imperial: sq ft, sq yd, acre
- Japanese traditional: tsubo, jō (Edo / Kyō / Chūkyō / Danchi versions), se, tan, chō
Zero dependencies, no build, 10 tests.
The "1 tsubo = 400/121 m²" exact fraction
Most references round tsubo to 3.30578 m². The legal definition is a fraction:
tsubo: { toM2: 400 / 121, label: '坪', ja: '坪' },
Derivation:
- 1 tsubo = a 6 shaku × 6 shaku square
- 1 shaku = 10/33 m (defined in the Meiji Metric Act of 1891)
- 1 tsubo =
(6 × 10/33)² = (20/11)² = 400/121 m²
The 10/33 figure is the historical ratio between the French meter (standardized via the meter-bar in Sèvres) and the Japanese kanejaku (carpenter's shaku). It was chosen so that 33 shaku = exactly 10 meters, giving surveyors a clean integer ratio to work with when converting land records. This is why area math in tsubo can be done with exact rationals a century later — the original law was careful.
When you write 400 / 121 in JavaScript, you get a float, but the ratio is exact. The rounding error that shows up in display is cosmetic; round-trips go back to the same value.
Tan, chō, and se as multiples of tsubo
The larger Japanese units are all exact multiples of tsubo, so the same fraction propagates:
se: { toM2: 30 * 400 / 121, label: '畝', ja: '畝(せ)' },
tan: { toM2: 300 * 400 / 121, label: '反', ja: '反(たん)' },
cho: { toM2: 3000 * 400 / 121, label: '町', ja: '町(ちょう)' },
- 1 se = 30 tsubo
- 1 tan = 300 tsubo = 10 se
- 1 chō = 3000 tsubo = 100 se = 10 tan
Decimal scaling across the hierarchy — clearly a designed system, not accidental. The relationships predate the Meiji Metric Act; they're inherited from Edo-period cadastral surveys.
Four kinds of jō
Tatami rooms are quoted in jō (mats), but the mat itself comes in four standard sizes:
jo_edoma: { toM2: 1.5488, label: '畳(江戸間)', ja: '畳(江戸間)' },
jo_kyoma: { toM2: 1.8240, label: '畳(京間)', ja: '畳(京間)' },
jo_chukyo: { toM2: 1.6562, label: '畳(中京間)', ja: '畳(中京間)' },
jo_danchi: { toM2: 1.4455, label: '畳(団地間)', ja: '畳(団地間)' },
Kyōma (Kyoto) is the largest at 1.8240 m². Danchi-ma (postwar public housing) is the smallest at 1.4455 m². A "6 jō room" is 10.9 m² in Kyōma and 8.7 m² in danchi-ma — a difference of over 2 m² for what the listing calls the same size.
The historical reason is interesting: Kansai construction sized the house around the tatami (畳割り — "mat-first layout"), while Edo construction sized the tatami to fit between pillars already laid out (柱割り — "pillar-first layout"). Different construction methods → different mat sizes. Danchi-ma came later as a cost-optimization for postwar housing blocks, deliberately sized smaller so the same apartment floor plan could be rebranded as having "more jō."
A single unit name covering a 26% range would be unacceptable in any formal measurement system. Japanese real estate gets away with it because listings have quietly standardized on "when in doubt, use Kyōma" for the formal number and everyone knows what apartments will actually feel like.
The convert / convertAll pair
Conversion goes through a canonical form (m²) so you don't need an N×N matrix:
export function convert(value, fromUnit, toUnit) {
if (!Number.isFinite(value)) return { error: 'invalid value' }
const from = UNITS[fromUnit]
const to = UNITS[toUnit]
if (!from || !to) return { error: 'unknown unit' }
const m2 = value * from.toM2
return { value: m2 / to.toM2, unit: toUnit }
}
15 units × 15 units would be 225 conversion constants. Going through m² needs only 15 (one per unit), and adding a 16th unit requires exactly one new entry.
The side-by-side UI uses a companion function that converts to every unit at once:
export function convertAll(value, fromUnit) {
const from = UNITS[fromUnit]
const m2 = value * from.toM2
const out = {}
for (const [id, def] of Object.entries(UNITS)) {
out[id] = m2 / def.toM2
}
return out
}
Enter "100 m²", get all 14 other values at once in a row layout. That row layout is the whole point — being able to see "100 m² = 30.25 tsubo = 54.6 jō (Kyōma)" without pressing a convert button.
Tests
10 cases on node --test:
test('1 tsubo equals exactly 400/121 m²', () => {
const r = convert(1, 'tsubo', 'm2')
assert.equal(r.value, 400 / 121)
})
test('1 tan equals 300 tsubo', () => {
const r = convert(1, 'tan', 'tsubo')
assert.equal(r.value, 300)
})
test('1 cho equals 10 tan', () => {
const r = convert(1, 'cho', 'tan')
assert.equal(r.value, 10)
})
test('roundtrip: 100 m² → tsubo → m²', () => {
const a = convert(100, 'm2', 'tsubo').value
const b = convert(a, 'tsubo', 'm2').value
assert.ok(Math.abs(b - 100) < 1e-9)
})
test('Kyōma > Chūkyō > Edoma > Danchi', () => {
assert.ok(UNITS.jo_kyoma.toM2 > UNITS.jo_chukyo.toM2)
assert.ok(UNITS.jo_chukyo.toM2 > UNITS.jo_edoma.toM2)
assert.ok(UNITS.jo_edoma.toM2 > UNITS.jo_danchi.toM2)
})
The last test is a data-integrity check disguised as trivia. If a contributor types a jō value wrong, this test fails immediately and tells you exactly which ordering broke. "Documentation tests" like this are one of the best ROI patterns for data-heavy tools.
Series
This is entry #19 in my 100+ public portfolio series.
- 📦 Repo: https://github.com/sen-ltd/area-units
- 🌐 Live: https://sen.ltd/portfolio/area-units/
- 🏢 Company: https://sen.ltd/
If you know a common unit I should add, issues welcome.

Top comments (0)