htmlcraft 0.0.0-stage → 0.1.0

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.
@@ -0,0 +1,160 @@
1
+ # Authoring decks for the htmlcraft editor and MCP server
2
+
3
+ These notes cover how to write decks that stay pleasant to edit by hand, by an
4
+ agent, and in the visual editor. The contract itself lives in
5
+ [contract.md](contract.md).
6
+
7
+ ## Start from structure, then style
8
+
9
+ 1. Create the deck with `create_deck` or `htmlcraft new`. Both produce a valid
10
+ document with slide ids, the canvas size, and the real runtime.
11
+ 2. Add or replace content as top-level objects. Each object owns its position,
12
+ size, and typography.
13
+ 3. Add a `<style>` block for the shared visual language.
14
+ 4. Validate, then open the editor for human review.
15
+
16
+ Prefer one object per visual block over deeply nested layout. The editor and
17
+ MCP tools address top-level objects, so a flat structure is easier to edit and
18
+ survives round trips with fewer surprises.
19
+
20
+ ## Editor-friendly structure
21
+
22
+ - Give every top-level object an explicit `data-ppt-el`. Do not rely on a
23
+ generated id when a later call needs to address the object.
24
+ - Keep each object self-contained: position it absolutely inside the slide and
25
+ set an explicit width. Text without a width can overflow the canvas.
26
+ - Use real text nodes for content. Text inside CSS `::before`/`::after`,
27
+ background images, or SVG `<text>` is not editable through `set_text`.
28
+ - Prefer semantic elements (`h1`, `h2`, `p`, `ul`, `table`, `figure`) so the
29
+ outline reports useful summaries and tags.
30
+ - Tables are real `<table>` elements with `<thead>`/`<tbody>`; put
31
+ `data-ppt-el` on the table.
32
+ - A `data-ppt-group` wrapper groups related objects. Do not nest group
33
+ wrappers.
34
+ - Notes are a direct-child `<aside data-ppt-notes hidden>` of the slide. One
35
+ aside per slide is enough.
36
+
37
+ Example object:
38
+
39
+ ```html
40
+ <div data-ppt-el="e3" style="position: absolute; left: 140px; top: 300px; width: 900px;">
41
+ <h2 style="margin: 0; font-size: 56px;">Why it matters</h2>
42
+ <p style="margin: 24px 0 0; font-size: 30px; line-height: 1.5; color: #4a4f59;">
43
+ Keep the message in a real paragraph so it can be edited in place.
44
+ </p>
45
+ </div>
46
+ ```
47
+
48
+ ## Styling freedom
49
+
50
+ - Put shared rules in a `<style>` block: colors, type scale, shared object
51
+ classes, print rules.
52
+ - Use inline styles for object-specific position, size, and one-off styling.
53
+ `set_style` edits these properties and accepts `null` to remove one.
54
+ - CSS custom properties, gradients, shadows, filters, masks, transforms,
55
+ flexbox, grid, inline SVG, and CSS animations are all allowed.
56
+ - Web fonts must use a `data:` or absolute URL.
57
+ - Keep the fixed canvas in mind. Do not use `position: fixed` or full-height
58
+ `100vh`/`100dvh`/`100svh`/`100lvh` layouts; validation warns (`fixed-layout`)
59
+ because they may not export reliably. Other viewport units are not detected
60
+ by the validator but still scale with the browser window, so avoid them for
61
+ layout. Use absolute positioning inside the 1600x900 (or chosen) canvas.
62
+ - Animations that run on their own are preserved. There is no animation
63
+ timeline or trigger authoring in v1.
64
+
65
+ `set_slide_background` accepts exactly one of `color`, `gradient`, or `image`.
66
+ A color uses the `background` shorthand; a gradient or image uses
67
+ `background-image`, and the other form is cleared.
68
+
69
+ ## Content edits
70
+
71
+ - `set_text` replaces an element's text content and escapes HTML. Use it for
72
+ ordinary copy.
73
+ - `set_element_html` replaces inner HTML. Use it for deliberate markup changes,
74
+ then validate immediately.
75
+ - `update_slide_html` replaces a whole slide's inner HTML. Read the slide first
76
+ with `read_slide`; recreating the objects by hand risks losing ids, notes, and
77
+ styles.
78
+ - `add_element` inserts exactly one top-level element. Provide `data-ppt-el` in
79
+ the fragment when you need a stable id; otherwise the returned `elementId`
80
+ tells you the generated id.
81
+ - Removing an element uses a target. The slide itself cannot be removed this
82
+ way; use `delete_slide`, and remember the last slide cannot be deleted.
83
+ - Slide order changes use `move_slide` or `set_slide_order`; the latter must
84
+ list every slide id exactly once.
85
+
86
+ Targets for element tools are exactly one of:
87
+
88
+ ```json
89
+ { "elementId": "e3" }
90
+ { "selector": ".card > h2" }
91
+ { "path": [1, 0] }
92
+ ```
93
+
94
+ `elementId` matches `data-ppt-el` within the slide. `selector` must match
95
+ exactly one element inside the slide. `path` is child indices starting at the
96
+ slide element. Missing or ambiguous targets produce stable error codes; read
97
+ the outline before guessing.
98
+
99
+ ## Notes, transitions, charts, tables, and images
100
+
101
+ - `set_notes` writes or clears the direct-child notes aside. An empty string
102
+ removes it.
103
+ - `set_transition` accepts `none`, `fade`, or `slide`.
104
+ - Chart data lives in `data-ppt-chart` on a `<figure>` as JSON with `type`
105
+ (`bar`, `line`, or `pie`), `labels`, and `series` (`{ name, values }`
106
+ entries). Optional fields are `title`, `colors`, `legend`, and
107
+ `valueLabels`. Labels and each series' values must have the same length, and
108
+ the rendered SVG is derived from the attribute. Use `update_chart` rather
109
+ than editing the SVG. Invalid JSON is a validation error.
110
+ - Tables are real `<table>` elements. `add_table` creates one with a header
111
+ row within the 50-row and 20-column core limits.
112
+ - `add_image` accepts a data URL, an absolute http(s) URL, or a local path.
113
+ Local files are embedded as data URLs after MIME and 8 MB checks; remote
114
+ URLs are validated but never fetched. Keep assets self-contained.
115
+
116
+ ## Round-trip rules
117
+
118
+ - Slide ids are unique, non-empty, and stable. Do not renumber slides to
119
+ reorder them; use `move_slide` or `set_slide_order`.
120
+ - Object ids are unique within a slide. Do not recycle an id for a different
121
+ object.
122
+ - Never write `data-ppt-editing` or `data-ppt-frame-slide`; validation rejects
123
+ saved files containing them.
124
+ - Keep the deck self-contained: no relative asset URLs, no external
125
+ stylesheet dependency, no layout that depends on JavaScript.
126
+ - Keep one runtime script with `data-ppt-runtime="1"` and the real body.
127
+ - Export should not change the meaning of the deck. Notes, transitions, chart
128
+ JSON, and object ids survive export.
129
+
130
+ ## Revision and conflict discipline
131
+
132
+ Reads and writes are revision-checked. The MCP server remembers the last
133
+ revision per file; a host-attached editor also tracks the file revision. If the
134
+ file changes between your read and write, the write fails with
135
+ `code: "conflict"` and the file is left untouched.
136
+
137
+ On conflict:
138
+
139
+ 1. Re-read with `get_outline` or `read_slide`.
140
+ 2. Decide how to reconcile the external change. Preserve edits you did not
141
+ intend to replace.
142
+ 3. Retry the mutation.
143
+
144
+ Do not bypass a conflict by rewriting the entire deck unless the user
145
+ explicitly asks for that.
146
+
147
+ ## Review and export
148
+
149
+ - Use `open_editor` (MCP) or `htmlcraft open <file>` (CLI) for human review. The
150
+ URL contains the deck's capability token; treat it as a secret. The token is
151
+ recorded per deck and reused by later opens until `htmlcraft stop` rotates it;
152
+ replacing a stale-build host rotates it too, because `open` stops the broken
153
+ host first, so a URL bookmarked before the replacement needs the newly printed
154
+ one. The first visit exchanges the token for a 30-day session cookie.
155
+ - Re-read after a person edits in the editor, because their writes create new
156
+ revisions.
157
+ - Run `validate_deck` or `htmlcraft validate` before exporting.
158
+ - `export_deck` writes `<name>.export.html` for `format: "html"`, or a PDF /
159
+ one PNG per slide for `pdf` / `png`. `outDir` resolves against the deck
160
+ directory and must stay inside it.
@@ -0,0 +1,177 @@
1
+ # htmlcraft deck contract (htmldeck/v1)
2
+
3
+ The HTML file is both the authoring format and the saved deck. The validator,
4
+ editor, CLI, and MCP server all read and write this same contract.
5
+
6
+ ## Document
7
+
8
+ - Start with `<!doctype html>`.
9
+ - Include a non-empty `<title>`. A missing title is a warning
10
+ (`missing-title`), not an error.
11
+ - The document must have content (`empty-document` error otherwise).
12
+ - The deck must contain at least one slide.
13
+ - The deck is self-contained: keep CSS in a `<style>` block or inline `style`
14
+ attributes, and keep assets inline or on absolute URLs. No build step is
15
+ required to open or export it.
16
+
17
+ ## Deck wrapper and slides
18
+
19
+ - `<main data-ppt-deck>` is the conventional wrapper. The runtime marks it
20
+ `data-ppt-ready="1"` while presenting.
21
+ - Detection order:
22
+ 1. Elements with `data-slide-id`.
23
+ 2. `.slide`, then `.page`, then `.slide-page`.
24
+ 3. The largest same-parent group of `<section>` elements.
25
+ 4. The body as a single slide with the id `body`.
26
+ - Explicit `data-slide-id` values are required for stable addressing. A slide
27
+ without one is a warning (`missing-slide-id`) and normalization assigns one.
28
+ - Slide ids must be unique and non-empty. Duplicates are an error
29
+ (`duplicate-slide-id`).
30
+ - Slides must not be nested inside another slide (`nested-slide` error).
31
+
32
+ Minimal explicit slide:
33
+
34
+ ```html
35
+ <section class="slide" data-slide-id="s1" data-width="1600" data-height="900">
36
+ <h1 data-ppt-el="e1">Title</h1>
37
+ </section>
38
+ ```
39
+
40
+ ## Canvas
41
+
42
+ - `data-width` and `data-height` are positive pixel numbers.
43
+ - Omit both to use 1600x900, or set both explicitly.
44
+ - An explicitly invalid value is an error (`invalid-canvas-size`).
45
+ - When the attributes are absent, an inline `width: <n>px; height: <n>px` on
46
+ the slide is also honored.
47
+ - Different sizes across slides produce the `mixed-canvas-sizes` warning.
48
+ Keep one canvas size per deck.
49
+
50
+ ## Objects
51
+
52
+ - Every top-level child of a slide is an object: text blocks, shapes, images,
53
+ tables, figures, and groups.
54
+ - Put `data-ppt-el="<id>"` on each top-level object. Ids are unique within the
55
+ slide and stay stable across edits.
56
+ - Nested elements may also carry `data-ppt-el`; they share the same uniqueness
57
+ rule within the slide. Duplicate ids are an error (`duplicate-element-id`).
58
+ - Normalization assigns a missing top-level `data-ppt-el` id. It does not
59
+ invent content.
60
+ - A `data-ppt-group` wrapper groups objects. Nested group wrappers are not
61
+ supported (`unsupported-group-nesting` warning).
62
+ - Objects are edited through inline styles and CSS classes. While a deck is
63
+ open, the editor's live frame may carry transient editor-only attributes
64
+ (`data-ppt-editing`, `data-ppt-frame-slide`). They are stripped before save
65
+ and never persist in saved output; see the artifacts rule under
66
+ [Round-trip and writes](#round-trip-and-writes).
67
+
68
+ ## Speaker notes
69
+
70
+ - Notes are a direct child of the slide:
71
+ `<aside data-ppt-notes hidden>Talk track</aside>`.
72
+ - Notes outside a slide, or nested deeper than a direct child, are an error
73
+ (`notes-nested-incorrectly`).
74
+ - `set_notes` removes the aside when the notes string is empty.
75
+
76
+ ## Transitions and runtime
77
+
78
+ - `data-ppt-transition` is optional and must be `none`, `fade`, or `slide`.
79
+ Any other value is an error (`invalid-transition`).
80
+ - Multi-slide decks should include exactly one runtime:
81
+ `<script data-ppt-runtime="1">...</script>` in the document.
82
+ - A missing runtime on a multi-slide deck is a warning (`missing-runtime`);
83
+ the deck is still valid HTML but cannot present itself.
84
+ - The runtime body must be the real runtime script, not an empty marker.
85
+ `create_deck` and `htmlcraft new` write it. Copy it from
86
+ `../examples/basic.html` when hand-authoring. Validation checks only that a
87
+ marker exists on a `<script>` with value `1`; it does not inspect the body,
88
+ so a comment or an empty script still validates but cannot present.
89
+ - More than one runtime marker is an error (`duplicate-runtime`). A
90
+ `data-ppt-runtime` attribute whose value is not `1`, or on an element other
91
+ than `<script>`, is an error (`invalid-runtime-marker`).
92
+ - The runtime handles the first/last slide, arrow keys, space, Page Up/Down,
93
+ Home/End, the `#/n` URL hash, and print styles. Clicking a noninteractive
94
+ area advances; links, buttons, form controls, and editable content keep their
95
+ own behavior. `F` toggles fullscreen and `P` opens the presenter view (notes,
96
+ next-slide preview, timer, prev/next). Authored `fade`/`slide` transitions
97
+ animate slide changes unless the viewer prefers reduced motion. Do not replace
98
+ the runtime with custom navigation unless the user asks and accepts that the
99
+ editor will not run it.
100
+
101
+ ## Charts
102
+
103
+ - Chart data lives in `data-ppt-chart` on a figure (or another element) and
104
+ must be valid JSON (`invalid-chart-json` error otherwise).
105
+ - A typical chart attribute:
106
+
107
+ ```html
108
+ <figure
109
+ data-ppt-el="e5"
110
+ data-ppt-chart='{"type":"bar","title":"Revenue","labels":["Q1","Q2"],"series":[{"name":"USD","values":[18,24]}],"colors":["#e8a33d"]}'>
111
+ </figure>
112
+ ```
113
+
114
+ - Keep the JSON small enough to read and edit directly. Treat the attribute as
115
+ the source of truth: any rendered chart is derived from it, so editing only
116
+ the rendered output would not change the data.
117
+
118
+ ## Assets and styling
119
+
120
+ - Use `data:` URIs or absolute URLs for images, fonts, and other assets.
121
+ - Relative `src`/`href` values and relative `url(...)` values produce the
122
+ `relative-asset` warning. They do not travel with an exported file.
123
+ - Arbitrary CSS is allowed: custom properties, flex/grid inside objects,
124
+ inline SVG, CSS animations, shadows, gradients, and absolute web fonts.
125
+ - `position: fixed` and full-height units (`100vh`, `100dvh`, `100svh`,
126
+ `100lvh`) produce the `fixed-layout` warning because they may not export
127
+ reliably. Other viewport units (for example `50vh`) are not matched by the
128
+ validator but still scale with the browser window, so avoid them for layout.
129
+ - A `<canvas>` produces the `canvas-content` warning: its drawing cannot be
130
+ edited visually.
131
+ - Scripts other than the runtime produce the `script-present` warning. The
132
+ editor does not execute them.
133
+
134
+ ## Round-trip and writes
135
+
136
+ - Serialization writes `<!doctype html>` followed by the document element. The
137
+ MCP/editor path removes editor-only attributes before writing:
138
+ `data-ppt-editing` and `data-ppt-frame-slide` are always rejected by
139
+ validation (`editor-artifacts` error) if present in a saved file.
140
+ - HTML export adds the generator comment
141
+ `<!-- Edited with htmlcraft. Format: htmldeck/v1. -->` and, for a multi-slide
142
+ deck with no runtime and no script at all, appends the runtime.
143
+ - Writes are atomic (temporary file plus rename) and compare against the
144
+ revision last read or written. A changed file produces a structured
145
+ `conflict` error; re-read and retry.
146
+ - Normalization may add missing slide/object ids; the editor may also add a
147
+ relative position to statically positioned slide roots. Unknown HTML and CSS
148
+ are preserved otherwise.
149
+
150
+ ## Validation summary
151
+
152
+ Errors make a deck invalid; warnings do not.
153
+
154
+ | Severity | Code | Meaning |
155
+ | --- | --- | --- |
156
+ | error | `empty-document` | No content in the document. |
157
+ | error | `nested-slide` | A slide is inside another slide. |
158
+ | error | `invalid-canvas-size` | Explicit canvas width/height is not positive. |
159
+ | error | `invalid-transition` | Transition is not none, fade, or slide. |
160
+ | error | `duplicate-element-id` | An element id repeats within a slide. |
161
+ | error | `invalid-chart-json` | `data-ppt-chart` is not valid JSON. |
162
+ | error | `duplicate-slide-id` | A slide id repeats. |
163
+ | error | `invalid-runtime-marker` | Runtime attribute is not `1` on a script. |
164
+ | error | `duplicate-runtime` | More than one runtime script. |
165
+ | error | `notes-nested-incorrectly` | Notes are not a direct child of a slide. |
166
+ | error | `editor-artifacts` | Editor-only attributes are present. |
167
+ | warning | `missing-title` | No `<title>`. |
168
+ | warning | `single-body-fallback` | No slides found; the body is one slide. |
169
+ | warning | `missing-slide-id` | A slide has no `data-slide-id`. |
170
+ | warning | `missing-runtime` | Multiple slides but no runtime. |
171
+ | warning | `script-present` | A non-runtime script is present. |
172
+ | warning | `relative-asset` | A relative asset URL is present. |
173
+ | warning | `fixed-layout` | `position: fixed` or a full-height `100vh` unit is present. |
174
+ | warning | `mixed-canvas-sizes` | Slides use different canvas sizes. |
175
+ | warning | `canvas-content` | A `<canvas>` cannot be edited visually. |
176
+ | warning | `unsupported-group-nesting` | Groups are nested. |
177
+ | info | `slide-count` | Number of detected slides. |