viewspec 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. viewspec-0.1.0/.github/workflows/pages.yml +30 -0
  2. viewspec-0.1.0/.gitignore +16 -0
  3. viewspec-0.1.0/LICENSE +21 -0
  4. viewspec-0.1.0/PKG-INFO +208 -0
  5. viewspec-0.1.0/README.md +179 -0
  6. viewspec-0.1.0/demos/CNAME +1 -0
  7. viewspec-0.1.0/demos/SPEC-DEMO-FIFTEEN-LINES.md +96 -0
  8. viewspec-0.1.0/demos/SPEC-DEMO-INVARIANTS.md +89 -0
  9. viewspec-0.1.0/demos/SPEC-DEMO-LANDING.md +101 -0
  10. viewspec-0.1.0/demos/SPEC-DEMO-LIVE-BUILDER.md +102 -0
  11. viewspec-0.1.0/demos/SPEC-DEMO-MOTIF-SWITCHER.md +91 -0
  12. viewspec-0.1.0/demos/SPEC-DEMO-PROVENANCE-INSPECTOR.md +104 -0
  13. viewspec-0.1.0/demos/build_fifteen_lines.py +572 -0
  14. viewspec-0.1.0/demos/build_invariants.py +644 -0
  15. viewspec-0.1.0/demos/build_landing.py +83 -0
  16. viewspec-0.1.0/demos/build_live_builder.py +446 -0
  17. viewspec-0.1.0/demos/build_motif_switcher.py +343 -0
  18. viewspec-0.1.0/demos/build_provenance_inspector.py +424 -0
  19. viewspec-0.1.0/demos/build_style_derivation.py +533 -0
  20. viewspec-0.1.0/demos/fifteen-lines/index.html +540 -0
  21. viewspec-0.1.0/demos/index.html +422 -0
  22. viewspec-0.1.0/demos/invariants/index.html +400 -0
  23. viewspec-0.1.0/demos/landing-compiled/diagnostics.json +1 -0
  24. viewspec-0.1.0/demos/landing-compiled/index.html +25 -0
  25. viewspec-0.1.0/demos/landing-compiled/intent_bundle.json +408 -0
  26. viewspec-0.1.0/demos/landing-compiled/provenance_manifest.json +523 -0
  27. viewspec-0.1.0/demos/live-builder/index.html +291 -0
  28. viewspec-0.1.0/demos/motif-switcher/index.html +1374 -0
  29. viewspec-0.1.0/demos/provenance-inspector/index.html +1589 -0
  30. viewspec-0.1.0/demos/serve.py +13 -0
  31. viewspec-0.1.0/demos/shared/nav.js +63 -0
  32. viewspec-0.1.0/demos/shared/pretext-canvas-surfaces.js +208 -0
  33. viewspec-0.1.0/demos/style-derivation/index.html +545 -0
  34. viewspec-0.1.0/demos/vendor/pretext/LICENSE +2 -0
  35. viewspec-0.1.0/demos/vendor/pretext/README.md +8 -0
  36. viewspec-0.1.0/demos/vendor/pretext/dist/analysis.mjs +6 -0
  37. viewspec-0.1.0/demos/vendor/pretext/dist/line-break.mjs +3 -0
  38. viewspec-0.1.0/demos/vendor/pretext/dist/line-text.mjs +3 -0
  39. viewspec-0.1.0/demos/vendor/pretext/dist/measurement.mjs +3 -0
  40. viewspec-0.1.0/demos/vendor/pretext/package.json +14 -0
  41. viewspec-0.1.0/demos/vendor/pretext/pretext.esm.js +3 -0
  42. viewspec-0.1.0/examples/comparison_view.py +16 -0
  43. viewspec-0.1.0/examples/emit_html.py +29 -0
  44. viewspec-0.1.0/examples/invoice_table.py +21 -0
  45. viewspec-0.1.0/examples/kpi_dashboard.py +20 -0
  46. viewspec-0.1.0/pyproject.toml +52 -0
  47. viewspec-0.1.0/src/viewspec/__init__.py +77 -0
  48. viewspec-0.1.0/src/viewspec/compiler.py +814 -0
  49. viewspec-0.1.0/src/viewspec/emitters/__init__.py +1 -0
  50. viewspec-0.1.0/src/viewspec/emitters/base.py +16 -0
  51. viewspec-0.1.0/src/viewspec/emitters/html_tailwind/__init__.py +190 -0
  52. viewspec-0.1.0/src/viewspec/schema/__init__.py +5 -0
  53. viewspec-0.1.0/src/viewspec/schema/viewspec_pb2.py +87 -0
  54. viewspec-0.1.0/src/viewspec/sdk/__init__.py +17 -0
  55. viewspec-0.1.0/src/viewspec/sdk/builder.py +348 -0
  56. viewspec-0.1.0/src/viewspec/types.py +762 -0
  57. viewspec-0.1.0/tests/__init__.py +1 -0
  58. viewspec-0.1.0/tests/test_compiler.py +135 -0
  59. viewspec-0.1.0/tests/test_roundtrip.py +81 -0
