1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
|
# Pure 연구 보고서 004: 빈 작업물에서 직접 작성하기
작성일: 2026-09-22
**이번에는 빈 문서에서 상태·입력·도형·반응을 작성하는 도구를 구현했다.**
새 동작을 추가하는 데 실행기 내부를 수정하지 않아도 된다. 자동 검사와 실제 브라우저 조작은
통과했지만, 사용자가 배우기 쉬운지와 기존 코드보다 제작하기 편한지는 아직 모른다.
실행 비용을 비교한 현재 구현은 고정된 JavaScript 예제보다 느렸다.
후속 사용자 관찰: 문법은 매력적이고 기본 사용에 걸림돌이 없었지만, 현재 결과는 작은 DSL이며
실제 큰 서비스·앱·CLI를 개발해야 가치를 판단할 수 있다는 피드백을 받았다.
이 관찰은 사용자 한 명의 현재 경험이다. 대규모 제작·성능·독창성은 여전히 미검증이다.
다음 설계는 [기반 계약 보고서 005](005-foundation-contract.md)에 기록했다.
[제작 화면 실행 안내](../../prototypes/workbench/README.md)를 따라 자신의 작은 동작을 만들어볼 수 있다.
첫 화면은 비어 있고, 예제는 직접 선택했을 때만 편집기에 들어온다.
사용자가 전달할 관찰은 **하려던 일 / 실제로 일어난 일 / 기대했던 일**이면 된다.
도구의 표현이나 설명이 막히는 지점을 재현하고 개선하는 일은 Codex가 맡는다.
## 이전 실험에서 바로잡은 점
사용자는 “Dino를 직접 만든 것이 아니므로 개발 경험을 평가할 수 없다”고 지적했다.
맞는 지적이다. 기존 데모는 정해진 동작의 설정 변경과 상태 보존을 시험했으며,
새 동작을 만드는 과정은 제공하지 않았다. 그 결과를 개발 경험의 증거로 쓰지 않는다.
이번 실험에서는 사용자가 직접 다음을 정의한다.
| 작성할 것 | 표현 |
|---|---|
| 기억할 값 | `state x = 80` |
| 입력 이름과 키 | `input right = ArrowRight` |
| 보여줄 대상과 상태 연결 | `circle seed(x, 180, 20, "#7ed9ae")` |
| 누름·놓음·시간 반응 | `on right.down`, `on right.up`, `on frame` |
| 계산·조건 | 대입, 산술·비교, `if`, `min/max/clamp` |
점프·중력·충전·충돌은 코어에 내장하지 않았다. 충전 예제의 중력과 바닥 판정도 작성한 코드에 있다.
화면의 입력 버튼, 상태 목록과 도형은 선언한 내용에서 만들어진다.
현재 범위는 숫자 상태와 간단한 도형을 사용하는 작은 상호작용이다. 임의 앱, 센서,
자유로운 창 관리, 셰이더, 문자열·배열·함수 등을 지원한다는 뜻은 아니다.
## 실제 제작 과정에서 확인한 의미
편집 중인 코드와 실행에 적용한 코드를 구분한다. 적용할 때 **같은 이름의 숫자 상태**는 유지한다.
상태 선언 순서를 바꿔도 이름으로 대응하며, 새 이름은 초깃값을 사용한다.
이름을 바꾸는 행위의 의미까지 추론하지는 않는다. 초깃값 변경을 현재 값에 반영하려면 초기화를 누른다.
문법·이름·용량 오류가 있는 수정은 기존 작업을 유지한다. 계산 중 오류가 생기면 해당 이벤트에서
실행한 모든 반응의 숫자 상태 변경을 함께 취소한다. 키보드와 포인터가 같은 입력을 동시에
누르면 첫 누름과 마지막 놓음만 전달한다. 누른 상태에서는 새 코드를 적용할 수 없다.
브라우저 검증 중 서로 다른 도형·입력·반응을 소스만 편집해 추가했다. 기존 실행기 변경은 없었다.
미적용 초안의 저장·불러오기도 확인했다. 실제 사용자의 자유로운 제작 성공률이나 소요 시간은
이 자동화로 측정되지 않는다.
## 이번에는 실제로 명령 해석기가 있다
초기 대화의 네이티브 C 함수 구성에는 자체 바이트코드 VM이 없었다.
이번에는 작성한 동작을 실행 중 교체하는 실험을 위해 **작은 중간 명령 해석기**를 도입했다.
구성이 달라졌으므로 바이트코드 저장량을 0이라고 말할 수 없다.
```text
작성한 .pure 텍스트
→ JavaScript 컴파일러: 이름·타입의 범위와 용량 검사, 중간 명령 생성
→ Zig 코어: 중간 명령 실행, 상태·오류·적용 관리
→ 브라우저 SVG 또는 터미널 JSON
```
Zig 코어 자체는 WebAssembly로 빌드한다. 사용자가 작성한 중간 명령과 이 Wasm 파일은
서로 다른 대상이다. 브라우저와 터미널은 같은 컴파일러·코어를 사용하지만 별도 인스턴스다.
이 선택이 최종 제품의 언어·컴파일 방식으로 확정된 것은 아니다.
## 보관 공간과 실행 명령 수
[충전 예제](../../prototypes/workbench/examples/charge.pure)를 실제 컴파일·실행한 값이다.
소스는 674바이트, 상태 4개, 입력 1개, 출력 4개, 반응 3개이며 중간 명령은 66개다.
| 항목 | 바이트 | 의미 |
|---|---:|---|
| 사용 중인 명령·반응 정보 | **1,092** | 명령 66 × 16 + 반응 3 × 12; 표시 계산 명령 포함 |
| 현재 숫자 상태 값 | **32** | 4 × 8 |
| 프로그램 한 개의 예약 공간 | 9,392 | 명령·반응·초깃값 등의 고정 용량 |
| 코어 구조체 예약 공간 | **19,072** | 실행 중 프로그램, 다음 적용을 위한 준비 공간, 상태·관리 정보 포함 |
| 그중 다음 프로그램 준비 공간 | 9,392 | 위 코어 구조체에 포함 |
| 한 번의 계산 평가 스택 용량 | 512 | 64 × 8; 영구 상태와 다른 임시 공간 |
| Wasm 선형 메모리 | **65,536** | 초기·최대값 고정; 코어와 예약한 16 KiB 호출 스택 포함 |
| 배포 Wasm 파일 | **48,182** | `ReleaseSafe`, 디버그 정보 제거한 파일 크기 |
표의 포함 관계를 무시하고 합산하면 안 된다. 특히 32바이트 상태만으로 전체 프로그램이
돌아간다는 뜻이 아니다. JS 컴파일러·소스·중간 명령 객체, 브라우저·Node 엔진, SVG,
기계어 코드와 프로세스 전체 메모리는 이 선형 메모리 수치에 포함되지 않는다.
JavaScript 비교 모델의 힙 사용량도 측정하지 않았으므로 메모리 우월성은 판단하지 않는다.
고정 용량 덕분에 이 코어는 작업이 작아도 프로그램 두 개 분량을 예약한다.
작업에 비례해 메모리가 줄어드는 구현도 아니고, 이 19 KiB를 최적이라고 주장하지도 않는다.
해당 예제에서 관찰한 이벤트당 중간 명령 실행 수는 다음과 같다.
| 실제 상황 | 실행한 중간 명령 |
|---|---:|
| 바닥에 정지한 상태로 한 프레임 | 22 |
| 바닥에서 입력 누르기 | 8 |
| 충전 중 한 프레임 | 29 |
| 한 프레임 충전한 뒤 놓기 | 13 |
| 이후 공중에서 한 프레임 | 18 |
이 값은 **해당 이벤트에서 해석한 명령** 수다. CPU 명령 수·CPU 사이클·함수 호출 횟수가 아니다.
컴파일, 호스트 입력 처리, 표시 표현식 평가와 렌더링도 제외한다.
[빌드·검사·명령 수 기록](../../prototypes/workbench/results/2026-09-22-linux-aarch64/verification.json)에
당시 상태와 코드·Wasm 해시를 남겼다.
## 일반 JavaScript와 비교한 결과
[독립 JavaScript 모델](../../prototypes/workbench/web/baseline.mjs)은 컴파일러나 Pure 코어를 사용하지 않는다.
같은 충전·해제·중력·바닥 계산과 출력 값을 일반 코드로 구현했다.
이 JS 모델에는 임의 프로그램의 실행 중 교체나 이름에 따른 상태 이전 기능이 없다.
길거나 짧은 누름, 중복 누름, 두 입력원, 공중 입력, 놓기, 초기화를 포함하는
**6,663회 호스트 호출**을 양쪽에 재생했다. 각 호출 뒤 상태·출력·틱·누른 입력을 비교했다.
초기 상태 포함 **6,664개 스냅샷**, 숫자 **126,616개**에서 차이가 0이었다.
이는 기록한 실행열에서의 일치다. 모든 가능한 실행의 동등성 증명은 아니다.
예를 들어 코어의 틱 카운터는 32비트에서 순환하지만 JS 모델의 틱은 같은 방식으로 순환하지 않는다.
이번 실행열은 그 경계에 도달하지 않는다.
같은 실행열로 준비 실행 후 측정 순서를 교대하며 7회 측정했다.
환경은 **Linux aarch64, Cortex-A76, Node 24.20.0, Zig 0.15.2**다.
M3 macOS에서 얻은 결과가 아니다.
| 경로 | 호출당 시간 중앙값 | 7회 측정값의 범위 |
|---|---:|---:|
| Pure 호스트 + Wasm 명령 해석기 | **569 ns** | 516~735 ns |
| 고정 JavaScript 모델 | **53.4 ns** | 52.7~74.6 ns |
이 실행열에서는 Pure 경로가 약 **10.7배** 오래 걸렸다.
누름·놓음 처리, 프레임 계산, 초기화 등의 총 시간을 호출 수로 나눈 배치 처리량이다.
한 입력의 지연 분포나 화면 응답 시간은 아니다. Pure 쪽의 일반 명령 해석과 진단 관리 비용도
함께 들어 있으므로 이 차이를 특정 연산이나 Wasm 경계 하나의 비용으로 단정하지 않는다.
컴파일·표시 표현식·스냅샷 생성·DOM 렌더링·코드 교체 시간은 제외했다.
CPU 고정·전력·온도 통제도 하지 않았으므로 절대 수치를 일반화하지 않는다.
작성 파일은 `.pure` 34줄·674바이트, JS 모델 68줄·2,251바이트다.
이는 주석·빈 줄을 포함한 물리적 파일 길이이며, 편집기의 줄 수는 마지막 빈 줄까지 세어 다를 수 있다.
JS 모델에는 입력원 관리와 출력 데이터 생성 코드도 들어간다. Pure는 그 일부를 공통 실행기로
옮겼으며 컴파일러·호스트 코드가 사라진 것이 아니다. 이 길이로 학습 부담이나 개발 시간을 판정하지 않는다.
재현 가능한 실행열 생성기·모든 측정값·환경·해시는
[비교 원자료](../../prototypes/workbench/results/2026-09-22-linux-aarch64/comparison.json)에 있다.
## 검사와 남은 질문
- Zig 네이티브 18개: 이벤트 원자성, 범위·스택·분기, 상태 이전, 메모리 집계 등.
- 컴파일러 13개: 문법·이름·식·분기·용량·예제 작성 범위.
- 실제 Wasm 호스트 통합 13개: 새 동작 작성, 입력원 결합, 적용 실패 보존, 상태 이름 대응,
오류 보존, 표시 계산의 순수성, 별도 인스턴스 일치, 고정 메모리.
- 독립 JS 모델 7개, 실제 터미널 프로세스 4개.
- Chromium 실제 조작 44개: 빈 작업물 작성부터 새 동작 추가, 편집 중 키 입력 격리,
잘못된 수정·실행 오류, 초안 파일 저장·복원, 390px 화면과 Wasm 로드 실패 처리.
검사 중 외부에서 반환된 프로그램 정보를 변경하면 다음 적용의 상태 대응이 틀어질 수 있는 문제를
발견해 해당 정보를 변경 불가능하게 만들었다. 실패한 누름 뒤 정상적인 놓음이 오류를 지워버리는
문제도 고쳤다. 마지막 실패와 가장 최근 입력을 따로 표시한다.
[브라우저 증거](../../prototypes/workbench/results/2026-09-22-linux-aarch64/browser-checks.json),
[빈 화면](../../prototypes/workbench/results/2026-09-22-linux-aarch64/blank.png),
[작성한 화면](../../prototypes/workbench/results/2026-09-22-linux-aarch64/authored.png),
[좁은 화면](../../prototypes/workbench/results/2026-09-22-linux-aarch64/mobile.png)을 보관했다.
좁은 화면 검사는 데스크톱 브라우저의 뷰포트 검사이며 실제 휴대폰 센서·터치를 검증하지 않는다.
다음 사용자 관찰은 **자신이 정한 동작을 이 표현으로 끝까지 작성할 수 있는가**다.
원하는 작은 숫자·도형 동작도 실행기 수정을 요청해야 한다면 그 지점이 표현 범위의 실패다.
구현 세부사항을 이해하지 못했다는 이유로 사용자의 책임으로 돌리지 않는다.
다음 성능 연구에서는 같은 의미를 유지하면서 실제 사용하는 상태·명령 수가 달라질 때
예약 공간, 상태 복사, 명령 해석, 호스트 경계, 표시 계산의 비용을 각각 분리해야 한다.
현재 전체 경로의 측정만으로 어느 부분을 최적화해야 할지 확정하지 않는다.
새 원리나 기존 런타임 대비 우월성은 아직 입증하지 않았다. 이번 산출물은
그 판단에 필요한 제작 경험과 수치를 얻기 위한 실행 가능한 실험이다.
|