tutuca 0.15.0 → 1.0.0-beta.2

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 (170) hide show
  1. package/CHANGELOG.md +132 -0
  2. package/LICENSE +1 -1
  3. package/README.md +64 -170
  4. package/{dist → deps}/immer.js +674 -249
  5. package/dist/tutuca.js +2342 -4057
  6. package/dist/tutuca.min.js +3 -3
  7. package/package.json +78 -96
  8. package/src/component.js +66 -0
  9. package/src/css/classes.js +77 -0
  10. package/src/dev/formatters.js +393 -0
  11. package/src/dev/jsonml.js +35 -0
  12. package/src/dev/panel.js +400 -0
  13. package/src/dev/summary.js +239 -0
  14. package/src/dev/vdom-formatters.js +102 -0
  15. package/src/drag.js +23 -0
  16. package/src/embed/element.js +111 -0
  17. package/src/env.js +30 -0
  18. package/src/events.js +85 -0
  19. package/src/history/bar.js +198 -0
  20. package/src/history/index.js +149 -0
  21. package/src/host.js +360 -0
  22. package/src/lint/index.js +470 -0
  23. package/src/meta.js +12 -0
  24. package/src/optimize.js +58 -0
  25. package/src/paths.js +205 -0
  26. package/src/playground/element.js +360 -0
  27. package/src/playground/index.js +5 -0
  28. package/src/playground/sources.js +107 -0
  29. package/src/playground/ui/playground.js +287 -0
  30. package/src/schema.js +460 -0
  31. package/src/scope.js +92 -0
  32. package/src/storybook/index.js +80 -0
  33. package/src/storybook/runner.js +452 -0
  34. package/src/storybook/stories.js +208 -0
  35. package/src/storybook/stress.js +76 -0
  36. package/src/storybook/ui/common.js +37 -0
  37. package/src/storybook/ui/link.js +80 -0
  38. package/src/storybook/ui/panels.js +32 -0
  39. package/src/storybook/ui/story-panel.js +432 -0
  40. package/src/storybook/ui/storybook.js +191 -0
  41. package/src/storybook/ui/stress-panel.js +231 -0
  42. package/src/sync/automerge.js +159 -0
  43. package/src/sync/codec.js +206 -0
  44. package/src/sync/diff.js +153 -0
  45. package/src/sync/index.js +97 -0
  46. package/src/sync/migrate.js +184 -0
  47. package/src/sync/ops.js +160 -0
  48. package/src/sync/remote.js +206 -0
  49. package/src/tag.js +24 -0
  50. package/src/tasks.js +244 -0
  51. package/src/test/driver.js +141 -0
  52. package/src/test/pbt.js +589 -0
  53. package/src/tutuca.js +66 -0
  54. package/src/vdom.js +349 -0
  55. package/src/view.js +354 -0
  56. package/src/walk.js +79 -0
  57. package/dist/chai.js +0 -4210
  58. package/dist/tutuca-cli.js +0 -16315
  59. package/dist/tutuca-components.js +0 -2232
  60. package/dist/tutuca-dev.ext.js +0 -8476
  61. package/dist/tutuca-dev.js +0 -13220
  62. package/dist/tutuca-dev.min.js +0 -5
  63. package/dist/tutuca-extra.ext.js +0 -4261
  64. package/dist/tutuca-extra.js +0 -4964
  65. package/dist/tutuca-extra.min.js +0 -3
  66. package/dist/tutuca-storybook.js +0 -970
  67. package/dist/tutuca.ext.js +0 -4183
  68. package/skill/margaui/SKILL.md +0 -105
  69. package/skill/margaui/components/accordion.md +0 -127
  70. package/skill/margaui/components/alert.md +0 -174
  71. package/skill/margaui/components/aura.md +0 -97
  72. package/skill/margaui/components/avatar.md +0 -220
  73. package/skill/margaui/components/badge.md +0 -193
  74. package/skill/margaui/components/breadcrumbs.md +0 -103
  75. package/skill/margaui/components/button.md +0 -322
  76. package/skill/margaui/components/calendar.md +0 -67
  77. package/skill/margaui/components/card.md +0 -373
  78. package/skill/margaui/components/carousel.md +0 -387
  79. package/skill/margaui/components/chat.md +0 -171
  80. package/skill/margaui/components/checkbox.md +0 -101
  81. package/skill/margaui/components/collapse.md +0 -172
  82. package/skill/margaui/components/countdown.md +0 -165
  83. package/skill/margaui/components/diff.md +0 -53
  84. package/skill/margaui/components/divider.md +0 -107
  85. package/skill/margaui/components/dock.md +0 -173
  86. package/skill/margaui/components/drawer.md +0 -184
  87. package/skill/margaui/components/dropdown.md +0 -388
  88. package/skill/margaui/components/fab.md +0 -346
  89. package/skill/margaui/components/fieldset.md +0 -88
  90. package/skill/margaui/components/file-input.md +0 -84
  91. package/skill/margaui/components/filter.md +0 -52
  92. package/skill/margaui/components/footer.md +0 -583
  93. package/skill/margaui/components/hero.md +0 -135
  94. package/skill/margaui/components/hover-3d.md +0 -129
  95. package/skill/margaui/components/hover-gallery.md +0 -49
  96. package/skill/margaui/components/indicator.md +0 -265
  97. package/skill/margaui/components/input.md +0 -389
  98. package/skill/margaui/components/join.md +0 -100
  99. package/skill/margaui/components/kbd.md +0 -127
  100. package/skill/margaui/components/label.md +0 -102
  101. package/skill/margaui/components/link.md +0 -96
  102. package/skill/margaui/components/list.md +0 -182
  103. package/skill/margaui/components/loading.md +0 -105
  104. package/skill/margaui/components/mask.md +0 -168
  105. package/skill/margaui/components/megamenu.md +0 -131
  106. package/skill/margaui/components/menu.md +0 -887
  107. package/skill/margaui/components/mockup-browser.md +0 -39
  108. package/skill/margaui/components/mockup-code.md +0 -81
  109. package/skill/margaui/components/mockup-phone.md +0 -39
  110. package/skill/margaui/components/mockup-window.md +0 -33
  111. package/skill/margaui/components/modal.md +0 -196
  112. package/skill/margaui/components/navbar.md +0 -282
  113. package/skill/margaui/components/otp.md +0 -171
  114. package/skill/margaui/components/pagination.md +0 -122
  115. package/skill/margaui/components/progress.md +0 -135
  116. package/skill/margaui/components/radial-progress.md +0 -67
  117. package/skill/margaui/components/radio.md +0 -133
  118. package/skill/margaui/components/range.md +0 -134
  119. package/skill/margaui/components/rating.md +0 -170
  120. package/skill/margaui/components/select.md +0 -225
  121. package/skill/margaui/components/skeleton.md +0 -64
  122. package/skill/margaui/components/stack.md +0 -142
  123. package/skill/margaui/components/stat.md +0 -254
  124. package/skill/margaui/components/status.md +0 -73
  125. package/skill/margaui/components/steps.md +0 -138
  126. package/skill/margaui/components/swap.md +0 -152
  127. package/skill/margaui/components/tab.md +0 -248
  128. package/skill/margaui/components/table.md +0 -1018
  129. package/skill/margaui/components/text-rotate.md +0 -91
  130. package/skill/margaui/components/textarea.md +0 -85
  131. package/skill/margaui/components/theme-controller.md +0 -266
  132. package/skill/margaui/components/timeline.md +0 -1356
  133. package/skill/margaui/components/toast.md +0 -165
  134. package/skill/margaui/components/toggle.md +0 -135
  135. package/skill/margaui/components/tooltip.md +0 -181
  136. package/skill/margaui/components/validator.md +0 -163
  137. package/skill/tutuca/SKILL.md +0 -56
  138. package/skill/tutuca/advanced.md +0 -292
  139. package/skill/tutuca/cli.md +0 -239
  140. package/skill/tutuca/component-design.md +0 -168
  141. package/skill/tutuca/core.md +0 -935
  142. package/skill/tutuca/iteration.md +0 -207
  143. package/skill/tutuca/macros.md +0 -86
  144. package/skill/tutuca/margaui.md +0 -175
  145. package/skill/tutuca/messages-and-intents.md +0 -414
  146. package/skill/tutuca/patterns/README.md +0 -48
  147. package/skill/tutuca/patterns/add-a-story.md +0 -26
  148. package/skill/tutuca/patterns/bind-text-and-attributes.md +0 -30
  149. package/skill/tutuca/patterns/conditional-attribute-value.md +0 -29
  150. package/skill/tutuca/patterns/coordinate-components.md +0 -54
  151. package/skill/tutuca/patterns/edit-through-a-dynamic-target.md +0 -32
  152. package/skill/tutuca/patterns/enrich-each-item.md +0 -25
  153. package/skill/tutuca/patterns/file-input.md +0 -39
  154. package/skill/tutuca/patterns/filter-a-list.md +0 -25
  155. package/skill/tutuca/patterns/filter-and-paginate.md +0 -60
  156. package/skill/tutuca/patterns/handle-events.md +0 -45
  157. package/skill/tutuca/patterns/iterate-a-list.md +0 -18
  158. package/skill/tutuca/patterns/paginate-a-list.md +0 -29
  159. package/skill/tutuca/patterns/render-a-child-component.md +0 -21
  160. package/skill/tutuca/patterns/reuse-markup-with-macros.md +0 -36
  161. package/skill/tutuca/patterns/share-state-across-the-tree.md +0 -53
  162. package/skill/tutuca/patterns/show-or-hide-content.md +0 -23
  163. package/skill/tutuca/patterns/switch-between-views.md +0 -30
  164. package/skill/tutuca/patterns/tabbed-interface.md +0 -43
  165. package/skill/tutuca/semantics.md +0 -219
  166. package/skill/tutuca/storybook.md +0 -270
  167. package/skill/tutuca/styles.md +0 -48
  168. package/skill/tutuca/testing.md +0 -345
  169. package/skill/tutuca-source/SKILL.md +0 -33
  170. package/skill/tutuca-source/tutuca.ext.js +0 -4183