@@ -0,0 +1,30 @@
1
+ name: Deploy to GitHub Pages
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ workflow_dispatch:
7
+
8
+ permissions:
9
+ contents: read
10
+ pages: write
11
+ id-token: write
12
+
13
+ concurrency:
14
+ group: pages
15
+ cancel-in-progress: false
16
+
17
+ jobs:
18
+ deploy:
19
+ environment:
20
+ name: github-pages
21
+ url: ${{ steps.deployment.outputs.page_url }}
22
+ runs-on: ubuntu-latest
23
+ steps:
24
+ - uses: actions/checkout@v4
25
+ - uses: actions/configure-pages@v5
26
+ - uses: actions/upload-pages-artifact@v3
27
+ with:
28
+ path: demos
29
+ - id: deployment
30
+ uses: actions/deploy-pages@v4
@@ -0,0 +1,16 @@
1
+ __pycache__/
2
+ *.pyc
3
+ *.pyo
4
+ *.egg-info/
5
+ dist/
6
+ !demos/vendor/pretext/dist/
7
+ !demos/vendor/pretext/dist/*.mjs
8
+ build/
9
+ .eggs/
10
+ *.egg
11
+ .ruff_cache/
12
+ .pytest_cache/
13
+ output/
14
+ viewspec_output/
15
+ .venv/
16
+ demos/server.*.log
viewspec-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 nxrobins
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,208 @@
1
+ Metadata-Version: 2.4
2
+ Name: viewspec
3
+ Version: 0.1.0
4
+ Summary: Universal UI from semantic data. Describe what your data means — the compiler figures out how it looks.
5
+ Project-URL: Homepage, https://github.com/nxrobins/viewspec
6
+ Project-URL: Repository, https://github.com/nxrobins/viewspec
7
+ Project-URL: Issues, https://github.com/nxrobins/viewspec/issues
8
+ Author: Nigel Robinson
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: compiler,composition-ir,declarative,protobuf,semantic,ui,viewspec
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Programming Language :: Python :: 3.14
20
+ Classifier: Topic :: Software Development :: Code Generators
21
+ Classifier: Topic :: Software Development :: Compilers
22
+ Classifier: Topic :: Software Development :: User Interfaces
23
+ Requires-Python: >=3.11
24
+ Requires-Dist: protobuf>=5.0
25
+ Provides-Extra: dev
26
+ Requires-Dist: pytest>=8.0; extra == 'dev'
27
+ Requires-Dist: ruff>=0.4; extra == 'dev'
28
+ Description-Content-Type: text/markdown
29
+
30
+ # ViewSpec
31
+
32
+ **Universal UI from semantic data.**
33
+
34
+ ViewSpec is a declarative language for describing what data means. The compiler figures out how it looks. Every pixel has a birth certificate.
35
+
36
+ 🌐 **[viewspec.dev](https://viewspec.dev)** — Live demos and interactive playground
37
+
38
+ ```python
39
+ from viewspec import ViewSpecBuilder, compile
40
+ from viewspec.emitters.html_tailwind import HtmlTailwindEmitter
41
+
42
+ builder = ViewSpecBuilder("invoice")
43
+ table = builder.add_table("items", region="main", group_id="rows")
44
+ table.add_row(label="Design System Audit", value="$4,200")
45
+ table.add_row(label="Component Library", value="$8,500")
46
+ table.add_row(label="API Integration", value="$3,100")
47
+
48
+ ast = compile(builder.build_bundle())
49
+ HtmlTailwindEmitter().emit(ast, "output/")
50
+
51
+ # That's it. Full UI. Full provenance. No CSS.
52
+ ```
53
+
54
+ ## What ViewSpec Does
55
+
56
+ **Before ViewSpec:** You manually bridge the gap between data and UI. Every component, every prop, every layout decision — hand-wired by a developer.
57
+
58
+ **After ViewSpec:** You declare what the data means. The compiler determines the visual structure. Rendering is a pluggable backend.
59
+
60
+ ```
61
+ Data → ViewSpec (semantic intent) → Compiler → CompositionIR → Emitter
62
+ ├── HTML/Tailwind (shipped)
63
+ ├── Canvas/Pretext
64
+ ├── PDF
65
+ ├── Native mobile
66
+ └── Your custom emitter
67
+ ```
68
+
69
+ ## Three Invariants
70
+
71
+ ViewSpec enforces three mathematical guarantees:
72
+
73
+ 1. **Exactly-once provenance.** Every data binding is routed exactly once. Nothing dropped. Nothing duplicated. Nothing hallucinated.
74
+
75
+ 2. **Semantic grouping.** Data is grouped by meaning, not by visual adjacency.
76
+
77
+ 3. **Strict ordering.** The original data order is preserved as a mathematical guarantee.
78
+
79
+ ## Install
80
+
81
+ ```bash
82
+ pip install viewspec
83
+ ```
84
+
85
+ Requires Python 3.11+.
86
+
87
+ ## Demos
88
+
89
+ Six interactive demos at [viewspec.dev](https://viewspec.dev):
90
+
91
+ | Demo | What it shows |
92
+ |------|--------------|
93
+ | [Same Data, Three Motifs](https://viewspec.dev/motif-switcher/) | One dataset → table, dashboard, or comparison. Change one parameter. |
94
+ | [Provenance Inspector](https://viewspec.dev/provenance-inspector/) | Hover any element. Trace DOM → IR → binding → address → raw data. |
95
+ | [Live Builder](https://viewspec.dev/live-builder/) | Browse ViewSpec JSON, IR tree, and rendered output in sync. |
96
+ | [The Invariants](https://viewspec.dev/invariants/) | Watch the compiler enforce — and refuse — each guarantee. |
97
+ | [15 Lines → Full UI](https://viewspec.dev/fifteen-lines/) | An invoice table builds itself from 15 lines of Python. |
98
+ | [Style Derivation](https://viewspec.dev/style-derivation/) | Same structure, different feel. Toggle four visual presets. |
99
+
100
+ Text rendering powered by [Pretext](https://github.com/chenglou/pretext) canvas surfaces.
101
+
102
+ ## Core Concepts
103
+
104
+ ### Semantic Substrate
105
+
106
+ The raw data graph. Nodes with typed attributes, slots, and edges. This is WHAT the data is — no visual intent.
107
+
108
+ ```python
109
+ builder = ViewSpecBuilder("my_view")
110
+ builder.add_node("user_1", "person", attrs={"name": "Alice", "role": "Engineer"})
111
+ builder.add_node("user_2", "person", attrs={"name": "Bob", "role": "Designer"})
112
+ ```
113
+
114
+ ### ViewSpec
115
+
116
+ The declarative intent layer. Regions (WHERE data can go), bindings (WHICH data goes WHERE), motifs (HOW it should be structured), and styles (how it should FEEL).
117
+
118
+ ```python
119
+ table = builder.add_table("team", region="main", group_id="members")
120
+ table.add_row(label="Alice", value="Engineer")
121
+ table.add_row(label="Bob", value="Designer")
122
+ ```
123
+
124
+ ### CompositionIR
125
+
126
+ The compiler's output. A strict hierarchical tree of 12 UI primitives (`root`, `stack`, `grid`, `cluster`, `surface`, `text`, `label`, `value`, `badge`, `image_slot`, `rule`, `svg`) with full provenance tracking. Every IR node knows which semantic addresses and intent refs produced it.
127
+
128
+ ### Emitters
129
+
130
+ Pluggable renderers that turn CompositionIR into concrete output. Subclass `EmitterPlugin`:
131
+
132
+ ```python
133
+ from viewspec.emitters.base import EmitterPlugin
134
+
135
+ class MyEmitter(EmitterPlugin):
136
+ def emit(self, ast_bundle, output_dir):
137
+ # Walk ast_bundle.result.root.root and produce output
138
+ ...
139
+ ```
140
+
141
+ The included HTML/Tailwind emitter produces standalone HTML with full Tailwind styling, provenance data attributes on every DOM element, action event dispatch, and a JSON provenance manifest.
142
+
143
+ ## Motif Types
144
+
145
+ | Builder | Motif | Use case |
146
+ |---------|-------|----------|
147
+ | `add_table()` | `table` | Tabular data with label-value rows |
148
+ | `add_dashboard()` | `dashboard` | KPI cards with label-value pairs |
149
+ | `add_outline()` | `outline` | Hierarchical outlines and trees |
150
+ | `add_comparison()` | `comparison` | Side-by-side comparisons |
151
+
152
+ Each builder returns a chained sub-builder. Compose them freely within a single ViewSpec.
153
+
154
+ ## Compilation
155
+
156
+ ### Reference Compiler (free, offline)
157
+
158
+ Handles the four standard motifs locally. No API, no network, no LLM. Deterministic.
159
+
160
+ ```python
161
+ ast = compile(builder.build_bundle())
162
+ ```
163
+
164
+ ### Hosted Compiler (api.viewspec.dev)
165
+
166
+ For complex layouts, novel data shapes, and advanced derivation. The hosted compiler was **evolved** (not hand-written) using reinforcement learning:
167
+
168
+ - **13/13** on a static validation suite
169
+ - **50/50** on novel, randomized out-of-distribution layouts (one-shot)
170
+ - **Level 2 derivation tokens** — data-aware emphasis, narrative routing, palette energy
171
+ - **Zero LLM cost at runtime** — deterministic Python, ~3ms per compile
172
+
173
+ ```python
174
+ from viewspec import compile_auto
175
+
176
+ # Try local first, fall back to hosted for unsupported motifs
177
+ ast = compile_auto(builder.build_bundle())
178
+ ```
179
+
180
+ | Tier | Price | Hosted Calls/Day |
181
+ |------|-------|-----------------|
182
+ | Free | $0 | 500 |
183
+ | Pro | $39/mo | 25,000 |
184
+ | Scale | $99/mo | 250,000 |
185
+ | Enterprise | Contact | Custom |
186
+
187
+ ## Wire Format
188
+
189
+ Protocol Buffers for language-agnostic serialization. The same ViewSpec can be constructed in Python, Rust, Go, TypeScript, or any language with protobuf support.
190
+
191
+ ```python
192
+ bundle = builder.build_bundle()
193
+ json_data = bundle.to_json() # JSON round-trip
194
+ proto_bytes = bundle.to_proto().SerializeToString() # Protobuf round-trip
195
+ ```
196
+
197
+ ## Examples
198
+
199
+ See [`examples/`](examples/):
200
+
201
+ - **`invoice_table.py`** — Build a table in 15 lines
202
+ - **`kpi_dashboard.py`** — KPI dashboard with style tokens
203
+ - **`comparison_view.py`** — Side-by-side comparison
204
+ - **`emit_html.py`** — Load a compiled AST and emit HTML
205
+
206
+ ## License
207
+
208
+ MIT
@@ -0,0 +1,179 @@
1
+ # ViewSpec
2
+
3
+ **Universal UI from semantic data.**
4
+
5
+ ViewSpec is a declarative language for describing what data means. The compiler figures out how it looks. Every pixel has a birth certificate.
6
+
7
+ 🌐 **[viewspec.dev](https://viewspec.dev)** — Live demos and interactive playground
8
+
9
+ ```python
10
+ from viewspec import ViewSpecBuilder, compile
11
+ from viewspec.emitters.html_tailwind import HtmlTailwindEmitter
12
+
13
+ builder = ViewSpecBuilder("invoice")
14
+ table = builder.add_table("items", region="main", group_id="rows")
15
+ table.add_row(label="Design System Audit", value="$4,200")
16
+ table.add_row(label="Component Library", value="$8,500")
17
+ table.add_row(label="API Integration", value="$3,100")
18
+
19
+ ast = compile(builder.build_bundle())
20
+ HtmlTailwindEmitter().emit(ast, "output/")
21
+
22
+ # That's it. Full UI. Full provenance. No CSS.
23
+ ```
24
+
25
+ ## What ViewSpec Does
26
+
27
+ **Before ViewSpec:** You manually bridge the gap between data and UI. Every component, every prop, every layout decision — hand-wired by a developer.
28
+
29
+ **After ViewSpec:** You declare what the data means. The compiler determines the visual structure. Rendering is a pluggable backend.
30
+
31
+ ```
32
+ Data → ViewSpec (semantic intent) → Compiler → CompositionIR → Emitter
33
+ ├── HTML/Tailwind (shipped)
34
+ ├── Canvas/Pretext
35
+ ├── PDF
36
+ ├── Native mobile
37
+ └── Your custom emitter
38
+ ```
39
+
40
+ ## Three Invariants
41
+
42
+ ViewSpec enforces three mathematical guarantees:
43
+
44
+ 1. **Exactly-once provenance.** Every data binding is routed exactly once. Nothing dropped. Nothing duplicated. Nothing hallucinated.
45
+
46
+ 2. **Semantic grouping.** Data is grouped by meaning, not by visual adjacency.
47
+
48
+ 3. **Strict ordering.** The original data order is preserved as a mathematical guarantee.
49
+
50
+ ## Install
51
+
52
+ ```bash
53
+ pip install viewspec
54
+ ```
55
+
56
+ Requires Python 3.11+.
57
+
58
+ ## Demos
59
+
60
+ Six interactive demos at [viewspec.dev](https://viewspec.dev):
61
+
62
+ | Demo | What it shows |
63
+ |------|--------------|
64
+ | [Same Data, Three Motifs](https://viewspec.dev/motif-switcher/) | One dataset → table, dashboard, or comparison. Change one parameter. |
65
+ | [Provenance Inspector](https://viewspec.dev/provenance-inspector/) | Hover any element. Trace DOM → IR → binding → address → raw data. |
66
+ | [Live Builder](https://viewspec.dev/live-builder/) | Browse ViewSpec JSON, IR tree, and rendered output in sync. |
67
+ | [The Invariants](https://viewspec.dev/invariants/) | Watch the compiler enforce — and refuse — each guarantee. |
68
+ | [15 Lines → Full UI](https://viewspec.dev/fifteen-lines/) | An invoice table builds itself from 15 lines of Python. |
69
+ | [Style Derivation](https://viewspec.dev/style-derivation/) | Same structure, different feel. Toggle four visual presets. |
70
+
71
+ Text rendering powered by [Pretext](https://github.com/chenglou/pretext) canvas surfaces.
72
+
73
+ ## Core Concepts
74
+
75
+ ### Semantic Substrate
76
+
77
+ The raw data graph. Nodes with typed attributes, slots, and edges. This is WHAT the data is — no visual intent.
78
+
79
+ ```python
80
+ builder = ViewSpecBuilder("my_view")
81
+ builder.add_node("user_1", "person", attrs={"name": "Alice", "role": "Engineer"})
82
+ builder.add_node("user_2", "person", attrs={"name": "Bob", "role": "Designer"})
83
+ ```
84
+
85
+ ### ViewSpec
86
+
87
+ The declarative intent layer. Regions (WHERE data can go), bindings (WHICH data goes WHERE), motifs (HOW it should be structured), and styles (how it should FEEL).
88
+
89
+ ```python
90
+ table = builder.add_table("team", region="main", group_id="members")
91
+ table.add_row(label="Alice", value="Engineer")
92
+ table.add_row(label="Bob", value="Designer")
93
+ ```
94
+
95
+ ### CompositionIR
96
+
97
+ The compiler's output. A strict hierarchical tree of 12 UI primitives (`root`, `stack`, `grid`, `cluster`, `surface`, `text`, `label`, `value`, `badge`, `image_slot`, `rule`, `svg`) with full provenance tracking. Every IR node knows which semantic addresses and intent refs produced it.
98
+
99
+ ### Emitters
100
+
101
+ Pluggable renderers that turn CompositionIR into concrete output. Subclass `EmitterPlugin`:
102
+
103
+ ```python
104
+ from viewspec.emitters.base import EmitterPlugin
105
+
106
+ class MyEmitter(EmitterPlugin):
107
+ def emit(self, ast_bundle, output_dir):
108
+ # Walk ast_bundle.result.root.root and produce output
109
+ ...
110
+ ```
111
+
112
+ The included HTML/Tailwind emitter produces standalone HTML with full Tailwind styling, provenance data attributes on every DOM element, action event dispatch, and a JSON provenance manifest.
113
+
114
+ ## Motif Types
115
+
116
+ | Builder | Motif | Use case |
117
+ |---------|-------|----------|
118
+ | `add_table()` | `table` | Tabular data with label-value rows |
119
+ | `add_dashboard()` | `dashboard` | KPI cards with label-value pairs |
120
+ | `add_outline()` | `outline` | Hierarchical outlines and trees |
121
+ | `add_comparison()` | `comparison` | Side-by-side comparisons |
122
+
123
+ Each builder returns a chained sub-builder. Compose them freely within a single ViewSpec.
124
+
125
+ ## Compilation
126
+
127
+ ### Reference Compiler (free, offline)
128
+
129
+ Handles the four standard motifs locally. No API, no network, no LLM. Deterministic.
130
+
131
+ ```python
132
+ ast = compile(builder.build_bundle())
133
+ ```
134
+
135
+ ### Hosted Compiler (api.viewspec.dev)
136
+
137
+ For complex layouts, novel data shapes, and advanced derivation. The hosted compiler was **evolved** (not hand-written) using reinforcement learning:
138
+
139
+ - **13/13** on a static validation suite
140
+ - **50/50** on novel, randomized out-of-distribution layouts (one-shot)
141
+ - **Level 2 derivation tokens** — data-aware emphasis, narrative routing, palette energy
142
+ - **Zero LLM cost at runtime** — deterministic Python, ~3ms per compile
143
+
144
+ ```python
145
+ from viewspec import compile_auto
146
+
147
+ # Try local first, fall back to hosted for unsupported motifs
148
+ ast = compile_auto(builder.build_bundle())
149
+ ```
150
+
151
+ | Tier | Price | Hosted Calls/Day |
152
+ |------|-------|-----------------|
153
+ | Free | $0 | 500 |
154
+ | Pro | $39/mo | 25,000 |
155
+ | Scale | $99/mo | 250,000 |
156
+ | Enterprise | Contact | Custom |
157
+
158
+ ## Wire Format
159
+
160
+ Protocol Buffers for language-agnostic serialization. The same ViewSpec can be constructed in Python, Rust, Go, TypeScript, or any language with protobuf support.
161
+
162
+ ```python
163
+ bundle = builder.build_bundle()
164
+ json_data = bundle.to_json() # JSON round-trip
165
+ proto_bytes = bundle.to_proto().SerializeToString() # Protobuf round-trip
166
+ ```
167
+
168
+ ## Examples
169
+
170
+ See [`examples/`](examples/):
171
+
172
+ - **`invoice_table.py`** — Build a table in 15 lines
173
+ - **`kpi_dashboard.py`** — KPI dashboard with style tokens
174
+ - **`comparison_view.py`** — Side-by-side comparison
175
+ - **`emit_html.py`** — Load a compiled AST and emit HTML
176
+
177
+ ## License
178
+
179
+ MIT
@@ -0,0 +1 @@
1
+ viewspec.dev
@@ -0,0 +1,96 @@
1
+ # Demo: 15 Lines → Full UI
2
+
3
+ ## What It Proves
4
+ The ratio between intent and output is extreme. Fifteen lines of semantic description produces a complete, styled, provenance-tracked UI. No components. No layout code. No CSS.
5
+
6
+ ## Behavior
7
+
8
+ Split screen. Left: Python code. Right: rendered output.
9
+
10
+ The code appears line by line (typewriter effect, ~80ms per character, ~400ms pause between lines). As each semantically meaningful line completes, the rendered output on the right updates to include the new element. The build-up is progressive — the user watches the UI construct itself from semantic declarations.
11
+
12
+ ### The Code (15 lines)
13
+ ```python
14
+ from viewspec import ViewSpecBuilder
15
+
16
+ builder = ViewSpecBuilder("invoice")
17
+
18
+ table = builder.add_table("items", region="main", group_id="rows")
19
+ table.add_row(label="Design System Audit", value="$4,200")
20
+ table.add_row(label="Component Library", value="$8,500")
21
+ table.add_row(label="API Integration", value="$3,100")
22
+ table.add_row(label="QA & Testing", value="$2,800")
23
+ table.add_row(label="Documentation", value="$1,400")
24
+
25
+ builder.add_style("s1", "items_row_5_label", "tone.muted")
26
+ builder.add_style("s2", "items_row_5_value", "emphasis.high")
27
+
28
+ bundle = builder.build_bundle()
29
+ ```
30
+
31
+ ### Progressive Reveal Steps
32
+ Lines 1-2 (import + builder): Empty root container appears on right
33
+ Line 4 (add_table): Table structure appears (empty, with header area)
34
+ Lines 5-9 (add_row × 5): Each row appears as the line completes
35
+ Lines 11-12 (add_style): The "Documentation" row's label dims and value bolds
36
+ Line 14 (build_bundle): A "✓ Bundle Ready" badge animates in below the table, showing binding count and provenance status
37
+
38
+ After the animation completes, a "Replay" button appears.
39
+
40
+ ## Implementation
41
+
42
+ ### Pre-generation
43
+ Write a Python script (`demos/build_fifteen_lines.py`) that:
44
+ 1. Builds the full IntentBundle
45
+ 2. Hand-builds IR trees for each progressive step (empty, table shell, 1 row, 2 rows, ..., 5 rows, styled, final)
46
+ 3. Emits HTML fragments for each step
47
+ 4. Packages into `index.html` with typewriter JS
48
+
49
+ ### HTML Structure
50
+ ```html
51
+ <div class="split-screen">
52
+ <div class="code-panel">
53
+ <div class="panel-header">
54
+ <span class="filename">invoice.py</span>
55
+ <span class="lang-badge">Python</span>
56
+ </div>
57
+ <pre><code id="code-display"></code></pre>
58
+ </div>
59
+
60
+ <div class="output-panel">
61
+ <div class="panel-header">
62
+ <span class="filename">Rendered Output</span>
63
+ <span class="live-badge">● Live</span>
64
+ </div>
65
+ <div id="output-display"></div>
66
+ </div>
67
+ </div>
68
+ ```
69
+
70
+ ### Styling
71
+ - Code panel: dark (slate-900), monospace, syntax highlighting via CSS classes
72
+ - Keywords (from, import): blue-400
73
+ - Strings: green-400
74
+ - Method calls: teal-300
75
+ - Comments: slate-500
76
+ - Output panel: light (slate-50), the normal emitter output
77
+ - Split: 50/50 on desktop, stacked on mobile (code on top)
78
+ - Cursor: blinking block cursor at end of current line during typing
79
+ - "✓ Bundle Ready" badge: slides up, green background, shows "10 bindings | 5 nodes | full provenance"
80
+
81
+ ### JS (~80 lines)
82
+ - Array of code lines with metadata: `{ text, delay, outputStep }`
83
+ - Typewriter loop: character by character with configurable speed
84
+ - On each `outputStep`, swap the output panel's innerHTML to the pre-generated fragment
85
+ - Replay button resets and restarts
86
+ - Skip button (subtle, bottom-right) jumps to final state
87
+
88
+ ## Output
89
+ `demos/fifteen-lines/index.html` — single self-contained HTML file.
90
+
91
+ ## Quality Bar
92
+ - The typing must feel natural (not robotic, slight variance in speed)
93
+ - Syntax highlighting must be accurate for Python
94
+ - The progressive reveal must feel like the UI is being BUILT, not just shown
95
+ - The final state must be a genuinely good-looking invoice table
96
+ - The ratio (15 lines → complete UI) must be felt, not just counted
@@ -0,0 +1,89 @@
1
+ # Demo: The Invariants
2
+
3
+ ## What It Proves
4
+ ViewSpec doesn't just produce correct UI — it refuses to produce incorrect UI. The three invariants (exactly-once provenance, semantic grouping, strict ordering) are enforced, visible, and unbreakable.
5
+
6
+ ## Behavior
7
+
8
+ Three sections, each demonstrating one invariant being enforced. Each section has:
9
+ - A title and one-sentence explanation
10
+ - A "Valid" example (green border, renders correctly)
11
+ - A "Violation" example (red border, shows the CompilerDiagnostic)
12
+ - A toggle to flip between them
13
+
14
+ ### Section 1: Exactly-Once Provenance
15
+
16
+ **Valid:** A table with 4 rows. Each binding routes exactly once. All data accounted for. A counter shows "4/4 bindings routed."
17
+
18
+ **Violation:** Same table but one binding is duplicated (appears in two rows). The compiler catches it: `CompilerDiagnostic { severity: "error", code: "DUPLICATE_ROUTING", message: "Binding 'row_2_value' routed to multiple IR nodes" }`. The duplicate element renders with a red dashed border and an error badge.
19
+
20
+ ### Section 2: Semantic Grouping
21
+
22
+ **Valid:** A dashboard with 3 cards. Each card's label and value are grouped by semantic boundary (same node). Groups are visually enclosed in surfaces.
23
+
24
+ **Violation:** A label from card 1 is grouped with the value from card 2 (cross-group contamination). Diagnostic: `{ code: "GROUP_VIOLATION", message: "Binding 'card_1_label' grouped with non-sibling 'card_2_value'" }`. The mismatched elements highlight with connecting red lines.
25
+
26
+ ### Section 3: Strict Ordering
27
+
28
+ **Valid:** A table where rows appear in the order they were declared in the substrate. Row 1 → Row 2 → Row 3 → Row 4.
29
+
30
+ **Violation:** Rows reordered (Row 1 → Row 3 → Row 2 → Row 4). Diagnostic: `{ code: "ORDER_VIOLATION", message: "Binding 'row_3_label' precedes 'row_2_label' but was declared after it in the substrate" }`. The out-of-order rows get numbered badges showing declared order vs rendered order.
31
+
32
+ ## Implementation
33
+
34
+ ### Pre-generation
35
+ Write a Python script (`demos/build_invariants.py`) that:
36
+ 1. For each invariant, builds a valid IntentBundle and a deliberately broken one
37
+ 2. Hand-builds correct IR trees for valid cases
38
+ 3. Hand-builds broken IR trees with `CompilerDiagnostic` entries for violation cases
39
+ 4. Emits both via `HtmlTailwindEmitter`
40
+ 5. Wraps in `index.html` with toggle JS
41
+
42
+ ### HTML Structure
43
+ ```html
44
+ <section class="invariant">
45
+ <h2>Exactly-Once Provenance</h2>
46
+ <p>Every data binding is routed exactly once. Nothing dropped. Nothing duplicated.</p>
47
+
48
+ <div class="toggle-group">
49
+ <button data-state="valid" class="active">✓ Valid</button>
50
+ <button data-state="violation">✗ Violation</button>
51
+ </div>
52
+
53
+ <div class="demo-container">
54
+ <div class="state-valid active">
55
+ <!-- valid rendered HTML with green border -->
56
+ <div class="status-bar valid">✓ 4/4 bindings routed exactly once</div>
57
+ </div>
58
+ <div class="state-violation">
59
+ <!-- violation rendered HTML with red border -->
60
+ <div class="diagnostic">
61
+ <span class="severity error">ERROR</span>
62
+ <span class="code">DUPLICATE_ROUTING</span>
63
+ <span class="message">Binding 'row_2_value' routed to multiple IR nodes</span>
64
+ </div>
65
+ </div>
66
+ </div>
67
+ </section>
68
+ ```
69
+
70
+ ### Styling
71
+ - Valid state: thin green-500 left border on the container
72
+ - Violation state: thin red-500 left border, diagnostic card below with monospace text
73
+ - Error elements within violations: red dashed border, semi-transparent red overlay
74
+ - Status bar: full-width bar below the rendered output showing pass/fail
75
+ - Diagnostic cards styled like compiler output (dark bg, monospace, severity badge)
76
+ - Subtle shake animation on the violation elements when toggled to (150ms, 2px)
77
+
78
+ ### JS (~30 lines)
79
+ Per-section toggle between valid and violation states.
80
+
81
+ ## Output
82
+ `demos/invariants/index.html` — single self-contained HTML file.
83
+
84
+ ## Quality Bar
85
+ - The violations must look genuinely broken, not just annotated
86
+ - The diagnostics must read like real compiler output
87
+ - The valid examples must feel solid and trustworthy
88
+ - The contrast between valid and violation should be visceral
89
+ - Someone watching should think "I want my UI to have this"