Abhidhamma Julatri (อภิธรรมชั้นจูฬตรี)
Abhidhamma Julatri (อภิธรรมชั้นจูฬตรี)
An interactive study site for the จูฬตรี level of the Thai Abhidhamma curriculum (อภิธรรมโชติกะวิทยาลัย), covering จิต-เจตสิก classification and the three nayas from ปริจเฉทที่ ๒ of the Abhidhammatthasangaha. Primary source: the official จูฬตรี textbook (“ปรมัตถโชติกะ ปริจเฉทที่ ๑-๒-๖” by พระสัทธัมมโชติกะ ธัมมาจริยะ, มูลนิธิสัทธัมมโชติกะ).
Language
จิต (Citta): A moment of consciousness. Classified into 89 (or 121, พิสดาร-expanded) types across kāmāvacara, rūpāvacara, arūpāvacara, and lokuttara realms. This project uses 121: standard for kāmāvacara/rūpāvacara/arūpāvacara, พิสดาร-expanded for โลกุตตรจิต (see below) — 121 total.
เจตสิก (Cetasika): A mental factor that arises together with a citta, sharing its object, base, arising, and ceasing. There are 52, grouped into อัญญสมานาเจตสิก (13), อกุศลเจตสิก (14), and โสภณเจตสิก (25).
อกุศลจิต: The 12 unwholesome cittas (โลภมูลจิต 8, โทสมูลจิต 2, โมหมูลจิต 2).
อเหตุกจิต: The 18 “rootless” cittas — no hetu (root) cetasika present. Includes the 10 dvi-pañca-viññāṇa (bare sense-consciousness), sampaṭicchana, santīraṇa, the two āvajjana, and hasituppāda (the Arahant’s smile-producing citta).
กามาวจร: The sense-sphere realm/scope — covers อกุศลจิต, อเหตุกจิต, and กามาวจรโสภณจิต (54 cittas total). Vacanattha (ch.1): กาเมติ = กาโม / กามสฺส ภโว = กาโม (the realm where sense-desire arises, or sense-desire itself) → กาเม อวจรตีติ = กามาวจรํ (a citta that habitually arises in that realm). No single UI element renders “กามาวจร” itself — it’s the umbrella over lobha-mula/dosa-mula/moha-mula/ahetuka/mahakusala/mahavipaka/mahakiriya in CITTA_GROUPS.
กามาวจรโสภณจิต: The 24 “beautiful” sense-sphere cittas: 8 มหากุศล (active wholesome), 8 มหาวิปาก (their resultants), 8 มหากิริยา (the same pattern as functional-only, for Arahants).
มหัคคตจิต: The 27 “exalted” cittas of jhāna attainment: 15 รูปาวจร (5 rūpa-jhāna levels × kusala/vipāka/kiriya) + 12 อรูปาวจร (4 arūpa levels × kusala/vipāka/kiriya). Vacanattha (ch.1, line 573): มหนฺตํ คโตติ = มหคฺคโต — a citta that has attained greatness/excellence. Like กามาวจร, this umbrella term (over rupa-jhana/arupa-jhana in CITTA_GROUPS) has no dedicated UI element of its own.
โลกียจิต / โลกุตตรจิต: โลกียจิต is the 81 mundane cittas (กามาวจร 54 + มหัคคตะ 27); โลกุตตรจิต is the supramundane cittas (4 magga + 4 phala). This project uses the 121-system’s พิสดาร (elaborated) form of โลกุตตรจิต — each of the 8 expanded into 5 jhāna-factor levels, 40 cittas total — not the abbreviated (ย่อ) 8-citta form. Vacanattha for โลกียะ (ch.1, line 579): โลเก นิยุตฺตาติ = โลกิยา — dhammas perpetually engaged in the 3 worlds (kāma/rūpa/arūpa loka). โลกียจิต itself, like กามาวจร and มหัคคตะ, has no dedicated CITTA_GROUPS entry — lokuttara is the only lokuttara/lokiya-axis group rendered directly.
จำแนกนัย ๙ (nine classification lenses for จิต ๑๒๑): ชาติ/ภูมิ/โสภณ/โลก/เหตุ/ฌาน/เวทนา/สัมปโยค/สังขารเภทนัย (ch.1, lines 639-707) — 9 ways to cut across the CITTA_GROUPS hierarchy (e.g. “all 62 โสมนัสสหคตจิต” spans multiple groups). Exposed in data.json as cittaLenses, computed in scripts/build_data.py, and browsable via the “เน้นตาม” overlay in js/app.js — available in สังคหนัย mode only (hidden in the other 2), since a lens match highlights both the matching cittas and, via their สังคหนัย edges, every cetasika that appears in at least one of them; that citta→cetasika direction is what สังคหนัย mode is already showing, so the overlay layers naturally on top of it. 8 of the 9 are implemented: ชาติ/ภูมิ/โสภณ/โลก/เหตุ/ฌาน are fully determined by a citta’s group; เวทนา and สังขาร vary within a group but were successfully reconciled against the book’s own totals (line 685-707: สุข=1/ทุกข์=1/โสมนัส=62/โทมนัส=2/อุเบกขา=55; อสังขาริก=37/สสังขาริก=84) via a derivation from group + a numeric id/order suffix, with those totals re-checked at every build_data.py run. สัมปโยคเภทนัย is deliberately left unimplemented — the book states its totals (สัมปยุตต์=87, วิปปยุตต์=34) but leaves the exact per-citta membership as “ฯลฯ” (unstated); the most obvious derivation (ทิฏฐิ/ญาณ-presence, all อเหตุกจิต→วิปปยุตต์, all ฌานจิต→สัมปยุตต์) lands on 83/38, not 87/34, and the discrepancy hasn’t been resolved. Don’t add a sampayoga lens without either finding the source’s exact citta list or having it manually re-derived and checked against 87/34.
นิยตโยคีเจตสิก / อนิยตโยคีเจตสิก: Whether a cetasika accompanies its citta unconditionally whenever that citta arises. 41 cetasikas are นิยตโยคี (unconditional); 11 are อนิยตโยคี (conditional), split into 3 further categories (ch.2, line 409): กทาจิ — arises only sometimes, alone (มานะ); นานากทาจิ — arises only sometimes, and never simultaneously with its named siblings (อิสสา/มัจฉริยะ/กุกกุจจะ; the 3 วิรตี in lokiya context; กรุณา/มุทิตา); สหกทาจิ — arises only sometimes, but always as a pair when it does (ถีนะ/มิทธะ). Modeled in data/cetasikas.yaml via combination_type and excludes on the 11 affected cetasikas — everything else is implicitly นิยตโยคี. Browsable via the “เน้นตาม (เจตสิก)” overlay in js/app.js (#combo-overlay) — available in สัมปโยคนัย mode only (เจตสิก is the source type there; สังคหนัย treats เจตสิก as a target, ตทุภยมิสสกนัย as a cetasika↔cetasika relation), same hide-and-reset-on-mode-switch pattern as the จิต lens overlay (updateComboAvailability). Selecting a category highlights the matched เจตสิก and, via their สัมปโยคนัย edges, every จิต at least one of them occurs in — mirroring how the จิต lens overlay highlights the เจตสิก reachable from its matched จิต.
สัมปโยคนัย (Sampayoga-naya): The method that takes each เจตสิก in turn and lists every จิต it can arise in (cetasika → citta direction). Correct spelling confirmed against the official textbook (chapter heading, p. 40). Avoid: สัมโยคนัย (common misspelling, missing the ป)
สังคหนัย (Sangaha-naya): The method that takes each จิต in turn and lists every เจตสิก that arises in it (citta → cetasika direction). The reverse mapping of สัมปโยคนัย, over the same underlying data.
ตทุภยมิสสกนัย (Tadubhaya-missaka-naya): The method that, for a given เจตสิก, finds every other เจตสิก that can co-occur with it in the same จิต. Derived by composing สัมปโยคนัย (get the citta set for the cetasika) with สังคหนัย (get the cetasika set for each of those cittas), then taking the union minus itself. Answers a cetasika↔cetasika question, not a citta↔cetasika one. Avoid: มิสสกสังคหะ (a different, unrelated จูฬโท concept — a category in the four-fold sammuccaya list, not this pairing method)
รูป (Physical Matter, ปริจเฉทที่ ๖)
รูป: Physical/material phenomena, as opposed to จิต/เจตสิก (mental phenomena). 28 total, organized under 5 นัย (classification lenses), each a genuinely different kind of relation rather than one bipartite edge relation viewed multiple ways (contrast the จิต↔เจตสิก data model below): รูปสมุทเทสนัย (the 28 themselves — definitions), รูปวิภาคนัย (11 คู่/pairs), รูปสมุฏฐานนัย (causal origin — กัมมชะ/จิตตชะ/อุตุชะ/อาหารชะ), รูปกลาปนัย (bundling into 23 กลาป), รูปปวัตติกมนัย (arising/ceasing across ภูมิ, ปฏิสนธิ/ปวัตติกาล, กำเนิด). Lives on its own page, rupa.html (not a tab on index.html — that page’s own URL is already live/bookmarkable and isn’t being disturbed), with a small cross-link nav between the two pages. All 5 นัย are now implemented — รูปสมุทเทสนัย, รูปวิภาคนัย, รูปสมุฏฐานนัย, จิตตชรูปนัย, รูปกลาปนัย, and (as a scoped slice, not the full source section) รูปปวัตติกมนัย.
รูปวิภาคนัย (the 11 คู่): An intrinsic categorical attribute per รูป, not a relation between two entity types — each of the 11 คู่ (ch.6 lines 561-703) splits the same 28 รูป into two named, mutually-exclusive categories (e.g. อัชฌัตติกรูป ๕ / พาหิรรูป ๒๓). This is the same shape as จำแนกนัย ๙ for จิต, so it’s implemented the same way: a lens-overlay filter (#rupa-lens-overlay in rupa.html, RUPA_VIBHAGA_LABELS/applyVibhagaOverlay in js/rupa.js) layered on top of the existing single-panel circle grid, reusing the exact .lens-match/.lens-nomatch CSS already defined for จิต’s lens overlay — no new panel or page needed. The 11 pairs’ exact id-membership is hardcoded in scripts/build_data.py’s _RUPA_VIBHAGA_PAIRS (not derived from group/bucket, since 3 of the 11 — โอฬาริก/สันติเก/สัปปฏิฆ, all sharing an identical 12-item set — cut across the mahabhuta group: they include ปถวี/เตโช/วาโย but exclude อาโป, because that 12-set is really “ปสาทรูป ๕ + วิสยรูป ๗” in the source’s original 7-item วิสยรูป count, and 3 of those 7 are the same substances as 3 of the 4 มหาภูตรูป — see the โผฏฐัพพารมณ์ redundancy note above). Computed as rupaLenses in data.json, validated against the source’s own stated counts at every build (mirroring _EXPECTED_SANKHARA_TOTALS’s discipline).
คู่ที่ ๘ (อุปาทินนรูป/อนุปาทินนรูป) count discrepancy — not a data error: the source states อุปาทินนรูป (= กัมมชรูป) = 18 but อนุปาทินนรูป = “๔๐” (line 593: จิตตชรูป 15 + อุตุชรูป 13 + อาหารชรูป 12 = 40). Unlike every other คู่ (whose two counts always sum to exactly 28), this “40” is a รูปสมุฏฐานนัย cause-instance sum that double-counts any รูป arising from more than one non-kamma cause (e.g. วิการรูป is both จิตตช and อุตุช) — it answers “how many (รูป, cause) pairs,” not “how many รูป.” The actual unique-รูป count on the “not กัมมชรูป” side is 28 − 18 = 10, which is what _EXPECTED_VIBHAGA_TOTALS["upadinna"] validates and what the UI displays — matching every other pair’s arithmetic. Don’t “fix” this back to 40; that would be reintroducing the double-count, not correcting an error. กัมมชรูป’s exact 18-member list (ปสาทรูป5 + ภาวรูป2 + หทยรูป1 + ชีวิตรูป1 + อวินิพโภครูป8 [= มหาภูตรูป4 + รูปารมณ์/คันธารมณ์/รสารมณ์ + อาหารรูป] + ปริจเฉทรูป1) notably crosses this project’s own นิปผันน/อนิปผันน bucket boundary (it includes ปริจเฉทรูป, bucketed อนิปผันน here, and excludes สัททารมณ์, bucketed นิปผันน) — a reminder that the bucket split from รูปสมุทเทสนัย and this คู่ ๘ split are genuinely different classifications that happen to both look like an “18/10-ish” binary.
นิปผันนรูป / อนิปผันนรูป: The top-level split of the 28 รูป: 18 นิปผันนรูป (“produced/concretely-arisen” — real, directly-caused matter with its own สภาวลักษณะ/องค์ธรรม) vs. 10 อนิปผันนรูป (“non-produced” — states/attributes/boundary-markers of the 18, without their own independent causal arising). The 18 นิปผันนรูป also carry 5 synonym names (สภาวรูป/สลักขณรูป/นิปผันนรูป/รูปรูป/สัมมสนรูป); the 10 อนิปผันนรูป carry the 5 opposite names. This split is distinct from the มหาภูตรูป/อุปาทายรูป cross-cut below — don’t conflate them.
มหาภูตรูป / อุปาทายรูป: A separate cross-cut of the same 28: 4 มหาภูตรูป (ปถวี/อาโป/เตโช/วาโย — the primary elements, each other รูป depends on) vs. 24 อุปาทายรูป (everything else, “derived” from the 4). Orthogonal to the นิปผันน/อนิปผันน 18/10 split — e.g. all 4 มหาภูตรูป are นิปผันนรูป, but not all นิปผันนรูป are มหาภูตรูป.
The 28 รูป, in source order (18 นิปผันน then 10 อนิปผันน): มหาภูตรูป 4 (ปถวี, อาโป, เตโช, วาโย) → ปสาทรูป 5 (จักขุ, โสต, ฆาน, ชิวหา, กาย) → วิสยรูป (รูปารมณ์, สัททารมณ์, คันธารมณ์, รสารมณ์, + the 3 โผฏฐัพพารมณ์ which are the same substances as ปถวี/เตโช/วาโย, not new circles — see redundancy note below) → ภาวรูป 2 (อิตถีภาวะ, ปุริสภาวะ) → หทยรูป 1 (หทยวัตถุ) → ชีวิตรูป 1 (ชีวิตินทรีย์) → อาหารรูป 1 (กพฬีการาหาร) → อากาสธาตุ/ปริจเฉทรูป 1 → วิญญัติรูป 2 (กายวิญญัติ, วจีวิญญัติ) → วิการรูป 3 (ลหุตา, มุทุตา, กัมมัญญตา — sometimes counted “5” by re-including the 2 วิญญัติรูป, see อ้างอิงตัวเลขทางเลือก below) → ลักขณรูป 4 (อุปจยะ, สันติ, ชรตา, อนิจจตา).
โผฏฐัพพารมณ์ redundancy (source-internal, not a modeling error): the source’s องค์ธรรม list runs 1–29, not 1–28, because โผฏฐัพพารมณ์ (touch-object) is restated as 3 separate lines (ปถวี/เตโช/วาโย-โผฏฐัพพะ) even though those are the same substances already counted once as มหาภูตรูป — the book explicitly flags this as intentional (a “touch is directly felt as these 3 elements” note), not double-counting toward the total of 28. The UI renders 28 circles, not 29 or 31 — this redundancy is a footnote/etymology-style annotation on the relevant group, not a separate entity.
อ้างอิงตัวเลขทางเลือก (alt-count notes): Several รูป counts have a bracketed alternate reading in the source itself (not a data-entry ambiguity to resolve, but a stated variant to preserve): “วิสยรูป ๗ หรือ ๔” (7 if counting the 3 โผฏฐัพพารมณ์ separately, 4 if collapsing them into มหาภูตรูป — see redundancy note above) and “วิการรูป ๕ หรือ ๓” (5 if re-including กายวิญญัติ/วจีวิญญัติ, 3 if counting only ลหุตา/มุทุตา/กัมมัญญตา). Modeled as a note field on the relevant group-definition object (parallel to the existing etymology field pattern from CETASIKA_GROUPS/CITTA_GROUPS), rendered as a tooltip on the group header — not baked into the group’s label or count.
รูปสมุทเทสนัย data shape (first implemented slice): per-รูป fields are name → group-level member list → องค์ธรรม (one line) → ที่เกิด/location (one line) → free-form อธิบายสภาวลักษณะ (containing embedded วจนัตถะ/etymology, sometimes 2-3 alternate readings explicitly labeled มุขยนัย/ฐานยูปจารนัย, sub-variety lists, and occasional กิจ — stated only for ปสาทรูป 5, not universally). This is not a uniform classic 4-part lakkhana/rasa/paccupatthana/padatthana table like a cetasika entry — no explicit ปทัฏฐาน field exists anywhere in the source for รูป. Grouping for the circle-grid UI follows the 11 fine-grained subgroups named above (มหาภูตรูป/ปสาทรูป/วิสยรูป/ภาวรูป/หทยรูป/ชีวิตรูป/อาหารรูป/อากาสธาตุ/วิญญัติรูป/วิการรูป/ลักขณรูป), matching the granularity (and reusing the group-definition object shape) of the existing CETASIKA_GROUPS pattern in js/app.js, not the coarse 18/10 นิปผันน/อนิปผันน split.
UI shape for รูปสมุทเทสนัย: single-panel layout (one circle-grid of the 28 รูป + one info panel), reusing the existing click-to-inspect/pin interaction and summarizeByGroup/renderGroupList/footnotes-<details> rendering helpers from js/app.js. No mode-tabs or second circle-panel yet — those existed in index.html specifically because จิต↔เจตสิก is one bipartite edge relation viewed from both directions; รูปสมุทเทสนัย alone isn’t a relation between two entity types, it’s a reference list. Tabs/second-panel infrastructure gets added only once a second นัย (e.g. รูปวิภาคนัย) is actually implemented, not speculatively now.
Coarse นิปผันน/อนิปผันน split, rendered without new interaction state: the 11 fine-grained subgroups (the grid’s primary grouping) already partition cleanly along the 18/10 boundary — มหาภูตรูป+ปสาทรูป+วิสยรูป+ภาวรูป+หทยรูป+ชีวิตรูป+อาหารรูป (7 subgroups) sum to exactly the 18 นิปผันนรูป; อากาสธาตุ+วิญญัติรูป+วิการรูป+ลักขณรูป (4 subgroups) sum to exactly the 10 อนิปผันนรูป; no subgroup straddles the boundary. So the coarse split is shown as two always-visible, labeled bounding rectangles nested around those two runs of subgroup blocks (e.g. “นิปผันนรูป ๑๘” / “อนิปผันนรูป ๑๐”) — pure nested-container layout, not an overlay-select toggle like the existing lens/combo overlays and not a relayout mode. Chosen over an overlay because the partition is static and free to render this way; no highlight-match/nomatch state is needed.
Alt-name field: the 5 synonym names shared by all 18 นิปผันนรูป (สภาวรูป/สลักขณรูป/นิปผันนรูป/รูปรูป/สัมมสนรูป) and the opposite 5 shared by all 10 อนิปผันนรูป are shown as a small static table/list in the info panel when any รูป is clicked — same value for every item on its side of the 18/10 split, so it’s derived from which side a รูป is on, not stored per-รูป.
กิจ field: shown as a separate labeled field in the info panel, present only for the 5 ปสาทรูป entries (the only รูป the source states a กิจ for) — same “field present only when applicable” pattern already used by footnotes on cetasikas (absent elsewhere, no placeholder shown).
Data file convention: รูป data lives in its own data/rupas.yaml, surfaced as a top-level rupas key in data.json — keeping the one-file-per-entity-type convention from cittas.yaml/cetasikas.yaml, even though this first slice has no cooccurrence-style relation to derive. build_data.py’s validation for it is purely structural (28 entries total, 18 tagged into the นิปผันน-side groups, 10 into the อนิปผันน-side groups) — the same cross-check-against-a-stated-total discipline as _EXPECTED_SANKHARA_TOTALS/_EXPECTED_VEDANA_TOTALS, just without a derived-category computation behind it yet.
รูปสมุฏฐานนัย (causal origin, 3rd นัย implemented): a many-to-many relation between the 28 รูป and 4 causes (กรรม/จิต/อุตุ/อาหาร, ch.6 lines 707-831) — a รูป can arise from more than one cause at once, so this isn’t a bipartition like รูปวิภาคนัย’s 11 คู่. Modeled as a 5th “cause,” นกุโตจิสมุฏฐานิกรูป, for the 4 ลักขณรูป that arise from no cause at all — the source names this explicitly (line 831, part of its own เอกสมุฏฐานิก(11)/ทวิ(1)/ติ(3)/จตุ(9)/นกุโตจิ(4) classification), so giving it a real bucket in the UI (rather than an absence-of-match state) matches the text rather than inventing a category. Own tab on rupa.html (รูปสมุฏฐานนัย), two-panel bidirectional click (28 รูป left, reusing the existing grid; 5 causes right) — _RUPA_SAMUTTHANA in build_data.py, emitted as rupaSamutthana/rupaSamutthanaCauses in data.json. เอกันตะ/อเนกันตะ mapping: the source separately states, per cause, which of its รูป are “เอกันตะ” (exclusive to that cause) vs “อเนกันตะ” (also arise from others) — e.g. กัมมชรูป’s 9 เอกันตะ + 9 อเนกันตะ (lines 762-767). This is the same fact as the count-of-causes classification just mentioned, viewed per-cause instead of per-count: the 11 เอกสมุฏฐานิกรูป are exactly the union of every cause’s เอกันตะ set, and the 13 ทวิ+ติ+จตุสมุฏฐานิกรูป are exactly the อเนกันตะ รูป. The UI renders this as an always-visible 3-way border color on every รูป circle in this tab (เอกันตะ/อเนกันตะ/นกุโตจิ, with a legend) — independent of click/highlight state, the same “static classification as nested layout, not an overlay toggle” reasoning as the นิปผันน/อนิปผันน bounding boxes above, just as a border color instead of a bounding box since this classification doesn’t correspond to a contiguous run of subgroups.
จิตตชรูปนัย (coarse, 4th นัย implemented) — scoped to activity-labels, not รูป-ids: buried inside รูปสมุฏฐานนัย’s จิตตชรูป section is a second relation, which of the 89/121 จิต can produce which of 7 activity-labels (จิตตชรูปสามัญ/การหัวเราะ/การร้องไห้/อิริยาบถน้อย/การพูด/อิริยาบถใหญ่ทั้ง๔/อิริยาบถใหญ่ทั้ง๔ตั้งมั่น — ch.6 lines 874-923). The source states each activity’s จิต-membership explicitly (e.g. “จิตที่ทำให้การหัวเราะเกิดขึ้นได้ มี ๑๓ ดวง คือ…”), but never gives a table of which of the 15 จิตตชรูป (รูป-ids) each activity actually produces — only prose describing activities in general terms. Modeling a จิต→รูป-id relation would require inferring that missing mapping, which is exactly the failure mode that sank สัมปโยคเภทนัย (จิต๑๒๑, “จำแนกนัย ๙” above): a stated total with unstated exact membership, where the obvious derivation landed on the wrong numbers. So this นัย is modeled only at the granularity the source actually supports: จิต↔activity-label (not จิต↔รูป). Own tab on rupa.html (จิตตชรูปนัย), two-panel bidirectional click, but with the left/right roles swapped from the other two รูป tabs — left = 7 activity labels, right = จิต (121, with the 14 always-ineligible ones — ทวิปัญจวิญญาณ ๑๐ + อรูปวิบาก ๔ — rendered disabled rather than hidden, so “not every จิต applies here” stays visible rather than silently vanishing). _build_cittaja_activities/_CITTAJA_ACTIVITIES helpers in build_data.py, emitted as cittajaActivities/cittaEligibility in data.json.
89→121 count translation (จิตตชรูปนัย only): the source’s จิตตชรูปนัย counts (75-of-89 baseline, กามชวนะ 29, อัปปนาชวนะ 26, etc.) are stated against the book’s un-expanded 89-จิต text, but data/cittas.yaml already carries the 121-total พิสดาร-expanded lokuttara (40 instead of the base 8) — the same situation CITTA_GROUP_LENSES/_EXPECTED_VEDANA_TOTALS/_EXPECTED_SANKHARA_TOTALS already live with for other จำแนกนัย. Where an activity’s rule doesn’t touch the lokuttara group (การหัวเราะ, การร้องไห้, อิริยาบถน้อย/การพูด/อิริยาบถใหญ่ทั้ง๔), the count is untouched by the expansion and matches the source exactly. Only อิริยาบถใหญ่ทั้ง๔ตั้งมั่น includes all of อัปปนาชวนะ (and therefore all of lokuttara), so its distinct-จิต count is 88 in this dataset, not the source’s own resolved 56 (see next note) — the difference is exactly the 32-จิต lokuttara-expansion delta (56 + 32 = 88), not an error. Don’t “fix” this back to 56.
อิริยาบถใหญ่ทั้ง๔ตั้งมั่น’s own internal double-count note (source-stated, line 890): the source’s raw phrasing sums to “58” ดวง (มโนทวาราวัชชนจิต 1 + กามชวนะ 29 + อภิญญาจิต 2 + อัปปนาชวนะ 26) by listing อภิญญาจิต separately even though those same 2 จิต (the 5th-jhāna รูปาวจรกุศล/กิริยาจิต) are already inside อัปปนาชวนะ’s รูปาวจร กุศล/กิริยา members — the source itself resolves this to 56 distinct จิต if อภิญญาจิต isn’t counted twice (line 890’s own caveat). This dataset uses the resolved 56-distinct-จิต rule (not the raw 58), which is what then becomes 88 once translated to the 121-จิต space per the note above.
รูปกลาปนัย (bundling, 5th นัย implemented): unlike the earlier caution in the handoff docs (which expected this to need a wholly different UI shape from the causal-filter tabs), it turned out to fit the same two-panel bidirectional-click pattern as รูปสมุฏฐานนัย — a กลาป is just another many-to-many-related entity type (a รูป can belong to several กลาป; a กลาป is a fixed subset of รูป), not a fundamentally different relation shape. 23 กลาป in 4 classes (ch.6 lines 936-1115): 9 กัมมชกลาป, 8 จิตตชกลาป, 4 อุตุชกลาป, 2 อาหารชกลาป — authored in data/kalapas.yaml (each entry’s rupaIds list references existing rupas.yaml ids directly; no new รูป entries needed since a กลาป is purely a bundling of existing รูป). Own tab on rupa.html (รูปกลาปนัย), left = 28 รูป (reusing the existing grid), right = 23 กลาป grouped by class. Plus a กาย ๓ ส่วน (อุปริมกาย/มัชฌิมกาย/เหฏฐิมกาย) region filter — a set of plain toggle buttons (.region-btn, not a <select> like the รูปวิภาคนัย lens) that re-renders the right panel to only the กลาป present in the selected region; region membership per class is hardcoded in build_data.py’s _KALAPA_REGIONS (mirrors _RUPA_SAMUTTHANA’s “small fully-explicit exception set, not worth round-tripping through yaml” reasoning) rather than authored in the yaml.
จิตตชกลาป ๖ vs ๘ (รูปกลาปนัย): this book follows the Visuddhimagga Aṭṭhakathā’s count of 8 จิตตชกลาป (line 1017-1033); the Abhidhammatthasangaha itself lists only 6, omitting สัททนวกกลาป and สัททลหุตาทิทวาทสกกลาป (the 2 “sound” ones) — stated as an explicit alt-reading footnote by the source itself (line 1033). Modeled as primary=8 with the 6-กลาป reading as a footnotes entry on those 2 กลาป (same convention as footnotesHtml in js/app.js, and the same “book-is-primary, alt-reading noted not silently dropped” convention already used for the วิสยรูป ๗-หรือ-๔ and วิการรูป ๕-หรือ-๓ notes in rupas.yaml). Confirmed with user 2026-08-25 session (recommended option chosen over treating the Sangaha’s 6 as primary).
กัมมชกลาป region counts diverge from the source’s own printed numbers, on purpose: the source’s อุปริมกาย/มัชฌิมกาย/เหฏฐิมกาย counts for กัมมชกลาป (7/4/3, lines 1005-1015) list “ภาวทสกกลาป” as a single item, even though this นัย’s own 9-กลาป total (and rupas.yaml’s ภาวรูป group) always keeps อิตถีภาวทสกกลาป and ปุริสภาวทสกกลาป as 2 full separate entries (only mutually exclusive per individual, by sex — line 995 — not per region). This dataset keeps both entries in every region list where “ภาวทสกกลาป” is mentioned, since structurally both occupy the same body location, giving region totals of 8/5/4 instead of the source’s printed 7/4/3. Confirmed with user 2026-08-25 session; don’t “fix” _EXPECTED_KALAPA_REGION_TOTALS back to 7/4/3 to match the printed source numbers — that would reintroduce the itthi/purisa collapse this project doesn’t apply anywhere else.
อุตุชกลาป’s constant-vs-intermittent timing note is descriptive text only, not modeled: all 4 อุตุชกลาป occur in all 3 body regions with no restriction (lines 1091-1093) — the source separately notes 2 of them (สุทธัฏฐกกลาป/ลหุตาทิเอกาทสกกลาป) are constantly present while the other 2 (the sound ones) occur only intermittently, but that’s a timing distinction, not a region gate. Deliberately left unmodeled as an interactive UI dimension (no data flag, no badge) — confirmed with user 2026-08-25 session, recommended option chosen over adding a flag.
รูปปวัตติกมนัย (temporal, 5th/last นัย, scoped slice): unlike the other 4 นัย, this source section (ch.6 lines 1119-1357) bundles ~9 distinct facts along a time axis rather than one relation viewed two ways — ภูมิ×รูป arisability, ปฏิสนธิ/ปวัตติกาล capability, a กำเนิด taxonomy, กัมมชกลาป×birth-context arisability, a week-by-week gestational timeline, and death-sequence citta-offset timing. Only the clean enumerable relations are implemented (confirmed with user, 2026-08-25 session — the gestational/death-sequence timeline is deliberately deferred as a possible future tab, not modeled here): ภูมิ×รูป (28 รูป × 4 ภูมิ-groups, many-to-many), a static per-รูป ปฏิสนธิกาล-capability attribute, and กัมมชกลาป(9)×birth-context (4 rows, many-to-many). Own tab on rupa.html (รูปปวัตติกมนัย), containing a nested sub-tab bar (.subtab-switch/.subtab-btn, a deliberately distinct, visually-smaller idiom from the top-level .mode-btn bar) with 2 sub-views: ภูมิ (left = 28 รูป reusing the existing grid, right = 4 ภูมิ-group nodes, bidirectional click; the ปฏิสนธิกาล-capability attribute renders as an always-on 2-way border on the รูป nodes, same “static classification, not overlay toggle” pattern as รูปสมุฏฐานนัย’s เอกันตะ/อเนกันตะ/นกุโตจิ borders) and กำเนิด (left = #kalapa-panel reused and filtered to the 9 กัมมชกลาป, right = 4 birth-context nodes, bidirectional click; plus an always-visible static <dl> reference block for the plain 4-item กำเนิด glossary, independent of click state). ภูมิ-group membership and the ปฏิสนธิกาล-incapable รูป set are hardcoded in build_data.py (_BHUMI_GROUPS, _PATISANDHI_INCAPABLE — same “small fully-explicit exception set” rationale as _KALAPA_REGIONS); the กัมมชกลาป×birth-context edges and the กำเนิด glossary are authored in data/rupa_pavatti.yaml.
birth-context ≠ กำเนิด: the กัมมชกลาป-at-ปฏิสนธิ table (L1229-1247) does not use the 4 กำเนิด (สังเสทชะ/โอปปาติกะ/อัณฑชะ/ชลาพุชะ) as its rows — it splits โอปปาติกะ by realm (กามภูมิ / รูปพรหม / อสัญญสัตตพรหม) and merges อัณฑชะ+ชลาพุชะ back into คัพภเสยยกะ. Modeling these as the same entity would misstate the source, so birth-context is its own entity (kama-sesa-oppa/rupa-brahma/asanna-brahma/gabbhaseyyaka in data/rupa_pavatti.yaml), and กำเนิด stays a plain 4-item glossary with no relation attached. Confirmed with user 2026-08-25 session (“two separate entities” chosen over reusing กำเนิด directly for the table’s rows). The fine-grained detail of which specific sub-population within kama-sesa-oppa can miss which กลาป (สังเสทชะ misses 4, ทุคคติโอปปาติกะ misses 3, สุคติโอปปาติกะ-มนุษย์-ต้นกัป misses 1, เทวดา-โอปปาติกะ misses none) is prose-only in that context’s info panel, not modeled as further sub-entities — same “interactive = enumerable relation, narrative nuance = text” cutoff already used for จิตตชรูปนัย’s activity-label granularity.
ปฏิสนธิกาล-incapable รูป: 9, not 8: the source states the Abhidhammatthasangaha’s own count is 8 (สัททะ/วิการรูป-3/ชรตา/อนิจจตา) but then explicitly resolves to 9 as its own conclusion (“ฉะนั้น…จึงคงเป็น…๙ รูป”, L1181) by additionally excluding สันตติรูป, per the Atthakatha/Tika reading — the same “book resolves to the Atthakatha/Tika reading as primary, Sangaha’s own count becomes a footnote” shape as the จิตตชกลาป ๖-หรือ-๘ decision above. Modeled as primary=9 (_PATISANDHI_INCAPABLE in build_data.py); the 8-count Sangaha reading is a footnote in data/rupa_pavatti.yaml. Confirmed with user 2026-08-25 session.
ชีวิตนวกกลาป’s ๘+๑=๘ arithmetic (kama-sesa-oppa birth-context): for สังเสทชะ+โอปปาติกะ-กามภูมิ, L1231 lists 8 กัมมชกลาป (including ชีวิตนวกกลาป) as arising at ปฏิสนธิ, but L1251 separately says ปวัตติกาล adds 1 more — also ชีวิตนวกกลาป — for a combined total that’s still 8, not 9. This only works arithmetically if ชีวิตนวกกลาป wasn’t really counted at ปฏิสนธิ in the first place; L1276 supports that reading (ชีวิตนวกกลาป for this group arises “ตั้งแต่ฐีติขณะของปฏิสนธิจิต,” which by the book’s own definition, L1175, is technically already ปวัตติกาล, not ปฏิสนธิกาล). This dataset nonetheless keeps ชีวิตนวกกลาป tagged phase: patisandhi for kama-sesa-oppa, exactly as L1231 literally lists it, and footnotes the ๘+๑=๘ oddity instead of reinterpreting the phase. Confirmed with user 2026-08-25 session (literal-list-with-footnote chosen over silently retiming it to pavatti).
Data model
All three nayas are computed views over a single underlying dataset: the set of citta↔cetasika edges (which เจตสิก occur in which จิต). สัมปโยคนัย and สังคหนัย are the two directional traversals of that edge set; ตทุภยมิสสกนัย is a second-order relation (cetasika↔cetasika) derived from composing both traversals. The edges are authored once; all three views are computed, not separately maintained.
All 121 cittas (89 kāma/rūpa/arūpa + 40 พิสดาร-expanded lokuttara) and all 52 cetasikas are entered, verified against the official textbook’s per-citta tables (pp. 50-56) and cross-checked against its summary diagram (p. 56).
Array order within each group in data/cittas.yaml determines row layout in the UI (CITTA_GROUPS in js/app.js, via each group’s rows or chunkSize) — it’s not arbitrary. อเหตุกจิต renders as 3 uneven rows (7/8/3, by resultant-type, matching the textbook’s own grouping — not “all 10 dvi-pañca-viññāṇa first”). รูปาวจร/อรูปาวจร/โลกุตตร render as even rows grouped by kind/stage first and jhāna-level second (matching the textbook’s summary diagram, p. 56), so their YAML entries are ordered kind-major / stage-major, not jhāna-level-major.