package/CHANGELOG.md ADDED
@@ -0,0 +1,132 @@
1
+ # Changelog
2
+
3
+ ## 1.0.0-beta.2
4
+
5
+ Messages are delivered by identity as well as by path, following the tree model in
6
+ `spec/tree`: a reply, a `sendAt` or a notification's next hop no longer reaches whatever
7
+ component took the path in the meantime. See [`docs/paths.md`](docs/paths.md).
8
+
9
+ ### Breaking
10
+
11
+ - **Asks are answered in an `answers` section.** `answers: { load: { ok, error, unhandled } }`
12
+ replaces the `xReplyOk` / `xReplyError` / `xHandlerNotFound` messages, and a send can't forge
13
+ one. `ctx.ask` returns a request id, which the answer's handler reads as `ctx.request`.
14
+ Stories answer asks with `step.answer`, tests with `driver.answer`. The lint checks the
15
+ section and warns about an ask a message emits with no answers for it.
16
+ - **An ask handler only answers.** It's called with the ask's arguments and `ctx.readOnly()`,
17
+ a frozen view of the asker's scope, path, source key and `now` / `random` / `uuid`, with
18
+ nothing to send with. The ask starts once the task that asked commits, so a failed task
19
+ never starts one, and its answer runs as a task of its own; an answer that throws fails only
20
+ itself.
21
+ - **A task made outside a handler is addressed with `task.prepare(root)`.**
22
+ `Host.prepareTask` is gone.
23
+ - **A message's context stages what its handler sends** in its own list, which the host
24
+ queues once the task commits.
25
+
26
+ ### Changes
27
+
28
+ - **Messages carry a sender and a receiver `Address`**, each a path and the identity it
29
+ reached. Every component instance has an identity, fresh when it's made or when a handler
30
+ returns a new one, and kept by updates. `ctx.reply(name, args)` sends to the sender of the
31
+ message being handled; `HOST` is the sender of DOM events and ask answers. A task whose
32
+ receiver was replaced is dropped and reported `stale`; one whose path reaches no component is
33
+ reported `orphaned`.
34
+ - **Notifications bubble in one turn.** Their hops are the sender's ancestors when the
35
+ bubble starts and run back to back, ahead of the queue. An ancestor without a handler passes
36
+ one on silently; one that no hop handled is reported `unhandled` once, at the root.
37
+ - **A message with no handler is a no-op that's reported** (`Host.notify("unhandled", { task,
38
+ message })`), whatever sent it, a DOM event included: components compose dynamically, so a
39
+ view can send a message its component lacks.
40
+ - **The host reports instead of throwing**: a render that throws is `renderFailed`, an event
41
+ the DOM can't route is `eventFailed`, and a stopped host drops late tasks.
42
+ - A handler's `emits` contract counts only what that handler emitted.
43
+ - `sourceKey` is `null` for a sender in another branch.
44
+ - Records and `oneOf` defaults meet the constraints of what they are made of: a record key
45
+ whose default breaks its constraints throws `NoDefaultError` naming the key, and a `oneOf`
46
+ makes its first alternative.
47
+
48
+ ### Fixes
49
+
50
+ - Morphing matches vnodes only to the nodes render made, so nodes other code puts in a
51
+ rendered element (an extension, a third-party widget, a foreign comment) stay in place.
52
+ - Routing and drags read `data-eid`, `data-dragtype` and the drag marks as attributes instead of
53
+ through `dataset`, which MathML elements lack, so a click on a formula reaches its handler.
54
+ - The vdom prebuilds constant children and elements once per view, and decides by itself
55
+ which attributes must stay dynamic.
56
+
57
+ ## 1.0.0-beta.1
58
+
59
+ Tutuca 1.0 is a rewrite. It keeps the core ideas of 0.x, but the API, the view language and the
60
+ tooling change a lot, so 0.x apps don't run on it without being ported. The 0.x line ends at
61
+ 0.15.0.
62
+
63
+ ### What stays the same
64
+
65
+ - **One immutable state tree.** The app state is a tree of component instances, and every
66
+ update replaces the root with a new value. Views are functions of that state.
67
+ - **Handlers mutate a draft.** A handler gets an immer draft and changes it in place.
68
+ Returning a value replaces the component. immer is still vendored, so the core has no npm
69
+ dependencies.
70
+ - **Typed fields and named views.** Components declare typed `fields`, a `main` view plus other
71
+ named views, and `methods` that views and handlers can read.
72
+ - **Rendering through paths.** The DOM holds no references to instances. Events are routed
73
+ through the dispatch path recorded at render time, and the update goes back in through the
74
+ path to the value that owns it.
75
+ - **Messages up, down and across.** A component handles its own events, can send messages to
76
+ components found by a selector, and can raise a message that bubbles up to its parents. A
77
+ request with `Ok` / `Error` replies becomes `ask` with `ReplyOk` / `ReplyError`.
78
+ - **Values passed down without threading them through props.** 0.x's `provide` / `lookup` is
79
+ now `provides` / `lookupBind`.
80
+ - **Iteration with filters and loop state** (`each` and loops, which were `@each`, `@when` and
81
+ `@loop-with`), **pushed views** for nested components, and **drag and drop**.
82
+ - **The checks are part of the library**: a linter, tests that run without a browser, and a
83
+ storybook built from the same component definitions.
84
+
85
+ ### What changes
86
+
87
+ - **Views are built in JavaScript, not parsed from HTML.** `h(tag, attrs, ...children)`, the
88
+ `tag` / `button` builders and AST helpers (`field`, `send`, `each`, `render`, `$if`,
89
+ `pushView`, `scope`, ...) replace the `html\`...\`` templates, the `@`/`:` directives and the
90
+ value grammar (`.x`, `$x`, `@x`, `^x`, `*x`). Macros are gone; use JavaScript functions that
91
+ return view nodes.
92
+ - **Explicit schemas.** Field types come from `t.*` (`t.number()`, `t.string()`, `t.array()`,
93
+ `t.option()`, `t.enum()`, `t.record()`, `t.oneOf()`, `t.map()`, `t.component()`, ...) rather than being inferred
94
+ from default values. They feed validation, the lint, property-based tests and sync.
95
+ - **Handlers.** `receive` and `intent` merge into one `on` table. A handler is called as
96
+ `handler(next, args, ctx)`, with `next` being the draft, and can declare a contract (`args`,
97
+ `sourceKey`, `pre`, `post`, `emits`). Components can declare `invariants`. Contracts and
98
+ invariants are checked in development and in tests.
99
+ - **The host.** `tutuca("#app")`, `registerComponents` and `app.state.set` are replaced by
100
+ `new Host({ document, rootNode })`, `host.scope.register({...})` and `host.start(instance)`.
101
+ Scopes nest, and they also hold the handlers that answer `ask`.
102
+ - **A controlled world.** Handlers read time and randomness through `ctx.now()`,
103
+ `ctx.random()` and `ctx.uuid()`, so test runs and sync replays repeat.
104
+ - **Styling.** The scoped `style` / `commonStyle` / `globalStyle` CSS is gone. `tutuca/classes`
105
+ lists the class names a view uses, for CSS tools that need them.
106
+ - **Packaging.** The package ships its ES module sources (`src/`) with one export per area
107
+ (`tutuca`, `/vdom`, `/dev`, `/lint`, `/classes`, `/pbt`, `/storybook`, `/element`,
108
+ `/playground`, `/history`, `/sync`, `/sync/remote`, `/automerge`). The CDN bundles are
109
+ `dist/tutuca.js` and `dist/tutuca.min.js`. jsdom, prettier and chai are no longer
110
+ dependencies. `fast-check` and `@automerge/automerge` are optional peers.
111
+ - **Removed:** the `tutuca` CLI (`get`, `list`, `show`, `lint`, `render`, `test`,
112
+ `storybook`, `install-skill`, `agent-context`, ...), the bundled agent skill, the
113
+ `tutuca/components` inspector components, the `getTests()` / `getExamples()` module
114
+ conventions and the `.dev.js` auto-discovery. The linter, tests and storybook are now used
115
+ as libraries.
116
+
117
+ ### New
118
+
119
+ - **Property-based testing** (`tutuca/pbt`): arbitraries generated from field schemas and a
120
+ headless `Driver` that runs message sequences and shrinks failures.
121
+ - **Sync** (`tutuca/sync`, `tutuca/sync/remote`, `tutuca/automerge`): a schema-guided diff,
122
+ per-field sync levels and pluggable engines that persist state or share it across tabs and
123
+ devices. State saved by another version of the components is adapted and reported. See
124
+ [`docs/sync.md`](docs/sync.md).
125
+ - **History** (`tutuca/history`, `tutuca/history/bar`): step through states one user action
126
+ at a time. Going back is applied as a change, so storage and peers follow.
127
+ - **Storybook stress tests**, with a log of each run and its shrink attempts.
128
+ - **`<tutuca-app>`** (`tutuca/element`) and **`<tutuca-playground>`**
129
+ (`tutuca/playground`), which edits a book of stories in CodeMirror and runs it live, keeping
130
+ state across edits.
131
+ - **DevTools formatters and an inspector panel** (`tutuca/dev`).
132
+ - **A formal model** of the semantics in PLT Redex (`spec/`), kept in sync with `src/`.
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 Mariano Guerra
3
+ Copyright (c) 2025-2026 Mariano Guerra
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,193 +1,87 @@
1
1
  # Tutuca
