@marver-design/marver 0.19.1 → 0.20.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.
- package/CHANGELOG.md +77 -0
- package/README.md +9 -11
- package/dist/{bake-kaf5kGZ7.mjs → bake-tAb0D6Rc.mjs} +1 -1
- package/dist/{build-7ed5H2vT.mjs → build-DwpNPl6Z.mjs} +3 -3
- package/dist/cli.mjs +18 -12
- package/dist/{dev-D3mP2x27.mjs → dev-BjdDP69b.mjs} +3 -3
- package/dist/{init-BQYCS3EU.mjs → init-DKxuRxBr.mjs} +33 -32
- package/dist/{plugin-DI-7NAnx.mjs → plugin-y4Ch7o_A.mjs} +7 -7
- package/dist/{poster-DNh6N27C.mjs → poster-FCv_nXyP.mjs} +1 -1
- package/dist/{publish-bakes-Dp-ZFk3d.mjs → publish-bakes-XH6Bac58.mjs} +8 -2
- package/dist/{shot-DMDvDbeP.mjs → shot-iw3SEcpn.mjs} +7 -7
- package/docs/live-jam.md +1 -1
- package/docs/slides.md +89 -89
- package/docs/sticky-notes.md +14 -4
- package/package.json +1 -1
- package/src/client/const.ts +27 -9
- package/src/client/content/chart.tsx +8 -8
- package/src/client/content/index.tsx +5 -4
- package/src/client/content/slide.tsx +26 -201
- package/src/client/frame-host/main.tsx +10 -0
- package/src/client/shell/Comments.tsx +12 -4
- package/src/client/shell/Play.tsx +26 -14
- package/src/client/shell/Toolbar.tsx +7 -5
- package/src/client/shell/canvas/FrameNode.tsx +16 -2
- package/src/client/shell/canvas/Sticky.tsx +16 -1
- package/src/client/shell/notes.ts +43 -9
- package/src/client/shell/store.ts +17 -8
- package/src/client/shell/tidy.ts +12 -5
- package/src/client/stage/main.tsx +56 -7
- package/templates/AGENTS-embedded.md +3 -2
- package/templates/AGENTS-studio.md +3 -2
- package/templates/instructions/reference/deck-layouts.md +153 -199
- package/templates/instructions/reference/deck-story.md +6 -6
- package/templates/instructions/shape.md +6 -4
- package/templates/instructions/slides.md +275 -383
package/docs/slides.md
CHANGED
|
@@ -3,67 +3,63 @@
|
|
|
3
3
|
A slide is an ordinary frame with `slide: true`:
|
|
4
4
|
|
|
5
5
|
```tsx
|
|
6
|
-
|
|
7
|
-
export const meta = { title: 'Cover', slide: true }
|
|
6
|
+
export const meta = { title: 'Onboarding time halved', slide: true }
|
|
8
7
|
export default () => (
|
|
9
|
-
<
|
|
10
|
-
<h1
|
|
11
|
-
</
|
|
8
|
+
<main className="deck deck-ink">
|
|
9
|
+
<h1>Onboarding time halved in one quarter.</h1>
|
|
10
|
+
</main>
|
|
12
11
|
)
|
|
13
12
|
```
|
|
14
13
|
|
|
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
|
-
fill-in template the agent drafts on the first deck), layouts, and house
|
|
57
|
-
rules live in `design/slides.md`, which overrides the doctrine and which
|
|
58
|
-
marver never overwrites.
|
|
14
|
+
That is the whole contract. Everything inside is your code - your
|
|
15
|
+
project's components and classes, any layout, any typeface, any image,
|
|
16
|
+
any SVG drawing, any CSS or JS animation. marver adds what a deck needs
|
|
17
|
+
around it: a stage, a player, and a place on the board.
|
|
18
|
+
|
|
19
|
+
- **The stage.** A slide renders at its stage size: 1280×720 by default,
|
|
20
|
+
or the `viewport` it declares (`viewport: 'laptop'` gives a 16:10 deck at
|
|
21
|
+
1280×800). On the canvas it is a frame like any other - comments, laser,
|
|
22
|
+
variants, Live Jam - with a slide badge.
|
|
23
|
+
- **The deck.** One scene is one deck; numbered files (`01-cover.tsx`) are
|
|
24
|
+
the authoring order, and **the board's reading order is the played
|
|
25
|
+
order** - drag slides around the canvas to reorder the deck.
|
|
26
|
+
- **The host scales, not the slide.** A slide never reflows. Slides mode
|
|
27
|
+
renders each slide at its stage and scales the whole stage to the screen -
|
|
28
|
+
up on a projector, down on a laptop or a phone - and a canvas node resized
|
|
29
|
+
smaller shows the same stage, scaled, like a thumbnail. The composition you
|
|
30
|
+
approved is the one everyone sees, without breakpoints.
|
|
31
|
+
- **Notes.** `<slide>.note.md` beside the frame is its
|
|
32
|
+
[sticky note](sticky-notes.md): the aim, the talk track, the visual
|
|
33
|
+
intent, the sources. Notes ship with a published canvas, so keep anything
|
|
34
|
+
the audience must not read out of them.
|
|
35
|
+
|
|
36
|
+
## The guidance the agent reads
|
|
37
|
+
|
|
38
|
+
`marver init` ships `design/instructions/slides.md` - not a rulebook, a
|
|
39
|
+
guide: how a slide plays and animates, the **deck kit** a strong deck is
|
|
40
|
+
built on (a master shell, whole-slide tones, the brand's type, hairlines
|
|
41
|
+
and labels, a drawing helper), the craft that makes a deck look made
|
|
42
|
+
rather than typed (the brand's own voice, one idea per slide, structure
|
|
43
|
+
with space instead of boxes, real images used big, a drawing system of its
|
|
44
|
+
own, pacing, honest numbers), the method (the answer first, a slide list
|
|
45
|
+
that tells the argument, a `_brief.md`, notes per slide), and a review that
|
|
46
|
+
squints at the contact sheet. Two references sit beside it:
|
|
47
|
+
`instructions/reference/deck-story.md` (intake, answer-first structure, the
|
|
48
|
+
evidence check, the words) and `instructions/reference/deck-layouts.md` (an
|
|
49
|
+
idea bank of compositions, rebuilding an existing deck, chart craft).
|
|
50
|
+
|
|
51
|
+
Your own **deck look** - master, tones, type, mark, imagery, drawing style,
|
|
52
|
+
colour meaning, voice - lives in `design/slides.md`, which the agent drafts
|
|
53
|
+
from your brand on the first deck, which overrides the shipped guide, and
|
|
54
|
+
which marver never overwrites.
|
|
59
55
|
|
|
60
56
|
## Playing and publishing a deck
|
|
61
57
|
|
|
62
58
|
Press `p` on a board whose publish row says slides and you get slides mode:
|
|
63
|
-
the
|
|
64
|
-
the default)
|
|
65
|
-
|
|
66
|
-
Publish it with:
|
|
59
|
+
the stage scaled to the window, the standard prototype toolbars (with
|
|
60
|
+
`chrome: full`, the default), arrows / Space / click to advance, `d` cycles
|
|
61
|
+
the theme, and two views of the stage: Slide (fit to the window, room for
|
|
62
|
+
the chrome) and Fill window (edge to edge). Publish it with:
|
|
67
63
|
|
|
68
64
|
```json
|
|
69
65
|
{ "boards": { "pitch": { "max": "comment", "type": "slides",
|
|
@@ -72,8 +68,8 @@ Publish it with:
|
|
|
72
68
|
|
|
73
69
|
- `transition`: `fade` (default) or `none`.
|
|
74
70
|
- `chrome`: `full` (default - the standard prototype chrome: the top-right
|
|
75
|
-
toolbar with comment, laser, theme, and devices
|
|
76
|
-
|
|
71
|
+
toolbar with comment, laser, theme, and devices, plus the bottom-left
|
|
72
|
+
walker; a locked deck-only share also carries the brand pill),
|
|
77
73
|
`minimal` (a slim progress strip, comments, the canvas door when the
|
|
78
74
|
board is not locked, and a pending-update control), or `none` (bare
|
|
79
75
|
stage).
|
|
@@ -83,35 +79,44 @@ Publish it with:
|
|
|
83
79
|
|
|
84
80
|
Viewers land straight in the deck; the URL survives refresh and back.
|
|
85
81
|
|
|
86
|
-
## Motion
|
|
82
|
+
## Motion
|
|
87
83
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
(
|
|
92
|
-
|
|
93
|
-
|
|
84
|
+
Motion is yours to write. While a deck plays, the stage puts
|
|
85
|
+
`data-sl-play` on `<html>` for the whole show, and `data-sl-entered` once
|
|
86
|
+
each slide has arrived (removed at each swap, set again when the new slide
|
|
87
|
+
settles); `useSlidePlay()` from `/content` is the playing flag in React. Key
|
|
88
|
+
your animations off them, so the canvas, `marver shot` and thumbnails show
|
|
89
|
+
the finished slide:
|
|
90
|
+
|
|
91
|
+
```css
|
|
92
|
+
:root[data-sl-entered] .route { animation: draw 900ms ease-out both }
|
|
93
|
+
@keyframes draw { from { stroke-dashoffset: 600 } to { stroke-dashoffset: 0 } }
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
On the canvas, a resting frame's animations are paused anyway (see sleep in
|
|
97
|
+
the README). marver adds three things on top:
|
|
94
98
|
|
|
95
99
|
- **Morphs**: give the same `view-transition-name` to an element on two
|
|
96
|
-
adjacent slides and it travels
|
|
97
|
-
- **Build steps**: progressive disclosure is sibling frames (`03a-`,
|
|
98
|
-
sharing morph names - every step visible and commentable on the
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
100
|
+
adjacent slides and it travels or resizes between them.
|
|
101
|
+
- **Build steps**: progressive disclosure is sibling frames (`03a-`,
|
|
102
|
+
`03b-`) sharing morph names - every step visible and commentable on the
|
|
103
|
+
board.
|
|
104
|
+
- **Entrance shortcuts**: `data-animate="fade-up | fade | scale-in"` +
|
|
105
|
+
`data-animate-delay="1-3"`, run once after a slide arrives. Never on an
|
|
106
|
+
element that carries a morph name.
|
|
102
107
|
|
|
103
|
-
|
|
104
|
-
|
|
108
|
+
`--marver-slide-tempo` in your theme (default 350ms) times the morphs and
|
|
109
|
+
the shortcuts. `prefers-reduced-motion` flattens both.
|
|
105
110
|
|
|
106
111
|
## Charts and video
|
|
107
112
|
|
|
108
113
|
- `<Chart option={...} h={420} />` - an Apache ECharts option, on a
|
|
109
114
|
fixed supported surface: series bar, line, pie, scatter, radar, gauge, heatmap, funnel, treemap, sunburst, sankey, boxplot; components grid, polar, radar, tooltip, legend, title, dataset (+ transform), markLine, markPoint, markArea, visualMap, dataZoom. Anything outside
|
|
110
115
|
it is dropped by ECharts without an error, so stay inside. marver
|
|
111
|
-
supplies the house theme
|
|
112
|
-
`
|
|
113
|
-
|
|
114
|
-
|
|
116
|
+
supplies the house theme from the slide's own ink and typeface (and
|
|
117
|
+
`--marver-slide-accent`), sizes labels for a stage, keeps the chart
|
|
118
|
+
still at rest and plays its entrance in slides mode. SVG-rendered, in a
|
|
119
|
+
lazy chunk chart-free canvases never download.
|
|
115
120
|
- `<Video src="intro.mp4" poster="intro.jpg" />` - the poster is the frame
|
|
116
121
|
at rest. Omit it on a local clip and marver renders one from the clip's own
|
|
117
122
|
first moments (`intro.mp4.poster.png` beside it - the dev server on first
|
|
@@ -122,19 +127,14 @@ slides and the entrance presets.
|
|
|
122
127
|
`ratio="9 / 16"` for a vertical clip; `autoplay` for a muted ambient loop
|
|
123
128
|
(that frame then stays live on the canvas). Remote https direct files work
|
|
124
129
|
too.
|
|
130
|
+
- Images: `Img` for a framed asset, or a plain `<img>` when the slide needs
|
|
131
|
+
full control. Slides play scaled up, so use files at least 2x the size
|
|
132
|
+
they show.
|
|
133
|
+
|
|
134
|
+
## Decks built before 0.20
|
|
125
135
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
both the entrances and the morphs between slides) from your theme and falls
|
|
132
|
-
back to the house palette. The stage is 1280×720 (`SLIDE_W` / `SLIDE_H`, exported from `/content`)
|
|
133
|
-
with asymmetric margins - 88px sides, 44px top and bottom, overridable in
|
|
134
|
-
px via `--marver-slide-pad-x` / `--marver-slide-pad-y` - leaving a 1104×632
|
|
135
|
-
content box. Morphs between slides are progressive enhancement: where
|
|
136
|
-
`document.startViewTransition` is missing, slides crossfade at the tempo.
|
|
137
|
-
Type roles, fixed: `sl-display` (160px, the one
|
|
138
|
-
oversize - a hero number, a section numeral), `sl-stat` (88px, a row of
|
|
139
|
-
figures), `sl-assertion` (56px),
|
|
140
|
-
`sl-support` (30px), `sl-body` (24px), `sl-caption` (18px).
|
|
136
|
+
Earlier decks wrap each slide in `<Slide>` and use its `sl-*` type classes.
|
|
137
|
+
`<Slide>` still exists, as an optional wrapper that fills the frame - but it
|
|
138
|
+
no longer pads the stage, centres content, sizes type or freezes animation,
|
|
139
|
+
and the `sl-*` classes carry no styles. Such a deck still plays; give it its
|
|
140
|
+
own styles (a deck kit, as the guide describes) to restore the look.
|
package/docs/sticky-notes.md
CHANGED
|
@@ -21,10 +21,11 @@ inert. A scene note is 380 wide, a frame note 260; when a frame has both, they s
|
|
|
21
21
|
scene first. An edit lands on the canvas as you save, without reloading the frame.
|
|
22
22
|
|
|
23
23
|
The room is the layout's job. Every layout the shell composes (a board's `layout` recipe, the auto
|
|
24
|
-
board, tidy, device views) reserves the note's width in front of its frame
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
board, tidy, device views) reserves the note's width in front of its frame and its height below it:
|
|
25
|
+
a note longer than its frame runs on under the card, and the row beneath starts under the note, the
|
|
26
|
+
gutter unchanged. A note landing on a board already composed re-applies the recipe so the frames
|
|
27
|
+
make way - whether the board is open at the time or not - and so does a note that grows. Nobody
|
|
28
|
+
moves frames for a note. A board dragged by hand keeps its positions; `t` makes the room there.
|
|
28
29
|
|
|
29
30
|
## Diagrams
|
|
30
31
|
|
|
@@ -43,6 +44,15 @@ own theme.
|
|
|
43
44
|
- Comments: in comment mode (`C`) click any element of a note; the pin sits on the note, follows a
|
|
44
45
|
fold onto the tab, and the thread card opens beside the column.
|
|
45
46
|
|
|
47
|
+
## On a slide
|
|
48
|
+
|
|
49
|
+
Beside a slide (`slide: true`), the note is the presenter's script and the next agent's memory,
|
|
50
|
+
and the [slides guide](slides.md) teaches agents to write it in four short parts - **Aim** (what the
|
|
51
|
+
slide must do in the argument), **Say** (the talk track), **Visual** (what the image or drawing
|
|
52
|
+
carries) and **Source context** (where the facts come from, and their limits) - so the slide itself
|
|
53
|
+
can stay sparse. A note ships with a published canvas like any other: keep anything the audience
|
|
54
|
+
must not read out of it.
|
|
55
|
+
|
|
46
56
|
## What it is not
|
|
47
57
|
|
|
48
58
|
A note is an aside, a screen's worth of reading at most. Specs, flows and mood boards stay content
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@marver-design/marver",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.20.0",
|
|
4
4
|
"description": "The agent-native design canvas. A design/ folder, one command, a canvas of live frames built from your repo's real components - comment @marver and your own coding agent does the work. The tool ships no AI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
package/src/client/const.ts
CHANGED
|
@@ -9,15 +9,33 @@ export const ROUTE = '/__mv'
|
|
|
9
9
|
* manifest scan (defaultSize for content frames) - one source, no drift. */
|
|
10
10
|
export const CONTENT_WIDTH: Record<string, number> = { document: 760, wide: 1280 }
|
|
11
11
|
|
|
12
|
-
/** The slide stage
|
|
13
|
-
*
|
|
14
|
-
*
|
|
12
|
+
/** The default slide stage: 16:9 at 1280×720, deliberately NOT a config viewport - no
|
|
13
|
+
* migration for existing projects, no deck device in sweeps. Dependency-neutral so
|
|
14
|
+
* server (shot) and shell (store, play) share it. */
|
|
15
15
|
export const SLIDE_INTRINSIC = { width: 1280, height: 720 }
|
|
16
16
|
|
|
17
|
-
/** The one
|
|
18
|
-
* `slide: true`
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
/** The one sizing rule for slide frames, shared by canvas, shot and slides mode: a
|
|
18
|
+
* `slide: true` frame's stage is its declared viewport when the project defines one
|
|
19
|
+
* (a 16:10 deck authored at `laptop` stays 1280×800), else the 1280×720 default. A
|
|
20
|
+
* slide is an ordinary frame at that size - slides mode scales the whole stage to the
|
|
21
|
+
* screen, so the frame never has to. */
|
|
22
|
+
export function slideSize(
|
|
23
|
+
frame: { slide?: boolean; viewport?: string },
|
|
24
|
+
viewports: Record<string, { width: number; height: number }> = {},
|
|
25
|
+
): { width: number; height: number } | null {
|
|
26
|
+
if (!frame.slide) return null
|
|
27
|
+
const vp = frame.viewport ? viewports[frame.viewport] : undefined
|
|
28
|
+
return vp ? { width: vp.width, height: vp.height } : SLIDE_INTRINSIC
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** The baseline every slide document shares, in the frame host and the stage alike: the
|
|
32
|
+
* document IS the stage, so the browser's body margin never frames it - whatever the theme
|
|
33
|
+
* or the content primitives a previous slide injected. */
|
|
34
|
+
export const SLIDE_DOC_CSS = 'html[data-mv-slide] body { margin: 0 }'
|
|
35
|
+
|
|
36
|
+
/** How a slide's stage sits in a box of any other size: scaled uniformly to fit and centred.
|
|
37
|
+
* A slide never reflows - the canvas node, the player and a shot all show the same stage. */
|
|
38
|
+
export function stageFit(stage: { width: number; height: number }, box: { w: number; h: number }): { k: number; ox: number; oy: number } {
|
|
39
|
+
const k = Math.max(0.01, Math.min(box.w / stage.width, box.h / stage.height))
|
|
40
|
+
return { k, ox: (box.w - stage.width * k) / 2, oy: (box.h - stage.height * k) / 2 }
|
|
23
41
|
}
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Chart (v1.5) - Apache ECharts, the Diagram way: the author picks the FORM
|
|
3
3
|
* (the ECharts option surface, pointed at from instructions/slides.md);
|
|
4
|
-
* marver injects the house theme and
|
|
5
|
-
* breaks the deck (animation at rest, above all).
|
|
4
|
+
* marver injects the house theme and keeps the chart still at rest.
|
|
6
5
|
*
|
|
7
|
-
* SVG renderer ONLY -
|
|
8
|
-
* the board (the lean-DOM serializer keeps <canvas> frames degraded). At
|
|
6
|
+
* SVG renderer ONLY - crisp at any canvas zoom and any stage scale. At
|
|
9
7
|
* rest the chart renders its final state (animation force-disabled); in
|
|
10
8
|
* slides mode (useSlidePlay) it plays its entrance once on mount.
|
|
11
9
|
*
|
|
@@ -66,19 +64,21 @@ export function chartTheme(t: { ink: string; font: string; accent: string; groun
|
|
|
66
64
|
|
|
67
65
|
/** The house theme, read from the frame the chart sits in, at render time. Ink and font are
|
|
68
66
|
* the element's own COMPUTED color and font-family - so a chart inherits a UI screen's
|
|
69
|
-
* Tailwind text colour and typeface, a Doc's tokens, or a
|
|
70
|
-
* wiring. Accent and ground come from slide tokens, then Doc tokens, then the
|
|
67
|
+
* Tailwind text colour and typeface, a Doc's tokens, or a slide's own type, with no
|
|
68
|
+
* per-context wiring. Accent and ground come from slide tokens, then Doc tokens, then the
|
|
69
|
+
* mode palette. A slide frame (meta `slide: true`, stamped on <html> as data-mv-slide) or a
|
|
70
|
+
* <Slide> wrapper takes the stage label scale. */
|
|
71
71
|
function houseTheme(el: HTMLElement, dark: boolean) {
|
|
72
72
|
const css = getComputedStyle(el)
|
|
73
73
|
const v = (...names: string[]) => { for (const n of names) { const x = css.getPropertyValue(n).trim(); if (x) return x } return '' }
|
|
74
74
|
return chartTheme({
|
|
75
75
|
ink: css.color || (dark ? '#F2F2F7' : '#1C1C1E'),
|
|
76
76
|
font: v('--sl-font') || css.fontFamily || FONT_STACK,
|
|
77
|
-
accent: v('--sl-accent', '--mv-accent') || (dark ? '#0091FF' : '#0088FF'),
|
|
77
|
+
accent: v('--sl-accent', '--marver-slide-accent', '--mv-accent') || (dark ? '#0091FF' : '#0088FF'),
|
|
78
78
|
ground: v('--sl-ground', '--mv-surface', '--mv-bg') || (dark ? '#1C1C1E' : '#FFFFFF'),
|
|
79
79
|
grid: v('--sl-grid') || (dark ? 'rgba(242,242,247,.12)' : 'rgba(28,28,30,.1)'),
|
|
80
80
|
dark,
|
|
81
|
-
inSlide: !!el.closest('.sl-root'),
|
|
81
|
+
inSlide: !!el.closest('.sl-root') || document.documentElement.hasAttribute('data-mv-slide'),
|
|
82
82
|
})
|
|
83
83
|
}
|
|
84
84
|
|
|
@@ -22,7 +22,7 @@ export function Diagram(props: Parameters<typeof DiagramRoot>[0]) { ensureStyles
|
|
|
22
22
|
import { Slide as SlideRoot } from './slide.tsx'
|
|
23
23
|
import { Chart as ChartRoot } from './chart.tsx'
|
|
24
24
|
import { Video as VideoRoot } from './video.tsx'
|
|
25
|
-
export { SLIDE_W, SLIDE_H } from './slide.tsx'
|
|
25
|
+
export { SLIDE_W, SLIDE_H, useSlidePlay } from './slide.tsx'
|
|
26
26
|
// the shared stylesheet used to ride in with Doc alone; a slide composes Img,
|
|
27
27
|
// Chart, and Video straight inside <Slide> with no Doc, so every public
|
|
28
28
|
// primitive installs it - once per document, idempotent
|
|
@@ -98,9 +98,10 @@ export function Img({ src, caption, alt, h }: { src: string; caption?: string; a
|
|
|
98
98
|
const url = assetUrl(src)
|
|
99
99
|
const [err, setErr] = useState(false)
|
|
100
100
|
const canvasRef = useRef<HTMLCanvasElement>(null)
|
|
101
|
-
//
|
|
102
|
-
// the
|
|
103
|
-
|
|
101
|
+
// on a slide the LOD canvas is OFF: slides mode scales the whole stage up to the screen,
|
|
102
|
+
// and a bitmap decoded for the frame's own box would blur there - the plain <img> keeps
|
|
103
|
+
// its full resolution. A slide frame is marked on <html> (data-mv-slide) before it renders.
|
|
104
|
+
const inSlide = useInSlide() || (typeof document !== 'undefined' && document.documentElement.hasAttribute('data-mv-slide'))
|
|
104
105
|
// LOD: paint the image on a <canvas> decoded to its on-screen size (never the full 17MB bitmap), and
|
|
105
106
|
// re-pick resolution only when the canvas settles after a zoom. See img-lod.ts. Falls back to a plain
|
|
106
107
|
// <img> where createImageBitmap/bitmaprenderer isn't available (correctness over the optimization).
|