scrolly 0.2.3__tar.gz → 0.2.4__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.
- {scrolly-0.2.3 → scrolly-0.2.4}/.gitignore +3 -0
- scrolly-0.2.4/PKG-INFO +118 -0
- scrolly-0.2.4/README.md +85 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/pyproject.toml +3 -1
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/_cli/_cli.py +2 -46
- scrolly-0.2.4/scrolly/_cli/_schema.py +167 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/errors/catalog/E003.md +2 -2
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/errors/catalog/E299.md +2 -2
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/errors/catalog/E601.md +3 -2
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/render/assets/canvas.css +1 -1
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/render/assets/canvas.js +15 -1
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/slide/__init__.py +2 -1
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/slide/ir/__init__.py +2 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/slide/ir/_framework/element.py +49 -1
- scrolly-0.2.3/PKG-INFO +0 -81
- scrolly-0.2.3/README.md +0 -50
- {scrolly-0.2.3 → scrolly-0.2.4}/LICENSE +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/__init__.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/_cli/__init__.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/_cli/_errors.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/_cli/_introspect/__init__.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/_cli/_introspect/_assets.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/_cli/_introspect/_common.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/_cli/_introspect/_dom.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/_cli/_introspect/_elements.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/_cli/_introspect/_slides.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/_cli/_introspect/_snaps.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/_cli/_introspect/_snapshot.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/_cli/_introspect/_timeline.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/deck/__init__.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/deck/inference.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/deck/introspect.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/deck/model.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/deck/parser.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/deck/schema.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/deck/validator.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/errors/__init__.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/errors/_catalog.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/errors/_codes.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/errors/_report.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/errors/_validation_error.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/errors/catalog/E001.md +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/errors/catalog/E002.md +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/errors/catalog/E004.md +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/errors/catalog/E005.md +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/errors/catalog/E006.md +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/errors/catalog/E007.md +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/errors/catalog/E008.md +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/errors/catalog/E009.md +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/errors/catalog/E010.md +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/errors/catalog/E011.md +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/errors/catalog/E012.md +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/errors/catalog/E101.md +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/errors/catalog/E102.md +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/errors/catalog/E103.md +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/errors/catalog/E201.md +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/errors/catalog/E202.md +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/errors/catalog/E203.md +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/errors/catalog/E204.md +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/errors/catalog/E205.md +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/errors/catalog/E206.md +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/errors/catalog/E207.md +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/errors/catalog/E301.md +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/errors/catalog/E302.md +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/errors/catalog/E303.md +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/errors/catalog/E304.md +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/errors/catalog/E305.md +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/errors/catalog/E306.md +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/errors/catalog/E307.md +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/errors/catalog/E308.md +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/errors/catalog/E401.md +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/errors/catalog/E402.md +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/errors/catalog/E403.md +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/errors/catalog/E501.md +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/errors/catalog/E502.md +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/errors/catalog/E503.md +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/errors/catalog/E504.md +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/errors/catalog/E505.md +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/errors/catalog/E602.md +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/errors/catalog/E603.md +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/errors/catalog/E701.md +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/errors/catalog/E702.md +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/errors/catalog/__init__.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/pipeline/__init__.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/pipeline/_bundler.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/pipeline/assets.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/pipeline/introspect.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/pipeline/lint.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/pipeline/loader.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/pipeline/orchestrator.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/pipeline/writer.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/render/__init__.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/render/assembler.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/render/assets/mermaid-LICENSE +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/render/assets/mermaid.min.js +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/render/bundled_assets.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/render/color.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/render/fan.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/render/nav_data.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/render/templates/index.html.j2 +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/render/zoom_control.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/slide/element_ir/__init__.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/slide/element_ir/ir.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/slide/element_ir/processor.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/slide/element_ir/registry.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/slide/element_ir/rendered.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/slide/element_ir/renderers/__init__.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/slide/element_ir/renderers/_shared.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/slide/element_ir/renderers/html.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/slide/element_ir/renderers/iframe.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/slide/element_ir/renderers/image.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/slide/element_ir/renderers/image_sequence.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/slide/element_ir/renderers/markdown.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/slide/element_ir/renderers/mermaid.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/slide/html.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/slide/introspect.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/slide/ir/_framework/__init__.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/slide/ir/_framework/animated_values.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/slide/ir/_framework/utils.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/slide/ir/slide.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/slide/processor.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/slide/registry.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/slide/renderers/__init__.py +0 -0
- {scrolly-0.2.3 → scrolly-0.2.4}/scrolly/slide/renderers/slide.py +0 -0
scrolly-0.2.4/PKG-INFO
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: scrolly
|
|
3
|
+
Version: 0.2.4
|
|
4
|
+
Summary: CLI that compiles a JSON5 deck + slide files into a self-contained 2D-canvas HTML presentation.
|
|
5
|
+
Project-URL: Homepage, https://scrolly.readthedocs.io/en/stable/
|
|
6
|
+
Project-URL: Documentation, https://scrolly.readthedocs.io/en/stable/
|
|
7
|
+
Project-URL: Source, https://github.com/bertpl/scrolly
|
|
8
|
+
Project-URL: Changelog, https://github.com/bertpl/scrolly/blob/main/CHANGELOG.md
|
|
9
|
+
Project-URL: Issues, https://github.com/bertpl/scrolly/issues
|
|
10
|
+
Author-email: Bert Pluymers <bert.pluymers@gmail.com>
|
|
11
|
+
License-Expression: MIT
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Keywords: cli,html,presentation,scrollytelling,slides
|
|
14
|
+
Classifier: Development Status :: 4 - Beta
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
17
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
22
|
+
Classifier: Topic :: Multimedia :: Graphics :: Presentation
|
|
23
|
+
Classifier: Topic :: Text Processing :: Markup :: HTML
|
|
24
|
+
Requires-Python: >=3.11
|
|
25
|
+
Requires-Dist: click>=8.2.0
|
|
26
|
+
Requires-Dist: jinja2>=3.1
|
|
27
|
+
Requires-Dist: json5>=0.13.0
|
|
28
|
+
Requires-Dist: markdown>=3.4
|
|
29
|
+
Requires-Dist: pydantic>=2.0
|
|
30
|
+
Requires-Dist: pyyaml>=6.0
|
|
31
|
+
Requires-Dist: rich>=13.0.0
|
|
32
|
+
Description-Content-Type: text/markdown
|
|
33
|
+
|
|
34
|
+
# scrolly
|
|
35
|
+
|
|
36
|
+
Compile a JSON5 deck into a single, self-contained, scrollable 2D-canvas HTML presentation.
|
|
37
|
+
|
|
38
|
+
*Liked by humans; understood by agents.*
|
|
39
|
+
|
|
40
|
+
[](https://scrolly.readthedocs.io/en/stable/)
|
|
41
|
+
|
|
42
|
+
[](https://github.com/bertpl/scrolly/actions/workflows/push_to_main.yml)
|
|
43
|
+
[](https://pypi.org/project/scrolly/)
|
|
44
|
+
[](https://pypi.org/project/scrolly/)
|
|
45
|
+
[](https://github.com/bertpl/scrolly/blob/main/LICENSE)
|
|
46
|
+
|
|
47
|
+
## Why it's different
|
|
48
|
+
|
|
49
|
+
- **A 2D canvas you fly around**, not a linear reel. Slides sit on an
|
|
50
|
+
integer grid connected by edges; readers zoom out to a deck map and
|
|
51
|
+
zoom into any slide to scroll through it.
|
|
52
|
+
- **Scroll-driven keyframe animation.** Element properties (position,
|
|
53
|
+
size, opacity, scale, angle) interpolate as the reader scrolls — no
|
|
54
|
+
timeline, no autoplay.
|
|
55
|
+
- **One self-contained HTML file.** A default build inlines every
|
|
56
|
+
asset into a single `index.html` with zero external loads — open it
|
|
57
|
+
by double-clicking, host it anywhere, email it.
|
|
58
|
+
- **Agent-friendly.** The CLI exposes full help, input schemas, deck
|
|
59
|
+
introspection, and numbered error codes, so agentic coding tools
|
|
60
|
+
immediately understand how to author and debug scrolly decks.
|
|
61
|
+
|
|
62
|
+
## Installation
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
pip install scrolly # or: uv tool install scrolly
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Quickstart
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
scrolly init my-deck # scaffold a starter deck
|
|
72
|
+
scrolly build my-deck/deck.deck.json --out out --force # compile to one HTML file
|
|
73
|
+
open out/index.html # double-click anywhere
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
A deck is a `.deck.json` manifest plus one `.slide.json` per slide (both
|
|
77
|
+
parsed as JSON5):
|
|
78
|
+
|
|
79
|
+
```json5
|
|
80
|
+
// deck.deck.json
|
|
81
|
+
{
|
|
82
|
+
title: "My Deck",
|
|
83
|
+
slides: [
|
|
84
|
+
{ id: "intro", position: [0, 0], source: "slides/intro.slide.json" },
|
|
85
|
+
],
|
|
86
|
+
edges: [],
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
```json5
|
|
91
|
+
// slides/intro.slide.json
|
|
92
|
+
{
|
|
93
|
+
title: "My Deck",
|
|
94
|
+
elements: [
|
|
95
|
+
{ markdown: "# My Deck\n\nWelcome to your new presentation." },
|
|
96
|
+
],
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Elements
|
|
101
|
+
|
|
102
|
+
Slides hold elements of six types — `markdown`, `image`, `image_sequence`,
|
|
103
|
+
`mermaid`, `html`, and `iframe` — each animatable via scroll-driven
|
|
104
|
+
keyframes. See the [element reference](https://scrolly.readthedocs.io/en/stable/reference/elements/)
|
|
105
|
+
for fields and examples.
|
|
106
|
+
|
|
107
|
+
## Learn more
|
|
108
|
+
|
|
109
|
+
- **[Documentation](https://scrolly.readthedocs.io/en/stable/)** — guided
|
|
110
|
+
walkthrough, concepts, authoring, and the full reference, with a live
|
|
111
|
+
interactive deck right on the homepage.
|
|
112
|
+
- **[Examples](examples/)** — including the
|
|
113
|
+
[stacked-diffs](examples/stacked-diffs/) hero deck.
|
|
114
|
+
- **[Changelog](CHANGELOG.md)**.
|
|
115
|
+
|
|
116
|
+
## License
|
|
117
|
+
|
|
118
|
+
[MIT](https://github.com/bertpl/scrolly/blob/main/LICENSE).
|
scrolly-0.2.4/README.md
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# scrolly
|
|
2
|
+
|
|
3
|
+
Compile a JSON5 deck into a single, self-contained, scrollable 2D-canvas HTML presentation.
|
|
4
|
+
|
|
5
|
+
*Liked by humans; understood by agents.*
|
|
6
|
+
|
|
7
|
+
[](https://scrolly.readthedocs.io/en/stable/)
|
|
8
|
+
|
|
9
|
+
[](https://github.com/bertpl/scrolly/actions/workflows/push_to_main.yml)
|
|
10
|
+
[](https://pypi.org/project/scrolly/)
|
|
11
|
+
[](https://pypi.org/project/scrolly/)
|
|
12
|
+
[](https://github.com/bertpl/scrolly/blob/main/LICENSE)
|
|
13
|
+
|
|
14
|
+
## Why it's different
|
|
15
|
+
|
|
16
|
+
- **A 2D canvas you fly around**, not a linear reel. Slides sit on an
|
|
17
|
+
integer grid connected by edges; readers zoom out to a deck map and
|
|
18
|
+
zoom into any slide to scroll through it.
|
|
19
|
+
- **Scroll-driven keyframe animation.** Element properties (position,
|
|
20
|
+
size, opacity, scale, angle) interpolate as the reader scrolls — no
|
|
21
|
+
timeline, no autoplay.
|
|
22
|
+
- **One self-contained HTML file.** A default build inlines every
|
|
23
|
+
asset into a single `index.html` with zero external loads — open it
|
|
24
|
+
by double-clicking, host it anywhere, email it.
|
|
25
|
+
- **Agent-friendly.** The CLI exposes full help, input schemas, deck
|
|
26
|
+
introspection, and numbered error codes, so agentic coding tools
|
|
27
|
+
immediately understand how to author and debug scrolly decks.
|
|
28
|
+
|
|
29
|
+
## Installation
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pip install scrolly # or: uv tool install scrolly
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Quickstart
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
scrolly init my-deck # scaffold a starter deck
|
|
39
|
+
scrolly build my-deck/deck.deck.json --out out --force # compile to one HTML file
|
|
40
|
+
open out/index.html # double-click anywhere
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
A deck is a `.deck.json` manifest plus one `.slide.json` per slide (both
|
|
44
|
+
parsed as JSON5):
|
|
45
|
+
|
|
46
|
+
```json5
|
|
47
|
+
// deck.deck.json
|
|
48
|
+
{
|
|
49
|
+
title: "My Deck",
|
|
50
|
+
slides: [
|
|
51
|
+
{ id: "intro", position: [0, 0], source: "slides/intro.slide.json" },
|
|
52
|
+
],
|
|
53
|
+
edges: [],
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
```json5
|
|
58
|
+
// slides/intro.slide.json
|
|
59
|
+
{
|
|
60
|
+
title: "My Deck",
|
|
61
|
+
elements: [
|
|
62
|
+
{ markdown: "# My Deck\n\nWelcome to your new presentation." },
|
|
63
|
+
],
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Elements
|
|
68
|
+
|
|
69
|
+
Slides hold elements of six types — `markdown`, `image`, `image_sequence`,
|
|
70
|
+
`mermaid`, `html`, and `iframe` — each animatable via scroll-driven
|
|
71
|
+
keyframes. See the [element reference](https://scrolly.readthedocs.io/en/stable/reference/elements/)
|
|
72
|
+
for fields and examples.
|
|
73
|
+
|
|
74
|
+
## Learn more
|
|
75
|
+
|
|
76
|
+
- **[Documentation](https://scrolly.readthedocs.io/en/stable/)** — guided
|
|
77
|
+
walkthrough, concepts, authoring, and the full reference, with a live
|
|
78
|
+
interactive deck right on the homepage.
|
|
79
|
+
- **[Examples](examples/)** — including the
|
|
80
|
+
[stacked-diffs](examples/stacked-diffs/) hero deck.
|
|
81
|
+
- **[Changelog](CHANGELOG.md)**.
|
|
82
|
+
|
|
83
|
+
## License
|
|
84
|
+
|
|
85
|
+
[MIT](https://github.com/bertpl/scrolly/blob/main/LICENSE).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "scrolly"
|
|
3
|
-
version = "0.2.
|
|
3
|
+
version = "0.2.4"
|
|
4
4
|
description = "CLI that compiles a JSON5 deck + slide files into a self-contained 2D-canvas HTML presentation."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "MIT"
|
|
@@ -54,6 +54,8 @@ capture = [
|
|
|
54
54
|
scrolly = "scrolly._cli._cli:cli"
|
|
55
55
|
|
|
56
56
|
[project.urls]
|
|
57
|
+
Homepage = "https://scrolly.readthedocs.io/en/stable/"
|
|
58
|
+
Documentation = "https://scrolly.readthedocs.io/en/stable/"
|
|
57
59
|
Source = "https://github.com/bertpl/scrolly"
|
|
58
60
|
Changelog = "https://github.com/bertpl/scrolly/blob/main/CHANGELOG.md"
|
|
59
61
|
Issues = "https://github.com/bertpl/scrolly/issues"
|
|
@@ -8,6 +8,7 @@ from rich.console import Console
|
|
|
8
8
|
from scrolly import __version__
|
|
9
9
|
from scrolly._cli._errors import errors_command
|
|
10
10
|
from scrolly._cli._introspect import introspect
|
|
11
|
+
from scrolly._cli._schema import schema
|
|
11
12
|
from scrolly.errors import ScrollyError, ValidationError
|
|
12
13
|
from scrolly.pipeline import build_deck, load_deck
|
|
13
14
|
from scrolly.pipeline.lint import lint_deck
|
|
@@ -82,52 +83,6 @@ def build(
|
|
|
82
83
|
click.echo(f"Built '{deck.title or '(untitled)'}': {len(deck.slides)} slides, {len(deck.edges)} edges → {out_dir}")
|
|
83
84
|
|
|
84
85
|
|
|
85
|
-
@cli.command()
|
|
86
|
-
@click.argument("type_name", required=False)
|
|
87
|
-
@click.option(
|
|
88
|
-
"--list-types",
|
|
89
|
-
"list_types",
|
|
90
|
-
is_flag=True,
|
|
91
|
-
help="Print bare type names one per line (no descriptions) for scripting use.",
|
|
92
|
-
)
|
|
93
|
-
def schema(type_name: str | None, list_types: bool) -> None:
|
|
94
|
-
"""Show source file schemas.
|
|
95
|
-
|
|
96
|
-
\b
|
|
97
|
-
scrolly schema → formatted index of available types
|
|
98
|
-
scrolly schema <type> → JSON Schema for <type>
|
|
99
|
-
scrolly schema --list-types → bare type names, one per line (agent / scripting)
|
|
100
|
-
"""
|
|
101
|
-
from scrolly.deck import deck_source_schema
|
|
102
|
-
from scrolly.slide import registered_ir_types
|
|
103
|
-
|
|
104
|
-
ir_types = registered_ir_types()
|
|
105
|
-
all_type_names = sorted(["deck", *ir_types])
|
|
106
|
-
|
|
107
|
-
if list_types:
|
|
108
|
-
for name in all_type_names:
|
|
109
|
-
click.echo(name)
|
|
110
|
-
return
|
|
111
|
-
|
|
112
|
-
if type_name is None:
|
|
113
|
-
click.echo("Available schemas:\n")
|
|
114
|
-
click.echo(f" {'deck':<17}{'.deck.json':<24}Deck structure (slides + edges)")
|
|
115
|
-
for name in sorted(ir_types):
|
|
116
|
-
cls = ir_types[name]
|
|
117
|
-
click.echo(f" {name:<17}{cls.SUFFIX:<24}{cls.DESCRIPTION}")
|
|
118
|
-
return
|
|
119
|
-
|
|
120
|
-
if type_name == "deck":
|
|
121
|
-
click.echo(json.dumps(deck_source_schema(), indent=2))
|
|
122
|
-
return
|
|
123
|
-
|
|
124
|
-
if type_name not in ir_types:
|
|
125
|
-
_err_console.print(f"[red]error:[/red] unknown type '{type_name}' (known: {', '.join(all_type_names)})")
|
|
126
|
-
sys.exit(1)
|
|
127
|
-
|
|
128
|
-
click.echo(json.dumps(ir_types[type_name].source_schema(), indent=2))
|
|
129
|
-
|
|
130
|
-
|
|
131
86
|
@cli.command()
|
|
132
87
|
@click.argument("deck_path", type=click.Path(exists=True, dir_okay=False, path_type=Path))
|
|
133
88
|
@click.option("--strict", is_flag=True, help="Enable additional lint checks (e.g. out-of-range keyframes).")
|
|
@@ -217,3 +172,4 @@ def init(dir_path: Path) -> None:
|
|
|
217
172
|
|
|
218
173
|
cli.add_command(errors_command)
|
|
219
174
|
cli.add_command(introspect)
|
|
175
|
+
cli.add_command(schema)
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"""``scrolly schema`` — show source-file and slide-element schemas from the CLI.
|
|
2
|
+
|
|
3
|
+
A Click group with two parallel subcommands, mirroring the
|
|
4
|
+
subcommand-group structure of ``scrolly introspect``:
|
|
5
|
+
|
|
6
|
+
* ``scrolly schema`` — combined index of file and element schemas.
|
|
7
|
+
* ``scrolly schema file`` — index of source-file schemas (deck, slide).
|
|
8
|
+
* ``scrolly schema file <type>`` — JSON Schema for a source-file type.
|
|
9
|
+
* ``scrolly schema file --list-types`` — bare file-type names, one per line.
|
|
10
|
+
* ``scrolly schema element`` — index of element schemas.
|
|
11
|
+
* ``scrolly schema element <type>`` — JSON Schema for an element type.
|
|
12
|
+
* ``scrolly schema element --list-types`` — bare element keys, one per line.
|
|
13
|
+
|
|
14
|
+
``schema`` shows static *type* definitions; ``introspect`` inspects a
|
|
15
|
+
specific *resolved deck instance* — different surfaces, kept distinct.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
import json
|
|
21
|
+
import sys
|
|
22
|
+
|
|
23
|
+
import click
|
|
24
|
+
from rich.console import Console
|
|
25
|
+
|
|
26
|
+
_err_console = Console(stderr=True, highlight=False)
|
|
27
|
+
|
|
28
|
+
# Width of the name / suffix columns in the human-readable index, matching
|
|
29
|
+
# the alignment used by ``scrolly errors``.
|
|
30
|
+
_NAME_COL = 17
|
|
31
|
+
_SUFFIX_COL = 24
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
# ==================================================================================================
|
|
35
|
+
# schema group
|
|
36
|
+
# ==================================================================================================
|
|
37
|
+
@click.group(name="schema", invoke_without_command=True)
|
|
38
|
+
@click.pass_context
|
|
39
|
+
def schema(ctx: click.Context) -> None:
|
|
40
|
+
"""Show source-file and slide-element schemas.
|
|
41
|
+
|
|
42
|
+
\b
|
|
43
|
+
scrolly schema → combined index (file + element schemas)
|
|
44
|
+
scrolly schema file [<type>] → source-file schemas (deck, slide)
|
|
45
|
+
scrolly schema element [<type>] → slide-element schemas (markdown, image, …)
|
|
46
|
+
|
|
47
|
+
Append --list-types to either subcommand for bare names (agent / scripting).
|
|
48
|
+
Shows static type definitions; use `scrolly introspect` for a resolved deck.
|
|
49
|
+
"""
|
|
50
|
+
if ctx.invoked_subcommand is None:
|
|
51
|
+
_print_file_index()
|
|
52
|
+
click.echo()
|
|
53
|
+
_print_element_index()
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
# --------------------------------------------------------------------------
|
|
57
|
+
# Subcommands
|
|
58
|
+
# --------------------------------------------------------------------------
|
|
59
|
+
@schema.command(name="file")
|
|
60
|
+
@click.argument("type_name", required=False)
|
|
61
|
+
@click.option(
|
|
62
|
+
"--list-types",
|
|
63
|
+
"list_types",
|
|
64
|
+
is_flag=True,
|
|
65
|
+
help="Print bare file-type names one per line (no descriptions) for scripting use.",
|
|
66
|
+
)
|
|
67
|
+
def schema_file(type_name: str | None, list_types: bool) -> None:
|
|
68
|
+
"""Source-file schemas (deck, slide).
|
|
69
|
+
|
|
70
|
+
\b
|
|
71
|
+
scrolly schema file → formatted index of file types
|
|
72
|
+
scrolly schema file <type> → JSON Schema for <type>
|
|
73
|
+
scrolly schema file --list-types → bare type names, one per line (agent / scripting)
|
|
74
|
+
"""
|
|
75
|
+
names = _file_type_names()
|
|
76
|
+
|
|
77
|
+
if list_types:
|
|
78
|
+
for name in names:
|
|
79
|
+
click.echo(name)
|
|
80
|
+
return
|
|
81
|
+
|
|
82
|
+
if type_name is None:
|
|
83
|
+
_print_file_index()
|
|
84
|
+
return
|
|
85
|
+
|
|
86
|
+
schema_dict = _file_schema(type_name)
|
|
87
|
+
if schema_dict is None:
|
|
88
|
+
_err_console.print(f"[red]error:[/red] unknown file type '{type_name}' (known: {', '.join(names)})")
|
|
89
|
+
sys.exit(1)
|
|
90
|
+
click.echo(json.dumps(schema_dict, indent=2))
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
@schema.command(name="element")
|
|
94
|
+
@click.argument("type_name", required=False)
|
|
95
|
+
@click.option(
|
|
96
|
+
"--list-types",
|
|
97
|
+
"list_types",
|
|
98
|
+
is_flag=True,
|
|
99
|
+
help="Print bare element keys one per line (no descriptions) for scripting use.",
|
|
100
|
+
)
|
|
101
|
+
def schema_element(type_name: str | None, list_types: bool) -> None:
|
|
102
|
+
"""Slide-element schemas (markdown, image, …).
|
|
103
|
+
|
|
104
|
+
\b
|
|
105
|
+
scrolly schema element → formatted index of element types
|
|
106
|
+
scrolly schema element <type> → JSON Schema for <type>
|
|
107
|
+
scrolly schema element --list-types → bare element keys, one per line (agent / scripting)
|
|
108
|
+
"""
|
|
109
|
+
from scrolly.slide import element_source_types
|
|
110
|
+
|
|
111
|
+
elements = element_source_types()
|
|
112
|
+
|
|
113
|
+
if list_types:
|
|
114
|
+
for key in elements:
|
|
115
|
+
click.echo(key)
|
|
116
|
+
return
|
|
117
|
+
|
|
118
|
+
if type_name is None:
|
|
119
|
+
_print_element_index()
|
|
120
|
+
return
|
|
121
|
+
|
|
122
|
+
if type_name not in elements:
|
|
123
|
+
_err_console.print(f"[red]error:[/red] unknown element type '{type_name}' (known: {', '.join(elements)})")
|
|
124
|
+
sys.exit(1)
|
|
125
|
+
click.echo(json.dumps(elements[type_name].source_schema(), indent=2))
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
# --------------------------------------------------------------------------
|
|
129
|
+
# Schema lookup + index rendering
|
|
130
|
+
# --------------------------------------------------------------------------
|
|
131
|
+
def _file_type_names() -> list[str]:
|
|
132
|
+
"""Return the sorted source-file type names (deck + registered slide types)."""
|
|
133
|
+
from scrolly.slide import registered_ir_types
|
|
134
|
+
|
|
135
|
+
return sorted(["deck", *registered_ir_types()])
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def _file_schema(type_name: str) -> dict | None:
|
|
139
|
+
"""Return the JSON Schema for a source-file type, or ``None`` if unknown."""
|
|
140
|
+
from scrolly.deck import deck_source_schema
|
|
141
|
+
from scrolly.slide import registered_ir_types
|
|
142
|
+
|
|
143
|
+
if type_name == "deck":
|
|
144
|
+
return deck_source_schema()
|
|
145
|
+
ir_types = registered_ir_types()
|
|
146
|
+
if type_name in ir_types:
|
|
147
|
+
return ir_types[type_name].source_schema()
|
|
148
|
+
return None
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def _print_file_index() -> None:
|
|
152
|
+
"""Print the human-readable index of source-file schemas."""
|
|
153
|
+
from scrolly.slide import registered_ir_types
|
|
154
|
+
|
|
155
|
+
click.echo("File schemas (source files):\n")
|
|
156
|
+
click.echo(f" {'deck':<{_NAME_COL}}{'.deck.json':<{_SUFFIX_COL}}Deck structure (slides + edges)")
|
|
157
|
+
for name, cls in sorted(registered_ir_types().items()):
|
|
158
|
+
click.echo(f" {name:<{_NAME_COL}}{cls.SUFFIX:<{_SUFFIX_COL}}{cls.DESCRIPTION}")
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def _print_element_index() -> None:
|
|
162
|
+
"""Print the human-readable index of slide-element schemas."""
|
|
163
|
+
from scrolly.slide import element_source_types
|
|
164
|
+
|
|
165
|
+
click.echo("Element schemas (slide elements):\n")
|
|
166
|
+
for key, cls in element_source_types().items():
|
|
167
|
+
click.echo(f" {key:<{_NAME_COL}}{cls.DESCRIPTION}")
|
|
@@ -14,5 +14,5 @@ require `title` and `elements`; per-slide entries in a deck require
|
|
|
14
14
|
|
|
15
15
|
## How to fix
|
|
16
16
|
|
|
17
|
-
Add the missing field. Run `scrolly schema deck` or `scrolly schema
|
|
18
|
-
slide` to see the full required
|
|
17
|
+
Add the missing field. Run `scrolly schema file deck` or `scrolly schema
|
|
18
|
+
file slide` to see the full required schema for each file type.
|
|
@@ -17,5 +17,5 @@ path embedded in the error message.
|
|
|
17
17
|
## How to fix
|
|
18
18
|
|
|
19
19
|
Read the embedded Pydantic message — it names the field path and the
|
|
20
|
-
constraint that failed. Cross-reference with `scrolly schema slide`
|
|
21
|
-
for the expected
|
|
20
|
+
constraint that failed. Cross-reference with `scrolly schema file slide`
|
|
21
|
+
for the expected schema of the slide source.
|
|
@@ -13,5 +13,6 @@ An element object with no recognised type field — no `markdown:`,
|
|
|
13
13
|
|
|
14
14
|
## How to fix
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
Run `scrolly schema element --list-types` to see the valid element
|
|
17
|
+
types, then `scrolly schema element <type>` for one's fields. Each
|
|
18
|
+
element must include the field that names its type.
|
|
@@ -1023,7 +1023,7 @@ body.pan-transitioning .canvas {
|
|
|
1023
1023
|
left: 0;
|
|
1024
1024
|
width: 100%;
|
|
1025
1025
|
height: 100%;
|
|
1026
|
-
background: rgba(
|
|
1026
|
+
background: rgba(200, 200, 200, 0.5);
|
|
1027
1027
|
backdrop-filter: blur(16px);
|
|
1028
1028
|
-webkit-backdrop-filter: blur(16px);
|
|
1029
1029
|
}
|
|
@@ -1651,6 +1651,18 @@
|
|
|
1651
1651
|
};
|
|
1652
1652
|
}
|
|
1653
1653
|
|
|
1654
|
+
// ---- resolveVersionLabel (pure — help-screen version display) ------------
|
|
1655
|
+
// The " vX.Y.Z" fragment shown after "scrolly" in the help About panel, or
|
|
1656
|
+
// "" when there is nothing to show. A `scrolly-version` URL override (null
|
|
1657
|
+
// when the param is absent) takes precedence over the built-in
|
|
1658
|
+
// `meta.version`; an empty override hides the version entirely — used by the
|
|
1659
|
+
// capture pipeline so rendered help screens don't bake in a pre-release
|
|
1660
|
+
// version number.
|
|
1661
|
+
function resolveVersionLabel(override, metaVersion) {
|
|
1662
|
+
const version = override !== null ? override : metaVersion;
|
|
1663
|
+
return version ? " v" + version : "";
|
|
1664
|
+
}
|
|
1665
|
+
|
|
1654
1666
|
// ---- Exports (for Node.js / Vitest testing) -------------------------------
|
|
1655
1667
|
|
|
1656
1668
|
if (typeof exports !== "undefined") {
|
|
@@ -1668,6 +1680,7 @@
|
|
|
1668
1680
|
exports.resolveTarget = resolveTarget;
|
|
1669
1681
|
exports.decompressBundle = decompressBundle;
|
|
1670
1682
|
exports.buildAutomationHook = buildAutomationHook;
|
|
1683
|
+
exports.resolveVersionLabel = resolveVersionLabel;
|
|
1671
1684
|
}
|
|
1672
1685
|
|
|
1673
1686
|
// ---- DOM code (skipped in Node.js) ----------------------------------------
|
|
@@ -2054,11 +2067,12 @@
|
|
|
2054
2067
|
const uniqueLine = formatCounts(p.unique);
|
|
2055
2068
|
const compressedLine = p.compressed ? "yes" : "no";
|
|
2056
2069
|
const savedLine = p.bytes_saved > 0 ? formatBytes(p.bytes_saved) : "0 B";
|
|
2070
|
+
const versionParam = new URLSearchParams(window.location.search).get("scrolly-version");
|
|
2057
2071
|
|
|
2058
2072
|
body.innerHTML =
|
|
2059
2073
|
'<h2>About</h2>' +
|
|
2060
2074
|
'<div class="help-about">' +
|
|
2061
|
-
'<p class="help-about-title"><strong>scrolly</strong>
|
|
2075
|
+
'<p class="help-about-title"><strong>scrolly</strong>' + resolveVersionLabel(versionParam, meta.version) + '</p>' +
|
|
2062
2076
|
'<p><a href="https://opensource.org/licenses/MIT" target="_blank" rel="noopener">MIT License</a></p>' +
|
|
2063
2077
|
'<p>' + meta.author + '</p>' +
|
|
2064
2078
|
'<p><a href="' + meta.pypi_url + '" target="_blank" rel="noopener">' + meta.pypi_url + '</a></p>' +
|
|
@@ -7,7 +7,7 @@ renderers with the element-IR registry.
|
|
|
7
7
|
|
|
8
8
|
from scrolly.slide.element_ir import renderers as _element_renderers # noqa: F401 — register element renderers
|
|
9
9
|
from scrolly.slide.html import SlideHTML
|
|
10
|
-
from scrolly.slide.ir import SlideIR
|
|
10
|
+
from scrolly.slide.ir import SlideIR, element_source_types
|
|
11
11
|
from scrolly.slide.processor import Renderer
|
|
12
12
|
from scrolly.slide.registry import (
|
|
13
13
|
find_renderer,
|
|
@@ -26,6 +26,7 @@ __all__ = [
|
|
|
26
26
|
"Renderer",
|
|
27
27
|
"SlideHTML",
|
|
28
28
|
"SlideIR",
|
|
29
|
+
"element_source_types",
|
|
29
30
|
"find_renderer",
|
|
30
31
|
"get_ir_class_for_path",
|
|
31
32
|
"register_ir",
|
|
@@ -15,6 +15,7 @@ from scrolly.slide.ir._framework.element import (
|
|
|
15
15
|
MarkdownElement,
|
|
16
16
|
MermaidElement,
|
|
17
17
|
SlideElement,
|
|
18
|
+
element_source_types,
|
|
18
19
|
)
|
|
19
20
|
from scrolly.slide.ir._framework.utils import parse_json5_ir, resolve_asset_paths
|
|
20
21
|
from scrolly.slide.ir.slide import SlideIR
|
|
@@ -33,6 +34,7 @@ __all__ = [
|
|
|
33
34
|
"SlideElement",
|
|
34
35
|
"SlideIR",
|
|
35
36
|
"Vec2Keyframes",
|
|
37
|
+
"element_source_types",
|
|
36
38
|
"parse_json5_ir",
|
|
37
39
|
"resolve_asset_paths",
|
|
38
40
|
]
|