2
2
 
3
- Batteries included SPA framework with a dependency-free browser bundle.
4
-
5
- - **Single file, no build, no dependencies, no setup** — a script tag is all you need
6
- - **Batteries included** — state management, side effects, automatic memoization, drag and drop, testing, CLI tooling, LLM skills and more
7
- - **Fits in your head** (and the context window)
8
- - **View source friendly** — step through the whole stack
9
- - **As much HTML as possible, as little JS as needed**
10
- - ~110KB minified, ~29KB brotli compressed (the core browser bundle; the dev build adds linting and test helpers)
11
-
12
- ## Quick Start
13
-
14
- For an interactive walk-through with editable examples, see the
15
- [tutorial](https://marianoguerra.github.io/tutuca/tutorial.html).
16
- Upgrading an Immutable.js-based app? See the
17
- [Immer migration guide](./docs/immer-migration.md).
18
-
19
- ### CDN (no install)
20
-
21
- ```html
22
- <!doctype html>
23
- <html lang="en">
24
- <head>
25
- <meta charset="UTF-8" />
26
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
27
- <title>Tutuca: Getting Started</title>
28
- </head>
29
- <body>
30
- <div id="app"></div>
31
- <script type="module">
32
- import { component, html, tutuca } from "https://cdn.jsdelivr.net/npm/tutuca/+esm";
33
-
34
- const Counter = component({
35
- name: "Counter",
36
- fields: {
37
- count: 0,
38
- },
39
- receive: {
40
- inc(draft) {
41
- draft.count++;
42
- },
43
- dec(draft) {
44
- draft.count--;
45
- },
46
- },
47
- view: html`<div>
48
- <button @on.click="dec">-</button>
49
- <div @text=".count"></div>
50
- <button @on.click="inc">+</button>
51
- </div>`,
52
- });
53
-
54
- function main() {
55
- const app = tutuca("#app");
56
- app.state.set(Counter.make({}));
57
- app.registerComponents([Counter]);
58
- app.start();
59
- }
60
-
61
- main();
62
- </script>
63
- </body>
64
- </html>
65
- ```
66
-
67
- ## Concepts at a Glance
68
-
69
- Each concept has a tutorial section with editable live examples:
70
-
71
- - **[Components & state](https://marianoguerra.github.io/tutuca/tutorial.html#basics)** —
72
- typed `fields`, Immer draft-first handlers, and views as pure functions of a
73
- single immutable state tree
74
- ([state & updates](https://marianoguerra.github.io/tutuca/tutorial.html#state-and-updates))
75
- - **[Collections](https://marianoguerra.github.io/tutuca/tutorial.html#collections)** —
76
- iterate with `@each`, filter with `@when`, paginate with `@loop-with`
77
- - **[Rendering components](https://marianoguerra.github.io/tutuca/tutorial.html#rendering-components)** —
78
- compose with `<x render>`, multiple views per component, scoped styles
79
- - **[Component communication](https://marianoguerra.github.io/tutuca/tutorial.html#component-communication)** —
80
- send messages to a target, or raise an intent and let a route find whoever
81
- answers it
82
- - **[Macros](https://marianoguerra.github.io/tutuca/tutorial.html#macros)** —
83
- reusable markup fragments with parameters and slots
84
- - **[Escape hatches](https://marianoguerra.github.io/tutuca/tutorial.html#escape-hatches)** —
85
- drag and drop, web components, raw HTML
86
- - **[Testing](https://marianoguerra.github.io/tutuca/tutorial.html#testing)** —
87
- `getTests()` suites run by the CLI or in the browser, plus a
88
- [linter](https://marianoguerra.github.io/tutuca/tutorial.html#linter-reference)
89
- that catches template mistakes before they render blank
90
-
91
- ## CLI
92
-
93
- Tutuca ships a single-file CLI (`dist/tutuca-cli.js`) for inspecting, linting,
94
- documenting, and rendering components defined in an ES module. The module just
95
- needs to export `getComponents()` and, for render-time commands, `getExamples()`
96
- in the storybook shape `{ title, description?, items: [{ title, description?, value, view? }] }` (a single section, or an array of sections).
97
- Expose **all** of your app's components through `getComponents()` — components
98
- left out are invisible to `lint`/`render`/`test` and silently lose coverage.
99
-
100
- ### Setup
101
-
102
- ```sh
103
- npm install --save-dev tutuca
104
- ```
3
+ A small framework for web apps in the browser, small enough to read in full, for people and for
4
+ coding agents.
105
5
 
106
- The package exposes `tutuca` via `bin`, so `npx tutuca` (or a global `npm i -g tutuca`) just works. `jsdom` (needed by `render` and `lint`) and `prettier` (used by `--pretty`) ship as regular dependencies and are installed automatically.
6
+ Tutuca covers components, typed state, rendering and event handling, and the tools to check them:
7
+ tests that run without a browser, property-based tests generated from your field types, a
8
+ storybook with stress tests, and a linter. State changes can be saved or shared with other tabs
9
+ and devices through sync engines you plug in ([`docs/sync.md`](docs/sync.md)). A formal model of
10
+ the semantics is being written in PLT Redex (`spec/`). The core is about 2,000 lines of
11
+ JavaScript with no npm dependencies (it includes a copy of immer).
107
12
 
108
- ### Commands
13
+ - Site: https://marianoguerra.github.io/tutuca/
14
+ - Storybook: https://marianoguerra.github.io/tutuca/storybook.html
109
15
 
110
- ```
111
- tutuca <command> <module-path> [args] [flags]
112
- tutuca help [command]
113
- ```
114
-
115
- | Command | What it does |
116
- |---|---|
117
- | `get <module>` | Export inventory and counts for the module |
118
- | `list <module> [name] [--limit n]` | List components and their fields/views (`--limit n` caps, `0` = all) |
119
- | `examples <module> [--limit n]` | List the examples defined in the module's section (`--limit n` caps, `0` = all) |
120
- | `show <module> [name]` | Component API docs — all, or one by name |
121
- | `lint <module> [name]` | Run lint checks — all, or one by name (exit `2` on errors) |
122
- | `render <module> [name] [--title t] [--view v]` | Render examples to HTML (exit `3` on render crash) |
123
- | `test <module> [name] [--grep p] [--bail]` | Run `getTests()` (exit `4` on failures) |
124
- | `storybook [dir]` | Serve a live storybook, auto-discovering co-located `*.dev.js` modules (`--port`, `--out`, `--dry-run`, `--no-margaui`, `--no-check`, `--no-tests`; no module path needed) |
125
- | `feedback [message]` | Append a feedback note (positional or stdin) to `~/.tutuca/feedback.jsonl` (no module path needed) |
126
- | `install-skill [--user\|--project] [--margaui-skill\|--all] [--dot-agents] [--dry-run] [--force]` | Install bundled Claude Code skills (no module path needed) |
127
- | `agent-context` | Print a versioned JSON schema of the entire CLI surface (no module path needed) |
128
-
129
- Global flags: `--json`, `-f, --format <cli\|md\|json\|html>`, `-o, --output <file>`, `--pretty`, `--module <path>`, `-h, --help`.
130
-
131
- `storybook` wires [MargaUI](https://github.com/marianoguerra/margaui) — a
132
- Tailwind v4 / daisyUI-compatible class library — by default; `--no-margaui`
133
- skips it. For the full flag reference, error codes, and "did you mean"
134
- behavior, run `tutuca help <command>`, or `tutuca agent-context` for a
135
- machine-readable schema of the whole surface.
136
-
137
- ### Usage examples
16
+ ## Install
138
17
 
139
18
  ```sh
140
- # Summary of what the module exports
141
- npx tutuca get ./src/components.js
19
+ npm install tutuca
20
+ ```
142
21
 
143
- # API docs for one component, as markdown
144
- npx tutuca show ./src/components.js Button --format md -o docs/button.md
22
+ Or from a CDN, without a build step:
145
23
 
146
- # Render every example to HTML, pretty-printed
147
- npx tutuca render ./src/components.js --format html --pretty -o dist/examples.html
24
+ ```js
25
+ import { component, h, Host } from "https://cdn.jsdelivr.net/npm/tutuca/dist/tutuca.min.js";
26
+ ```
148
27
 
149
- # Post-edit verification: lint, then render the example covering the
150
- # feature you just changed.
151
- npx tutuca lint ./src/components.js
152
- npx tutuca render ./src/components.js --title "Disabled state"
28
+ ## Example
29
+
30
+ ```js
31
+ import { component, field, h, Host, send, t } from "tutuca";
32
+
33
+ const Counter = component({
34
+ name: "Counter",
35
+ fields: { count: t.number() },
36
+ view: h("button", { "on:click": send("inc") }, "Clicked ", field("count")),
37
+ on: {
38
+ inc(next) {
39
+ next.count += 1;
40
+ },
41
+ },
42
+ });
43
+
44
+ const host = new Host({ document, rootNode: document.getElementById("app") });
45
+ host.scope.register({ Counter });
46
+ host.start(host.scope.components.Counter());
153
47
  ```
154
48
 
155
- ## Use with Claude Code
49
+ ## Modules
156
50
 
157
- Tutuca ships an LLM-facing reference (`SKILL.md` plus topic files such as
158
- `core.md`, `cli.md`, `advanced.md`, `testing.md`, `storybook.md`, and more)
159
- packaged as a [Claude Code skill](https://docs.claude.com/en/docs/claude-code/skills).
160
- Once installed, Claude auto-loads it whenever a session touches tutuca
161
- components, views, macros, or the CLI.
51
+ | Import | What |
52
+ |---|---|
53
+ | `tutuca` | components, views, schemas, the host, the `tag` and `button` element builders |
54
+ | `tutuca/dev` | DevTools formatters |
55
+ | `tutuca/lint` | the linter |
56
+ | `tutuca/classes` | `collectClasses`, `classNamesOf` and `ClassCompiler`, for CSS compilers that need class names listed |
57
+ | `tutuca/pbt` | property-based testing and the headless driver (bring your own `fast-check`) |
58
+ | `tutuca/storybook` | the storybook |
59
+ | `tutuca/playground` | the `<tutuca-playground>` element: edit a book of stories and run it live (bring your own CodeMirror) |
60
+ | `tutuca/element` | the `<tutuca-app>` custom element |
61
+ | `tutuca/vdom` | the virtual DOM |
62
+ | `tutuca/sync` | sync engines: projection, schema-guided diff, ops, `startSynced`, `storageEngine` |
63
+ | `tutuca/sync/remote` | an engine that sends diffs to a remote and applies the ones it sends |
64
+ | `tutuca/automerge` | an engine over an Automerge document (bring your own `@automerge/automerge`) |
162
65
 
163
- ```sh
164
- # project-scoped: writes ./.claude/skills/tutuca/ (commit it for the team)
165
- npx tutuca install-skill
66
+ ## Docs
166
67
 
167
- # or user-scoped: writes ~/.claude/skills/tutuca/
168
- npx tutuca install-skill --user
68
+ - [`docs/paths.md`](docs/paths.md): how update paths, dispatch paths and selectors route messages.
69
+ - [`docs/sync.md`](docs/sync.md): persisting and syncing state with sync engines.
70
+ - [`spec/README.md`](spec/README.md): the formal semantics in PLT Redex and how it maps to `src/`.
169
71
 
170
- # companion MargaUI skill, or install both bundled skills
171
- npx tutuca install-skill --margaui-skill
172
- npx tutuca install-skill --all
72
+ ## Development
173
73
 
174
- # install into ./.agents/skills/ instead of ./.claude/skills/
175
- npx tutuca install-skill --dot-agents
74
+ Tasks are in the `justfile`; `just` lists them.
176
75
 
177
- # overwrite an existing install
178
- npx tutuca install-skill --force
76
+ ```sh
77
+ just install # npm install
78
+ just check # lint, then test
79
+ just storybook # serve the storybook from the repo
80
+ just site # build the landing page and storybook into _site/ and serve it
81
+ just smoke # build dist/ and check what would be published
82
+ just publish # publish to npm as latest
179
83
  ```
180
84
 
181
- The skill content is generated from `docs/skill/`, so the same reference
182
- runs locally (`tutuca lint <module>` + `tutuca render <module> --title …`)
183
- and inside Claude.
184
-
185
- ## Links
186
-
187
- - [Documentation & Playground](https://marianoguerra.github.io/tutuca/)
188
- - [Tutorial](https://marianoguerra.github.io/tutuca/tutorial.html)
189
- - [GitHub](https://github.com/marianoguerra/tutuca)
190
-
191
85
  ## License
192
86
 
193
87
  MIT