규칙 서술
학습 경로가 아니라 참고 문서다. 필요할 때 들어와 찾아보는 곳.
390 판에 지금 적용되는 규칙이다. 행마다 외우는 것이 아니라 한 번 익히면 여러 행에 그대로 적용되는 메타 규칙을 모았다 — 꼬리 공백·문장부호가 여기서 갈린다.
정본 데이터는 rules.md, 단계 설계는 rules_step.md, 표기는 notation.md. 배우려는 사람은 training.md.
아래는 전부 실측 확인분이다. 근거 없이 적지 않는다 — 규칙마다 검증 방법을 함께 적었다.
출력 꼬리 — 공백·기호
규칙1. 조사·명사형 뒤에는 공백이 자동으로 붙는다
sp=✔ 인 행은 출력 끝에 spacebar 가 붙는다.
조사(품사=p)와 명사형 전성어미(품사=n)가 그
대상이다.
| 품사 | sp=✔ | 비고 |
|---|---|---|
p 조사 |
30 / 36 | 예외 6건은 전부 수식키
변형(규칙2) — 무수식 조사는 전량 ✔ |
n 명사형 |
10 / 10 | 예외 없음. 2026-08-05 부터 8행이 2단계 소속(단계만 이동, 품사 유지) |
e 어미 |
89 / 100 | 나머지는 ⌥ 변형 등 |
- ex)
hl(는) →는␣·jl(은) →은␣·m,(할) →할␣ - 검증:
품사별sp분포를 세어 확인(2026-08-04 실측)
꼬리 공백의
표현은 sp 컬럼 하나다 (2026-08-04 정리)
txt 에는 꼬리 공백을 넣지 않는다. 넣으면 sp
와 이중이 되어 라벨이 실제보다 공백 하나를 더 가진 것처럼 읽힌다 —
생성기는 txt 의 꼬리 공백을 무시하므로 산출은
정상인데 문서만 틀리는 유형이다.
- 정리분 9행(390) / 7행(final):
과·만·면·행·즉→ 꼬리 공백 제거. 산출 키열 무변화 확인(build 해시 동일) - 특히
k.+⌥(2-029)은 규칙2에 따라 공백이 없는데 라벨만과␣여서 무수식 행(2-026)과 구분되지 않았다 — 사용자 지적으로 발견 sp·기호의 공백 토큰(␣)은 폐기했다(390 4행 · final 6행 →—). 스키마 enum 에서도 뺐으므로 되돌리면validate_schema.py가 즉시 실패한다(회귀 가드 실증 완료)- ⚠️ 빈값 토큰은
—(em dash) 다.-(하이픈)는⌥·⇧·⌘수식키 컬럼 전용이며,sp에 쓰면 리터럴"-"로 저장돼 스키마 위반 +gen_rules생성실패가 난다(2026-08-04 실측 5건)
규칙2.
⌥ 변형은 꼬리가 없다 — 공백도 기호도 안 붙는다
⌥=✔ 인 행은 기호·sp
컬럼과 무관하게 자모만 출력한다. 문장 중간에 조사를 붙여 쓸 때
쓴다.
- ex)
hl(는) =는␣↔︎⌥hl=는(공백 없음) - 컬럼이 그렇게 보이지 않아도 그렇다 —
⌥hl행은sp=␣인데 실제 출력에 공백이 없다. 컬럼보다 이 규칙이 우선 - 검증:
⌥=✔16행 전량이 꼬리 없음. 예외 0건(2026-08-04 실측) - 같은 불변식이
keymap_derive.py(
tools/n3sh/keymap_derive.py)rec_symbols주석에도 있다
규칙3. 390 의 기호 대응 — ⇧
가 ?, ⇧⌘ 가 !
| 수식키 | 기호 | 실제 키 |
|---|---|---|
| 무수식 | . |
period |
⇧ |
? |
slash |
⇧⌘ |
! |
b |
⌘ |
행마다 다름 | period(는) / 없음(을·를) —
일괄 규칙 아님 |
✅ 최종식도 같다(2026-08-06 실기 확인 — 입력 소스를
최종식으로 두고 ⇧+/→? ·
⇧+b→!). 원문(Numbers)은
⇧=!·⇧⌘=? 라고 적지만
원문이 틀렸다. 390 실측은 .
한때 "배열이 다르면 같은 키코드도 다른 문자를 낸다" 는 가설로 이 차이를 설명했으나, 실측 결과 두 배열의
⇧·⇧⌘기호 대응은 동일하다. 배열 차이는ㅒ트리거 등 다른 항목에만 있다키코드로 기호를 추론하지 말 것. 배열을 함께 봐야 한다
⌘는 일괄 규칙이 없다 —는+⌘ 는는.␣인데을+⌘ 는을(꼬리 없음)이다. 행별기호·sp컬럼을 따른다
트리거
⚠️ 전제 — 모디파이어는 자모보다 먼저 눌려 있어야 한다.
c1·c2두 자모는 모아치기라 서로 순서가 없지만, ⌥·⇧·⌘ 는 그 둘보다 앞서야 한다. 자모를 친 뒤에 모디파이어를 누르면 그 행은 발동하지 않는다. 아래 규칙들은 트리거가 제대로 잡힌 뒤의 이야기다.
- Karabiner 는 키가 눌리는 순간의 모디파이어 상태로
from을 판정한다 — 자모가 이미 눌린 뒤라면 판정이 끝나 있다- 결과가 무반응이 아니라 무수식 행 출력이라 더 헷갈린다 —
kj+⌘(까)에서 ⌘ 가 늦으면 ㄲ 이,k␣+⌘(께)는 게 가 나간다- 후치 표기는 타건 순서가 아니다 — 트리거를 앞세워 읽기 쉽게 한 것이다. 이 오해가 실제로 났다(2026-08-12 —
u␣+⌥(던) 사용자 지적)- 표기 SSOT: notation.md "모디파이어"
규칙4. 같은 트리거를 두 행이 쓸 수 없다
(c1, c2, ⌥, ⇧, ⌘) 복합키는 유일해야
한다. Karabiner 는 같은 from 을 가진 manipulator
중 먼저 나온 것만 발동시키므로, 뒤엣것은 표에 있어도 죽은
규칙이다.
- 출력(
txt)이 달라도 트리거가 같으면 충돌이다 — 그래서 복합키에txt를 넣지 않는다 - 집행: validate_schema.py(
tools/validate_schema.py)check_trigger_unique - ✅ 해소(2026-08-05) —
함(m+l무수식)이 어미(품사 e)와 명사형(품사 n) 두 행이었고 실측상 둘 다함.␣로 출력이 같아 뒤엣것이 매 빌드에서 스킵됐다. 무수식이 종결형으로 동작하고 같은 트리거의 수식 변형 4행이 전부e이므로e행을 남기고n행을 삭제했다. 현재 이 규칙의 미해소 건은 0 이다
규칙5. 실제로 쓰는 기호 키는 10종
' , - . ; [ \ ] ␣ ⏎
quote · comma · hyphen · period · semicolon · open_bracket · backslash · close_bracket · spacebar · return_or_enter
⚠️ 원문 규칙5는 8종만 적고 있다 — -(읽
j+-)·\(월 j+\)가 빠졌다. 위가
실측값이다(2026-08-04, 양 배열 전수).
c1·c2컬럼에서 스페이스바는␣로 적고 JSON 에는_로 저장된다(data-md-first-rules.md(.claude/rules/data-md-first-rules.md))
규칙6. 조사는 패턴
규칙이라 억지 가 아니다
이·히·가·은·는·을·를 등은 자모 조립으로 정상 산출되므로
억지=✔ 를 붙이지 않는다. 2026-08-03 사용자 확인으로
3건(이·히·가)을 해제했다.
억지=✔는 자모 조립이 불가능해 오라클 키열을 그대로 써야 하는 행에만 붙인다- 그 literal 은
oracle_390.json(
Extensions/n3sh/core/oracle_390.json)manual_overrides로 지정한다
배열 차이 (390 ↔︎ 최종식)
같은 규칙인데 트리거가 배열마다 다른 것들이다. 전체 목록은
keymap_final_to_390.json(Extensions/n3sh/core/keymap_final_to_390.json).
| 출력 | 390 | 최종식 | 비고 |
|---|---|---|---|
ㅒ |
r+f |
g+f |
— 390 정본이 최종식 값을 담고 있던 오기를 교정 |
될 |
u+[ |
u+[ |
·49 — 양 배열 모두 구 u+]
에서 이동. 구 자리는 staging 빈자리 등재 |
- ⚠️
keymap_final_to_390.json의 pattern A 는 정본을 덮는다 — 정본이 틀려도 산출이 정상으로 나와 오기가 안 드러난다.gen_rules.py가 매 실행마다 정본과 대조해 불일치를 보고한다
관련
- 정본 데이터: rules.md · 단계 설계: rules_step.md · 손 훈련: training.md
- 표기 SSOT: notation.md ·
컬럼 해설:
rules_Intersection.md(
Extensions/n3sh/layout/rules_Intersection.md) - 훈련: training.md · training_cheatsheet.md