@jokerized/decksmith 0.3.1 → 0.3.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.
- package/README.md +112 -1
- package/dist/cli.js +2814 -730
- package/dist/deck-player-element.js +1 -0
- package/dist/deck-player.js +1 -0
- package/dist/deck-runtime.js +27 -2
- package/dist/embed.html +243 -0
- package/dist/index.js +2888 -854
- package/dist/mcp.js +2865 -818
- package/dist/types/deck/player-element.d.ts +1 -0
- package/dist/types/deck/player.d.ts +37 -0
- package/dist/types/deck/protocol.d.ts +80 -0
- package/dist/types/deck/runtime.d.ts +36 -0
- package/dist/types/emit/archetypes/claim-figure.d.ts +0 -7
- package/dist/types/emit/kit.d.ts +33 -0
- package/dist/types/images/providers.d.ts +14 -5
- package/dist/types/index.d.ts +13 -0
- package/dist/types/mcp/tools.d.ts +20 -0
- package/dist/types/net/fetch.d.ts +81 -0
- package/dist/types/pack/media.d.ts +12 -0
- package/dist/types/plan/prompt.d.ts +2 -1
- package/dist/types/server/pipeline.d.ts +51 -8
- package/dist/types/server/upload.d.ts +29 -5
- package/dist/types/source/assets.d.ts +77 -4
- package/dist/types/source/harvest.d.ts +250 -0
- package/dist/types/source/readability.d.ts +120 -0
- package/dist/types/source/transcode.d.ts +83 -0
- package/dist/types/types.d.ts +21 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -51,7 +51,9 @@ decksmith unpack talk.deck -o reopened/
|
|
|
51
51
|
```
|
|
52
52
|
|
|
53
53
|
- **ingest** — document to `Source`: sections, figures, equations and tables, each with a
|
|
54
|
-
stable id so a later stage can point back at it.
|
|
54
|
+
stable id so a later stage can point back at it. Give it an http(s) URL instead of a
|
|
55
|
+
path and it reads the page in a browser first — see "Ingesting a web page" below, which
|
|
56
|
+
also says what happens to a video.
|
|
55
57
|
- **plan** — `Source` to `Storyboard`: an ordered list of beats. Each beat carries an
|
|
56
58
|
`intent` (what the viewer should understand), an optional `claim` it is accountable to,
|
|
57
59
|
`evidence` refs into the Source, a `weight`, and an archetype with its parameters.
|
|
@@ -108,6 +110,77 @@ decksmith unpack talk.deck -o reopened/
|
|
|
108
110
|
- **pack** / **unpack** — the whole deck as one `.deck` file, and back again. See "The
|
|
109
111
|
`.deck` container" below.
|
|
110
112
|
|
|
113
|
+
### Ingesting a web page
|
|
114
|
+
|
|
115
|
+
`ingest` takes a URL wherever it takes a file:
|
|
116
|
+
|
|
117
|
+
```sh
|
|
118
|
+
decksmith ingest https://example.com/the-paper -o source.json
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
It opens a headless Chrome, puts the page's own bytes into it, and **aborts every request
|
|
122
|
+
the page then makes**. A browser pointed at a stranger's URL is otherwise an open proxy —
|
|
123
|
+
the page says `<img src="http://169.254.169.254/latest/meta-data/">` and the browser
|
|
124
|
+
fetches it from inside your network. So the HTML comes through the same address guard
|
|
125
|
+
everything else here uses, and each figure is fetched afterwards, one at a time, through
|
|
126
|
+
that guard again. That has a cost, and it is stated rather than discovered: a page that assembles its body
|
|
127
|
+
from an external bundle harvests to almost nothing, because that bundle was one of the
|
|
128
|
+
aborted requests. Save the page and ingest the file.
|
|
129
|
+
|
|
130
|
+
Which part of the page becomes the document is scored the way Readability scores it: strip
|
|
131
|
+
what the tag, the ARIA role or the class name says is chrome, score every paragraph by its
|
|
132
|
+
length and its commas, propagate that up to five levels of ancestor, discount each
|
|
133
|
+
candidate by its link density, then merge the winner with the siblings that score near it.
|
|
134
|
+
That is what keeps a consent banner and a 142-comment thread out of a deck about the
|
|
135
|
+
article. When it is not sure it declines, says so, and leaves the page to a blunter rule —
|
|
136
|
+
believe `<main>`, believe `<article>`, else take the densest container. Either way the
|
|
137
|
+
line after it is the one to read:
|
|
138
|
+
|
|
139
|
+
```
|
|
140
|
+
ingest: harvested "Sparse attention at scale" — 6 images, 1 clips
|
|
141
|
+
ingest: 9 sections, 6 figures, 0 equations
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Nine sections for a nine-section article is the extraction working. Ninety is the page.
|
|
145
|
+
|
|
146
|
+
**A video has three cases, and they are three different decks.**
|
|
147
|
+
|
|
148
|
+
- **A file the page serves** — `<video src="…mp4">`, or a link ending in one — is
|
|
149
|
+
downloaded, measured off its own container, and re-encoded to a VP9 webm no more than
|
|
150
|
+
1280px on its longest edge, with the audio dropped and the length capped at 60 seconds.
|
|
151
|
+
It **plays in the presented deck and in the rendered mp4**: the composition holds a real
|
|
152
|
+
`<video>` seeked on the deck's own clock. The encode is why the cap exists — `render`
|
|
153
|
+
pre-decodes a clip to one still per output frame before capture begins, at the source's
|
|
154
|
+
own resolution, so a 4K original writes 4K stills into an 860px plate. **If ffmpeg is
|
|
155
|
+
not installed the clip is still used**, exactly as the page served it, and the harvest
|
|
156
|
+
says so in a warning naming what to install. `--no-transcode` asks for that on purpose;
|
|
157
|
+
`--max-clip-seconds` moves the cap.
|
|
158
|
+
- **A player-page link** — YouTube, Vimeo, Dailymotion, Loom — keeps its still and where
|
|
159
|
+
to watch it. The **mp4 gets the poster frame**, because that is all a captured document
|
|
160
|
+
can honestly hold. The **presented deck gets the real player**: `deck.html` carries the
|
|
161
|
+
embeddable form of that URL, and a `▶ Video` button (or `v`) opens it over the slide,
|
|
162
|
+
click to play, torn down when you leave the slide. Nothing is fetched until you press
|
|
163
|
+
it, and `index.html` never gains an iframe — a third-party frame in the captured
|
|
164
|
+
document would play at wall-clock speed while the deck is being seeked, and refetch
|
|
165
|
+
itself from the network on every render.
|
|
166
|
+
|
|
167
|
+
**The bytes are deliberately not downloaded.** They sit behind a manifest, DRM or terms,
|
|
168
|
+
and pulling down what a YouTube link stands for is usually against that site's terms.
|
|
169
|
+
It is the same `embed` policy the container uses — see "bake, link, embed" below — and
|
|
170
|
+
it is a property of the URL rather than a choice you can make. A host we have no
|
|
171
|
+
verified embed rule for keeps the poster and the link, and no frame: a URL we invented
|
|
172
|
+
would 404 inside the frame as a black rectangle with nothing to click.
|
|
173
|
+
- **No video at all** is the ordinary case, and nothing changes. A `<video>` with a poster
|
|
174
|
+
and no source becomes an ordinary figure, warned; one with neither becomes a line of
|
|
175
|
+
prose carrying the link, also warned.
|
|
176
|
+
|
|
177
|
+
The URL-only budgets, each named after the option it sets so that a refusal naming
|
|
178
|
+
`maxAssets` names something findable in `--help`: `--max-assets` (40), `--max-clips` (4),
|
|
179
|
+
`--max-bytes` (96 MB in total), `--max-seconds` (180, wall clock for the whole harvest),
|
|
180
|
+
`--max-clip-seconds` (60, per clip), `--no-transcode`. Every figure, clip or whole video
|
|
181
|
+
left out is printed verbatim before the plan is paid for, which is the only moment anyone
|
|
182
|
+
can act on it.
|
|
183
|
+
|
|
111
184
|
### What `build` writes
|
|
112
185
|
|
|
113
186
|
```
|
|
@@ -279,6 +352,8 @@ for pictures still finishes, on the tool's own SVG if it has to.
|
|
|
279
352
|
| `GET /api/jobs/:id/events` | the same payload as SSE on every change |
|
|
280
353
|
| `GET /api/formats` | the presets, themes, tones, densities and canvas bounds the picker draws from |
|
|
281
354
|
| `GET /d/:id/...` | the built deck, served statically; `/d/:id/deck.html` is the player |
|
|
355
|
+
| `GET /player.js` | the `<decksmith-player>` element, as an ES module — see below |
|
|
356
|
+
| `GET /examples/embed.html` | a page that embeds two decks with it, and the file you copy |
|
|
282
357
|
|
|
283
358
|
Options on `POST`, all optional, all defaulted server-side: `format`, `width`+`height`,
|
|
284
359
|
`theme`, `slides`, `lang`, `tone`, `density`, `speed`, `narrate`, `voice`, `images`,
|
|
@@ -850,6 +925,42 @@ The corollary is worth internalising before you trust a green gate: `check` has
|
|
|
850
925
|
twice on artifacts that were broken. The gates verify the mechanics of what the structure
|
|
851
926
|
exposes, and a structurally wrong deck exposes nothing to check.
|
|
852
927
|
|
|
928
|
+
### Embedding a deck in your own page
|
|
929
|
+
|
|
930
|
+
The same step layer is reachable from outside as a custom element. A consumer learns one
|
|
931
|
+
thing — where the deck is:
|
|
932
|
+
|
|
933
|
+
```html
|
|
934
|
+
<script type="module" src="/player.js"></script>
|
|
935
|
+
<decksmith-player deck="/d/<id>/"></decksmith-player>
|
|
936
|
+
```
|
|
937
|
+
|
|
938
|
+
`next()`, `prev()`, `go(i)` and `play(on)` are methods; `ds-ready`, `ds-stop` and
|
|
939
|
+
`ds-error` are events. `ds-ready` carries every stop the deck can land on, which is what
|
|
940
|
+
a jump list is built from. Setting `deck` again swaps the deck in place.
|
|
941
|
+
|
|
942
|
+
**The iframe stays, and is the module boundary.** It is tempting to mount the deck
|
|
943
|
+
inline instead, and three facts in this tree rule it out. `frameOf` reads
|
|
944
|
+
`contentDocument` and returns null cross-origin while the runtime only warns, so an
|
|
945
|
+
inlined deck served from a CDN would navigate perfectly and paint nothing, silently.
|
|
946
|
+
`customElements.define` is one registry per document, so two decks would be two vendored
|
|
947
|
+
hyperframes bundles and the second `define` throws. And the deck's own chrome is written
|
|
948
|
+
against `100vh` being the box, which is true inside a frame and quietly wrong outside it.
|
|
949
|
+
Keeping the frame leaves the same-origin pair as `deck.html`↔`index.html`, one directory,
|
|
950
|
+
always true — and makes the host link `postMessage`, which does not care about origin.
|
|
951
|
+
|
|
952
|
+
**Silence is a supported state.** A deck is a static artifact that outlives the tool that
|
|
953
|
+
built it, and every deck built before this change has no bridge in it. The element waits,
|
|
954
|
+
gives up, emits `ds-error` with reason `no-bridge`, and leaves the deck exactly as usable
|
|
955
|
+
as it was — still a deck in a frame, its own keyboard still working. It does not blank and
|
|
956
|
+
it does not throw.
|
|
957
|
+
|
|
958
|
+
`examples/embed.html` is both the demo the dev server serves at `/examples/embed.html`
|
|
959
|
+
and the file you copy next to a built deck. Nothing in `lint`, `check`, `verify`, `drift`
|
|
960
|
+
or `render` opens a deck page, so a browser pass is the only instrument that can tell you
|
|
961
|
+
any of this works. The design note is
|
|
962
|
+
[`.planning/2026-09-07-player-as-a-module.md`](.planning/2026-09-07-player-as-a-module.md).
|
|
963
|
+
|
|
853
964
|
## Invariants the generator enforces
|
|
854
965
|
|
|
855
966
|
These were all learned by breaking them, and they are why build output is generated
|