truedemo 2.0.0__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.
- truedemo-2.0.0/LICENSE +204 -0
- truedemo-2.0.0/PKG-INFO +315 -0
- truedemo-2.0.0/README.md +277 -0
- truedemo-2.0.0/pyproject.toml +74 -0
- truedemo-2.0.0/setup.cfg +4 -0
- truedemo-2.0.0/tests/test_capture.py +1087 -0
- truedemo-2.0.0/tests/test_cli.py +236 -0
- truedemo-2.0.0/tests/test_core.py +227 -0
- truedemo-2.0.0/tests/test_docker.py +810 -0
- truedemo-2.0.0/tests/test_exec.py +986 -0
- truedemo-2.0.0/tests/test_ffmpeg.py +408 -0
- truedemo-2.0.0/tests/test_hygiene.py +262 -0
- truedemo-2.0.0/tests/test_job.py +366 -0
- truedemo-2.0.0/tests/test_mcp.py +736 -0
- truedemo-2.0.0/tests/test_movie.py +1093 -0
- truedemo-2.0.0/tests/test_presentation.py +715 -0
- truedemo-2.0.0/tests/test_provenance.py +233 -0
- truedemo-2.0.0/tests/test_providers.py +431 -0
- truedemo-2.0.0/tests/test_studio.py +1624 -0
- truedemo-2.0.0/tests/test_terminal.py +281 -0
- truedemo-2.0.0/tests/test_timeframe.py +364 -0
- truedemo-2.0.0/truedemo/__init__.py +24 -0
- truedemo-2.0.0/truedemo/__main__.py +6 -0
- truedemo-2.0.0/truedemo/_loop.py +192 -0
- truedemo-2.0.0/truedemo/_version.py +9 -0
- truedemo-2.0.0/truedemo/assembler.py +1223 -0
- truedemo-2.0.0/truedemo/capture.py +653 -0
- truedemo-2.0.0/truedemo/card.py +132 -0
- truedemo-2.0.0/truedemo/cli.py +450 -0
- truedemo-2.0.0/truedemo/context.py +193 -0
- truedemo-2.0.0/truedemo/errors.py +19 -0
- truedemo-2.0.0/truedemo/exec.py +1420 -0
- truedemo-2.0.0/truedemo/ffmpeg.py +666 -0
- truedemo-2.0.0/truedemo/job.py +609 -0
- truedemo-2.0.0/truedemo/mcp_server.py +1786 -0
- truedemo-2.0.0/truedemo/narration.py +176 -0
- truedemo-2.0.0/truedemo/overlay.py +75 -0
- truedemo-2.0.0/truedemo/panels.py +417 -0
- truedemo-2.0.0/truedemo/provenance.py +228 -0
- truedemo-2.0.0/truedemo/provider.py +185 -0
- truedemo-2.0.0/truedemo/py.typed +0 -0
- truedemo-2.0.0/truedemo/reports.py +501 -0
- truedemo-2.0.0/truedemo/scaffold.py +212 -0
- truedemo-2.0.0/truedemo/secrets.py +161 -0
- truedemo-2.0.0/truedemo/snapshot.py +159 -0
- truedemo-2.0.0/truedemo/spec.py +1476 -0
- truedemo-2.0.0/truedemo/studio.py +1503 -0
- truedemo-2.0.0/truedemo/svg.py +150 -0
- truedemo-2.0.0/truedemo/terminal.py +415 -0
- truedemo-2.0.0/truedemo/timeframe.py +468 -0
- truedemo-2.0.0/truedemo/tts.py +119 -0
- truedemo-2.0.0/truedemo/verify.py +564 -0
- truedemo-2.0.0/truedemo.egg-info/PKG-INFO +315 -0
- truedemo-2.0.0/truedemo.egg-info/SOURCES.txt +56 -0
- truedemo-2.0.0/truedemo.egg-info/dependency_links.txt +1 -0
- truedemo-2.0.0/truedemo.egg-info/entry_points.txt +3 -0
- truedemo-2.0.0/truedemo.egg-info/requires.txt +15 -0
- truedemo-2.0.0/truedemo.egg-info/top_level.txt +1 -0
truedemo-2.0.0/LICENSE
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
|
|
2
|
+
Copyright 2026 Anindyasundar Bera
|
|
3
|
+
|
|
4
|
+
Apache License
|
|
5
|
+
Version 2.0, January 2004
|
|
6
|
+
http://www.apache.org/licenses/
|
|
7
|
+
|
|
8
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
9
|
+
|
|
10
|
+
1. Definitions.
|
|
11
|
+
|
|
12
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
13
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
14
|
+
|
|
15
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
16
|
+
the copyright owner that is granting the License.
|
|
17
|
+
|
|
18
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
19
|
+
other entities that control, are controlled by, or are under common
|
|
20
|
+
control with that entity. For the purposes of this definition,
|
|
21
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
22
|
+
direction or management of such entity, whether by contract or
|
|
23
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
24
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
25
|
+
|
|
26
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
27
|
+
exercising permissions granted by this License.
|
|
28
|
+
|
|
29
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
30
|
+
including but not limited to software source code, documentation
|
|
31
|
+
source, and configuration files.
|
|
32
|
+
|
|
33
|
+
"Object" form shall mean any form resulting from mechanical
|
|
34
|
+
transformation or translation of a Source form, including but
|
|
35
|
+
not limited to compiled object code, generated documentation,
|
|
36
|
+
and conversions to other media types.
|
|
37
|
+
|
|
38
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
39
|
+
Object form, made available under the License, as indicated by a
|
|
40
|
+
copyright notice that is included in or attached to the work
|
|
41
|
+
(an example is provided in the Appendix below).
|
|
42
|
+
|
|
43
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
44
|
+
form, that is based on (or derived from) the Work and for which the
|
|
45
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
46
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
47
|
+
of this License, Derivative Works shall not include works that remain
|
|
48
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
49
|
+
the Work and Derivative Works thereof.
|
|
50
|
+
|
|
51
|
+
"Contribution" shall mean any work of authorship, including
|
|
52
|
+
the original version of the Work and any modifications or additions
|
|
53
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
54
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
55
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
56
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
57
|
+
means any form of electronic, verbal, or written communication sent
|
|
58
|
+
to the Licensor or its representatives, including but not limited to
|
|
59
|
+
communication on electronic mailing lists, source code control systems,
|
|
60
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
61
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
62
|
+
excluding communication that is conspicuously marked or otherwise
|
|
63
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
64
|
+
|
|
65
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
66
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
67
|
+
subsequently incorporated within the Work.
|
|
68
|
+
|
|
69
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
70
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
71
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
72
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
73
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
74
|
+
Work and such Derivative Works in Source or Object form.
|
|
75
|
+
|
|
76
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
77
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
78
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
79
|
+
(except as stated in this section) patent license to make, have made,
|
|
80
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
81
|
+
where such license applies only to those patent claims licensable
|
|
82
|
+
by such Contributor that are necessarily infringed by their
|
|
83
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
84
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
85
|
+
institute patent litigation against any entity (including a
|
|
86
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
87
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
88
|
+
or contributory patent infringement, then any patent licenses
|
|
89
|
+
granted to You under this License for that Work shall terminate
|
|
90
|
+
as of the date such litigation is filed.
|
|
91
|
+
|
|
92
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
93
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
94
|
+
modifications, and in Source or Object form, provided that You
|
|
95
|
+
meet the following conditions:
|
|
96
|
+
|
|
97
|
+
(a) You must give any other recipients of the Work or
|
|
98
|
+
Derivative Works a copy of this License; and
|
|
99
|
+
|
|
100
|
+
(b) You must cause any modified files to carry prominent notices
|
|
101
|
+
stating that You changed the files; and
|
|
102
|
+
|
|
103
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
104
|
+
that You distribute, all copyright, patent, trademark, and
|
|
105
|
+
attribution notices from the Source form of the Work,
|
|
106
|
+
excluding those notices that do not pertain to any part of
|
|
107
|
+
the Derivative Works; and
|
|
108
|
+
|
|
109
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
110
|
+
distribution, then any Derivative Works that You distribute must
|
|
111
|
+
include a readable copy of the attribution notices contained
|
|
112
|
+
within such NOTICE file, excluding those notices that do not
|
|
113
|
+
pertain to any part of the Derivative Works, in at least one
|
|
114
|
+
of the following places: within a NOTICE text file distributed
|
|
115
|
+
as part of the Derivative Works; within the Source form or
|
|
116
|
+
documentation, if provided along with the Derivative Works; or,
|
|
117
|
+
within a display generated by the Derivative Works, if and
|
|
118
|
+
wherever such third-party notices normally appear. The contents
|
|
119
|
+
of the NOTICE file are for informational purposes only and
|
|
120
|
+
do not modify the License. You may add Your own attribution
|
|
121
|
+
notices within Derivative Works that You distribute, alongside
|
|
122
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
123
|
+
that such additional attribution notices cannot be construed
|
|
124
|
+
as modifying the License.
|
|
125
|
+
|
|
126
|
+
You may add Your own copyright statement to Your modifications and
|
|
127
|
+
may provide additional or different license terms and conditions
|
|
128
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
129
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
130
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
131
|
+
the conditions stated in this License.
|
|
132
|
+
|
|
133
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
134
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
135
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
136
|
+
this License, without any additional terms or conditions.
|
|
137
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
138
|
+
the terms of any separate license agreement you may have executed
|
|
139
|
+
with Licensor regarding such Contributions.
|
|
140
|
+
|
|
141
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
142
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
143
|
+
except as required for reasonable and customary use in describing the
|
|
144
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
145
|
+
|
|
146
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
147
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
148
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
149
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
150
|
+
implied, including, without limitation, any warranties or conditions
|
|
151
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
152
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
153
|
+
appropriateness of using or redistributing the Work and assume any
|
|
154
|
+
risks associated with Your exercise of permissions under this License.
|
|
155
|
+
|
|
156
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
157
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
158
|
+
unless required by applicable law (such as deliberate and grossly
|
|
159
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
160
|
+
liable to You for damages, including any direct, indirect, special,
|
|
161
|
+
incidental, or consequential damages of any character arising as a
|
|
162
|
+
result of this License or out of the use or inability to use the
|
|
163
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
164
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
165
|
+
other commercial damages or losses), even if such Contributor
|
|
166
|
+
has been advised of the possibility of such damages.
|
|
167
|
+
|
|
168
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
169
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
170
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
171
|
+
or other liability obligations and/or rights consistent with this
|
|
172
|
+
License. However, in accepting such obligations, You may act only
|
|
173
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
174
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
175
|
+
defend, and hold each Contributor harmless for any liability
|
|
176
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
177
|
+
of your accepting any such warranty or additional liability.
|
|
178
|
+
|
|
179
|
+
END OF TERMS AND CONDITIONS
|
|
180
|
+
|
|
181
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
182
|
+
|
|
183
|
+
To apply the Apache License to your work, attach the following
|
|
184
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
185
|
+
replaced with your own identifying information. (Don't include
|
|
186
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
187
|
+
comment syntax for the file format. We also recommend that a
|
|
188
|
+
file or class name and description of purpose be included on the
|
|
189
|
+
same "printed page" as the copyright notice for easier
|
|
190
|
+
identification within third-party archives.
|
|
191
|
+
|
|
192
|
+
Copyright [yyyy] [name of copyright owner]
|
|
193
|
+
|
|
194
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
195
|
+
you may not use this file except in compliance with the License.
|
|
196
|
+
You may obtain a copy of the License at
|
|
197
|
+
|
|
198
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
199
|
+
|
|
200
|
+
Unless required by applicable law or agreed to in writing, software
|
|
201
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
202
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
203
|
+
See the License for the specific language governing permissions and
|
|
204
|
+
limitations under the License.
|
truedemo-2.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: truedemo
|
|
3
|
+
Version: 2.0.0
|
|
4
|
+
Summary: Create narrated, captioned demo videos of software — a real browser UI, a real terminal command, or a document it produces — from a declarative spec plus your own data; then reopen the .mp4 and verify every promise the spec made. Runs from a shell or an agent over MCP.
|
|
5
|
+
Author: Anindyasundar Bera
|
|
6
|
+
License-Expression: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/anindyasundarbera/truedemo
|
|
8
|
+
Project-URL: Repository, https://github.com/anindyasundarbera/truedemo
|
|
9
|
+
Project-URL: Issues, https://github.com/anindyasundarbera/truedemo/issues
|
|
10
|
+
Project-URL: Changelog, https://github.com/anindyasundarbera/truedemo/blob/main/CHANGELOG.md
|
|
11
|
+
Keywords: demo-video,screencast,video-generation,playwright,ffmpeg,mcp
|
|
12
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
21
|
+
Classifier: Topic :: Multimedia :: Video
|
|
22
|
+
Classifier: Topic :: Software Development :: Documentation
|
|
23
|
+
Requires-Python: <3.15,>=3.10
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
License-File: LICENSE
|
|
26
|
+
Requires-Dist: PyYAML<7,>=6.0.3
|
|
27
|
+
Provides-Extra: capture
|
|
28
|
+
Requires-Dist: playwright<2,>=1.63.0; extra == "capture"
|
|
29
|
+
Provides-Extra: tts
|
|
30
|
+
Requires-Dist: piper-tts<2,>=1.8.0; extra == "tts"
|
|
31
|
+
Provides-Extra: mcp
|
|
32
|
+
Requires-Dist: mcp<3,>=1.30.0; extra == "mcp"
|
|
33
|
+
Provides-Extra: dev
|
|
34
|
+
Requires-Dist: pytest<10,>=9.1.1; extra == "dev"
|
|
35
|
+
Requires-Dist: pytest-cov<8,>=7.1.0; extra == "dev"
|
|
36
|
+
Requires-Dist: ruff<1,>=0.16.10; extra == "dev"
|
|
37
|
+
Dynamic: license-file
|
|
38
|
+
|
|
39
|
+
# truedemo
|
|
40
|
+
|
|
41
|
+
**truedemo creates narrated, captioned demo videos of software.** Point it at a real browser UI
|
|
42
|
+
or a real terminal command, give it your own data, and describe the film in a small
|
|
43
|
+
declarative spec — it drives the software, records what it does, draws your data onto charts,
|
|
44
|
+
writes the narration, and assembles the result into an `.mp4` with an `.srt`. Then it
|
|
45
|
+
**reopens the finished `.mp4`** to check it kept every promise the spec made. A broken promise
|
|
46
|
+
fails the build. Run it from a shell, or let an autonomous agent drive it over MCP.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## What it is
|
|
51
|
+
|
|
52
|
+
You have a piece of software. You need a demo video of it — for a launch page, a README, a
|
|
53
|
+
customer, or a release. Today you make that by hand: drive the app, record the screen, write
|
|
54
|
+
a script, record a voice-over, cut the takes together, and type the numbers onto the slides.
|
|
55
|
+
It works, and it does not scale. Change the product and the video is stale; change the
|
|
56
|
+
numbers and the video is a lie that nobody notices until a customer does.
|
|
57
|
+
|
|
58
|
+
truedemo automates that whole loop from a declarative spec, and — the part that makes it worth
|
|
59
|
+
using — refuses to let the result be dishonest. Every frame comes from something real, and a
|
|
60
|
+
report re-opens the render to check the claims actually held.
|
|
61
|
+
|
|
62
|
+
**It is for** anyone who makes software demo videos by hand and is tired of them drifting
|
|
63
|
+
out of date, and for agents that must produce one without a human watching the screen.
|
|
64
|
+
|
|
65
|
+
**It films software you can drive on screen** — a web UI in a real browser, a command in a
|
|
66
|
+
real terminal, or a document the software produces. It does not capture a native desktop GUI,
|
|
67
|
+
invent a UI, or act as a video editor: there is no timeline to drag and no keyframes to set.
|
|
68
|
+
You declare shots, and truedemo builds the film and checks it.
|
|
69
|
+
|
|
70
|
+
> New here? [**A tour: what happens when you build**](docs/guides/tour.md) is the orientation —
|
|
71
|
+
> what a spec is, what the ten stages do, and what can be on screen.
|
|
72
|
+
|
|
73
|
+
## See it run
|
|
74
|
+
|
|
75
|
+
Thirty seconds, with no browser, no network, and no voice model — every number in this
|
|
76
|
+
example is counted from the files in this repository at the moment of the build:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
git clone https://github.com/anindyasundarbera/truedemo
|
|
80
|
+
cd truedemo
|
|
81
|
+
pip install -e ".[dev]" # ffmpeg and rsvg-convert are required; see Install below
|
|
82
|
+
|
|
83
|
+
truedemo doctor examples/hello-world/video.yaml # is this machine ready?
|
|
84
|
+
truedemo plan examples/hello-world/video.yaml # scenes, timings, guards — render nothing
|
|
85
|
+
truedemo build examples/hello-world/video.yaml # → hello-world.mp4 + .srt + verify.json
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
`plan` is the cheap one: it prints the whole scene plan and the estimated runtime without
|
|
89
|
+
touching a pixel. `build` is the real thing, and the `verify.json` it writes is the report
|
|
90
|
+
this project exists to produce. This example is the fixture CI builds on every push.
|
|
91
|
+
|
|
92
|
+
## Why it is honest
|
|
93
|
+
|
|
94
|
+
**Nothing is fabricated.** Every frame traces to something real: a live capture of a running
|
|
95
|
+
product, a chart drawn from a provider's measured data, or a declared graphic the engine drew
|
|
96
|
+
from the script's own words. There is no "mock UI" mode, because a mock UI is
|
|
97
|
+
indistinguishable from a real one once it is inside the `.mp4`.
|
|
98
|
+
|
|
99
|
+
**The engine then reopens the render and proves it.** `verify` does not read your spec back
|
|
100
|
+
to you. It decodes the finished `.mp4`, the `.srt`, and the audio track, and checks the
|
|
101
|
+
artifact against the promises the spec made. A broken promise fails the build.
|
|
102
|
+
|
|
103
|
+
The failure modes this prevents are boring and predictable, which is exactly why they keep
|
|
104
|
+
happening:
|
|
105
|
+
|
|
106
|
+
- The recording shows **development mode** while the narration says the product is live.
|
|
107
|
+
- A **caption runs off the screen** two lines into a sentence, so nobody reads it.
|
|
108
|
+
- The voice-over states a number that was **typed from memory**, not measured.
|
|
109
|
+
- The cut **drifts out of sync**, because the timing table was estimated rather than measured.
|
|
110
|
+
- The runtime is 26 minutes and the limit was 25.
|
|
111
|
+
- The script makes a claim the spec **explicitly forbade**, and nothing checks it.
|
|
112
|
+
|
|
113
|
+
Hand that job to an LLM agent and it hits every one of those faster, because the agent
|
|
114
|
+
cannot see the screen. It writes a spec, renders, and reports success. Nothing in that loop
|
|
115
|
+
ever asked whether the pixels agreed with the words.
|
|
116
|
+
|
|
117
|
+
And one rule that turned out to matter more than any single feature:
|
|
118
|
+
|
|
119
|
+
> **A declaration is not a measurement.** A check about what a picture *did* decodes the
|
|
120
|
+
> picture. A camera move declared in the spec is not a camera move until two frames of the
|
|
121
|
+
> finished clip disagree.
|
|
122
|
+
|
|
123
|
+
That rule has since caught real defects three separate times — including a check that could
|
|
124
|
+
never fail, because it compared a list against a filter of itself and cheerfully reported
|
|
125
|
+
*"5 of 6 shots move"* about shots that had only **said** they move.
|
|
126
|
+
|
|
127
|
+
## What it does
|
|
128
|
+
|
|
129
|
+
Ten stages, one pass, no timeline editor anywhere in it — `data` → `panels` → `stills` →
|
|
130
|
+
`capture` → `exec` → `narration` → `clips` → `concat` → `render` → `verify`. Each stage
|
|
131
|
+
reads something, writes a file, or stops the build.
|
|
132
|
+
|
|
133
|
+
The measured audio is the **master clock**: each scene's video segment is sized to the
|
|
134
|
+
duration ffmpeg measured from that scene's WAV, so sync is a consequence of the pipeline
|
|
135
|
+
rather than something you keep by hand. The [tour](docs/guides/tour.md#the-ten-stages) walks
|
|
136
|
+
each stage and the [pipeline](docs/foundations/pipeline.md) defines its exact inputs,
|
|
137
|
+
outputs, and failure conditions.
|
|
138
|
+
|
|
139
|
+
## Install
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
pip install -e . # the engine — YAML/JSON specs
|
|
143
|
+
pip install -e ".[capture]" # + Playwright, to film a real browser UI
|
|
144
|
+
pip install -e ".[tts]" # + Piper, for a local voice
|
|
145
|
+
pip install -e ".[mcp]" # + the MCP server (`truedemo-mcp`)
|
|
146
|
+
pip install -e ".[dev]" # + pytest
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Required external binaries are **`ffmpeg`** and **`rsvg-convert`** (Debian/Ubuntu:
|
|
150
|
+
`sudo apt-get install ffmpeg librsvg2-bin`). Optional: `ffprobe` (durations are read from
|
|
151
|
+
ffmpeg when absent), `pdftoppm`/`gs` (for filming PDFs), Chromium (Playwright), and a Piper
|
|
152
|
+
voice model. The extras are additive and independent — the core suite needs none of them.
|
|
153
|
+
|
|
154
|
+
`truedemo doctor` reports exactly which of these are present, and names the **missing rung**
|
|
155
|
+
rather than a bare "Docker: unavailable".
|
|
156
|
+
|
|
157
|
+
## The spec and your data
|
|
158
|
+
|
|
159
|
+
A spec is data. No code executes from it; the only code that runs is the provider module you
|
|
160
|
+
name. The loader refuses unknown top-level keys **by name**, so a typo is an error rather than
|
|
161
|
+
a silently dropped section. The [spec reference](docs/authoring/spec-reference.md) opens with
|
|
162
|
+
all fourteen legal keys on one screen; here is the shape:
|
|
163
|
+
|
|
164
|
+
```yaml
|
|
165
|
+
project: { title: …, slug: …, output: out.mp4, size: [1920, 1080], fps: 30,
|
|
166
|
+
min_seconds: 60, max_seconds: 120 }
|
|
167
|
+
story: { slug: …, title: … } # optional manifest, or a story.yaml folder
|
|
168
|
+
timeframe: { start: 2026-09-07, end: 2026-10-06 } # or { days: 90, as_of: … }
|
|
169
|
+
voice: { engine: piper, model: voice.onnx } # engine: none → declared silent cut
|
|
170
|
+
narration: { source: narration.md } # "## Scene N — … · mm:ss–mm:ss", spoken lines **bold**
|
|
171
|
+
provider: provider # provider.py: datasets, panels, stills
|
|
172
|
+
captures: [ … ] exec: { steps: [ … ] } environment: [ … ] charts: [ … ]
|
|
173
|
+
score: { src: bed.ogg, volume: 0.45, duck_db: -12.0 }
|
|
174
|
+
scenes: [ … ] guard: { banned: […], required: […] } style: { … }
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
**What can be on screen.** A scene holds one or more shots, and a shot's `weight` splits the
|
|
178
|
+
scene's time between them. Every shot is one of `still:`, `capture:`, `chart:`, `exec:`,
|
|
179
|
+
`card:`, or `solid:`, and any shot may carry `motion:` or `transition:`. The
|
|
180
|
+
[tour](docs/guides/tour.md#what-can-be-on-screen) lists each with what it shows, and the
|
|
181
|
+
[spec reference](docs/authoring/spec-reference.md#scenes) has every field and default.
|
|
182
|
+
|
|
183
|
+
**Your data.** `provider.py` is a plain module named in the spec, and it is the only code a
|
|
184
|
+
spec can run — all project-specific knowledge lives there, which is what keeps the engine
|
|
185
|
+
generic:
|
|
186
|
+
|
|
187
|
+
```python
|
|
188
|
+
from truedemo import panels as panel_lib
|
|
189
|
+
|
|
190
|
+
def register(): panel_lib.register("my_chart", my_chart_renderer)
|
|
191
|
+
def datasets(ctx): return {"trend": fetch_trend(), "totals": compute_totals()}
|
|
192
|
+
def panels(): return {"trend": {"kind": "my_chart", "dataset": "trend"}}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Datasets are snapshotted on every build, so a later render replays them offline — and a
|
|
196
|
+
*degraded* one is declared in the report rather than passed off as live. Eleven panel kinds
|
|
197
|
+
ship with the engine. See the [provider guide](docs/authoring/provider-guide.md) and the
|
|
198
|
+
[panels reference](docs/authoring/panels-reference.md).
|
|
199
|
+
|
|
200
|
+
## The studio — driving it from an agent
|
|
201
|
+
|
|
202
|
+
`truedemo-mcp` runs **separately** from the consumer's repo: the story stays in your repo, the
|
|
203
|
+
tool stays a tool. It is session-oriented — an agent opens a sitting, pokes at a live
|
|
204
|
+
environment, tries several takes, keeps the best, builds, and reads the report back:
|
|
205
|
+
|
|
206
|
+
```
|
|
207
|
+
session_open ──► session_exec / browser_open+browser_act ──► browser_shot ×3
|
|
208
|
+
│
|
|
209
|
+
take_select ┘
|
|
210
|
+
▼
|
|
211
|
+
session_build ──► session_report
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
There are **34 MCP tools** and **7 resources**. A selected take survives the build, and
|
|
215
|
+
budgets (wall-clock, container, step) are declared and refused rather than silently
|
|
216
|
+
overrun. The workflow, the tool groups, and the take/budget rules are in
|
|
217
|
+
[the studio reference](docs/operations/studio-reference.md); wiring the server into a client
|
|
218
|
+
is in the [MCP server](docs/operations/mcp-server.md) page.
|
|
219
|
+
|
|
220
|
+
For a transport-independent integration, the same work is available as a job:
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
truedemo --json run plan --story examples/hello-world # {action, story, out} → one manifest
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## Verification — the part that makes it worth using
|
|
227
|
+
|
|
228
|
+
`verify.json` is the point of the project. It is not a log; it is an argument about the
|
|
229
|
+
finished file, and every check can fail. There are **twenty kinds of check**, and a build
|
|
230
|
+
runs only the ones its spec can actually break — a typical build runs a dozen or so, covering
|
|
231
|
+
the runtime window, caption readability, frame size, audio presence, banned/required phrases,
|
|
232
|
+
the declared timeframe, live captures and filmed artifacts, sandboxed exec, dataset
|
|
233
|
+
freshness, and the honesty of every picture and camera move:
|
|
234
|
+
|
|
235
|
+
| A sample of the checks | What it establishes |
|
|
236
|
+
|---|---|
|
|
237
|
+
| `runtime within window` | The cut is inside the declared `min_seconds`/`max_seconds`. |
|
|
238
|
+
| `captions readable (<=2 lines, <=42 chars)` | Every cue fits on screen, two lines at most. |
|
|
239
|
+
| `banned phrase absent` / `required phrase present` | The script says what it must, and never what it must not. |
|
|
240
|
+
| `all live captures present` | Every capture the spec named is really in the film. |
|
|
241
|
+
| `every picture has an honest source` | Each artwork is a capture, a dataset, or a declared asset — nothing unknown. |
|
|
242
|
+
| `every camera move is accounted for` | `facts.motion[].mae` is **measured** from real frames; a move that did not move is reported. |
|
|
243
|
+
| `declared score is in the mix` | The bed really was mixed, with the measured ducking depth. |
|
|
244
|
+
|
|
245
|
+
The full table, and what each check does *not* prove, is in
|
|
246
|
+
[verification](docs/verification/verification.md). `provenance.json` answers a different
|
|
247
|
+
question — *what is this file?* — with the spec digest, the resolved timeframe, the provider,
|
|
248
|
+
and the tool versions that made it ([provenance](docs/verification/provenance.md)).
|
|
249
|
+
|
|
250
|
+
## Examples in this repo
|
|
251
|
+
|
|
252
|
+
| Example | Proves |
|
|
253
|
+
|---|---|
|
|
254
|
+
| [`hello-world`](examples/hello-world/) | The smallest complete build: offline, silent, every number measured from disk. The CI fixture. |
|
|
255
|
+
| [`capture-kit`](examples/capture-kit/) | A real page, scripted interactions, and assert-before-shot. |
|
|
256
|
+
| [`terminal-demo`](examples/terminal-demo/) | A real command in a real sandbox, recorded through a PTY and filmed. |
|
|
257
|
+
| [`docker-demo`](examples/docker-demo/) | A real Postgres, written to and read back **inside one container**, then torn down. |
|
|
258
|
+
| [`movie-demo`](examples/movie-demo/) | A film with **no capture, no provider, no browser**: drawn cards, a moving camera, a score. |
|
|
259
|
+
|
|
260
|
+
CI builds each of these as an end-to-end probe on a clean runner, and one more probe drives
|
|
261
|
+
the MCP server through a whole sitting — on top of the unit suite.
|
|
262
|
+
|
|
263
|
+
## Extending
|
|
264
|
+
|
|
265
|
+
The engine is meant to be extended from your provider, not edited — a new chart via
|
|
266
|
+
`panels.register()`, a new capture action, or a new TTS engine. The
|
|
267
|
+
[tour](docs/guides/tour.md#extending) lists the seams, and
|
|
268
|
+
[architecture](docs/foundations/architecture.md) maps every module, key type, and extension
|
|
269
|
+
point in one place.
|
|
270
|
+
|
|
271
|
+
## Layout
|
|
272
|
+
|
|
273
|
+
The engine is 29 modules behind one ten-stage pipeline.
|
|
274
|
+
[architecture](docs/foundations/architecture.md) maps every module, the one-way dependency
|
|
275
|
+
graph, and the typed seams between them.
|
|
276
|
+
|
|
277
|
+
## Docs
|
|
278
|
+
|
|
279
|
+
Docs are modular and machine-routable. Start at [`docs/README.md`](docs/README.md), or read
|
|
280
|
+
the route table in [`docs/modules.yaml`](docs/modules.yaml) — 26 routes across 7 modules.
|
|
281
|
+
An agent can fetch any doc by bare name over MCP (`truedemo_docs name="tour"`).
|
|
282
|
+
|
|
283
|
+
For the project's own record, see [`docs/plan/`](docs/plan/): [PLAN](docs/plan/PLAN.md) (now and
|
|
284
|
+
next), [HISTORY](docs/plan/HISTORY.md) (what happened, with evidence),
|
|
285
|
+
[DECISIONS](docs/plan/DECISIONS.md) (why, with alternatives), and the root
|
|
286
|
+
[ROADMAP.md](ROADMAP.md) (requirements and milestones).
|
|
287
|
+
|
|
288
|
+
## Tests
|
|
289
|
+
|
|
290
|
+
```bash
|
|
291
|
+
python3 -m pytest tests -q # 782 tests; the core needs no external tools
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
The suite is written to **skip honestly**: six independent capability markers
|
|
295
|
+
(`needs_render`, `needs_sandbox`, `needs_docker`, `needs_playwright`, `needs_mcp`,
|
|
296
|
+
`needs_pre_312_python`) each probe *whether that capability is usable*, not whether the
|
|
297
|
+
toolchain looks complete. CI runs the lean suite on Python 3.10 and 3.12, then builds the
|
|
298
|
+
examples end to end.
|
|
299
|
+
|
|
300
|
+
## What it is not
|
|
301
|
+
|
|
302
|
+
- **Not an NLE.** No timeline UI, no keyframe editing; a film is a sequence of shots.
|
|
303
|
+
- **Not a UI generator.** It films what runs. It will not invent an interface for you.
|
|
304
|
+
- **Not your data layer.** It reads; your provider owns the truth and the fetching.
|
|
305
|
+
- **Not a hosted service.** It runs locally and offline after install.
|
|
306
|
+
- **Not vendored.** Consumers point at the standalone server; the story stays in their repo.
|
|
307
|
+
|
|
308
|
+
## Status
|
|
309
|
+
|
|
310
|
+
`1.0.0`, Apache-2.0, and honest about where it is: the engine, the studio surface, capture,
|
|
311
|
+
sandboxed exec, Docker environments, and movie mode are merged and verified, and CI builds
|
|
312
|
+
the examples end to end on a clean runner. The MCP server supports SDK 1.x and 2.x
|
|
313
|
+
(`mcp>=1.20,<3`). What remains is release bookkeeping — the `v1.0.0` tag and the version for
|
|
314
|
+
these post-1.0 milestones are still an open owner decision — and a compositor
|
|
315
|
+
(picture-in-picture, masks, text over live motion), which is deliberately unowned.
|