@xplainer/motion 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +110 -0
- package/NOTICE +68 -0
- package/README.md +78 -2
- package/package.json +56 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
Copyright (c) 2026 BrewMyTech.
|
|
2
|
+
|
|
3
|
+
This repository is NOT under a single licence. Part of it is open source and
|
|
4
|
+
part of it is proprietary, and the line between them is drawn per directory
|
|
5
|
+
below. Read the whole of this file before copying anything out of here.
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
PART ONE — OPEN SOURCE, APACHE LICENCE 2.0
|
|
9
|
+
|
|
10
|
+
The eight packages published to npm — seven under the `@xplainer/` scope, plus
|
|
11
|
+
the unscoped `xplainer`, which is an alias for `@xplainer/cli` — are licensed
|
|
12
|
+
under the Apache Licence, Version 2.0:
|
|
13
|
+
|
|
14
|
+
apps/cli @xplainer/cli
|
|
15
|
+
packages/alias xplainer
|
|
16
|
+
packages/mcp-server @xplainer/mcp-server
|
|
17
|
+
packages/motion @xplainer/motion
|
|
18
|
+
packages/protocol @xplainer/protocol
|
|
19
|
+
packages/render-core @xplainer/render-core
|
|
20
|
+
packages/skill @xplainer/skill
|
|
21
|
+
packages/tts-client @xplainer/tts-client
|
|
22
|
+
|
|
23
|
+
Everything inside those eight directories is Apache-2.0, including the workspace
|
|
24
|
+
template and the scaffold templates under `packages/render-core`.
|
|
25
|
+
The full licence text is in LICENSE-APACHE-2.0 at the root of this repository,
|
|
26
|
+
and a copy of it is committed as `LICENSE` inside each of the eight package
|
|
27
|
+
directories so that it also travels inside every published tarball. The
|
|
28
|
+
attribution notice Apache-2.0 section 4(d) propagates is the NOTICE file, at
|
|
29
|
+
the root and inside each of the eight.
|
|
30
|
+
|
|
31
|
+
Each of those eight manifests declares `"license": "Apache-2.0"`. That SPDX
|
|
32
|
+
identifier is the authoritative statement for machine consumers.
|
|
33
|
+
|
|
34
|
+
Licensed under the Apache Licence, Version 2.0 (the "Licence"); you may
|
|
35
|
+
not use these files except in compliance with the Licence. You may obtain
|
|
36
|
+
a copy of the Licence at
|
|
37
|
+
|
|
38
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
39
|
+
|
|
40
|
+
Unless required by applicable law or agreed to in writing, software
|
|
41
|
+
distributed under the Licence is distributed on an "AS IS" BASIS, WITHOUT
|
|
42
|
+
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
43
|
+
Licence for the specific language governing permissions and limitations
|
|
44
|
+
under the Licence.
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
PART TWO — PROPRIETARY, ALL RIGHTS RESERVED
|
|
48
|
+
|
|
49
|
+
Every file that neither Part One nor Part Three names is proprietary. No
|
|
50
|
+
permission is granted to use, copy, modify, merge, publish, distribute,
|
|
51
|
+
sublicense, or sell any part of it. This covers, without being limited to:
|
|
52
|
+
|
|
53
|
+
apps/desktop the desktop client (tier: open-later)
|
|
54
|
+
packages/config shared build presets and tooling (tier: open-later)
|
|
55
|
+
services/tts-sidecar the packaged TTS sidecar (tier: open-later)
|
|
56
|
+
|
|
57
|
+
infra/ (but not infra/ffmpeg/, which is Part Three), scripts/, docs/,
|
|
58
|
+
.github/ (but not .github/workflows/ffmpeg-macos.yml, also Part Three),
|
|
59
|
+
and every other file at the root
|
|
60
|
+
|
|
61
|
+
No `hosted` member remains in this repository. `apps/api`, `apps/web` and
|
|
62
|
+
`services/media-service` were relocated to a private repository on 2026-09-06
|
|
63
|
+
(ADR 0023) and this file stopped listing them when they went; that tier stays
|
|
64
|
+
proprietary wherever it lives.
|
|
65
|
+
|
|
66
|
+
The three `open-later` members listed above are on a path to being opened but
|
|
67
|
+
have NOT been relicensed: opening the published packages did not open them,
|
|
68
|
+
and each still declares `"license": "UNLICENSED"` in its own manifest. Nothing
|
|
69
|
+
in Part One extends to them. Making this repository public did not change that
|
|
70
|
+
either — it made them readable, not usable.
|
|
71
|
+
|
|
72
|
+
The tier each package belongs to is declared in its own package.json as
|
|
73
|
+
`"xplainer": { "tier": "hosted" | "open-later" }`, and the boundary between
|
|
74
|
+
the tiers is machine-checked. The tier field describes intent; this file
|
|
75
|
+
describes the grant. Where they appear to disagree, this file and the
|
|
76
|
+
`license` field of the package's own manifest govern.
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
PART THREE — THE macOS FFMPEG BUILD SCRIPTS, MIT LICENCE
|
|
80
|
+
|
|
81
|
+
The scripts that build the macOS FFmpeg which `xplainer setup` downloads, and
|
|
82
|
+
the workflow that runs them, are licensed under the MIT Licence:
|
|
83
|
+
|
|
84
|
+
infra/ffmpeg/ except infra/ffmpeg/keys/
|
|
85
|
+
.github/workflows/ffmpeg-macos.yml
|
|
86
|
+
|
|
87
|
+
They are published beside every build as part of its complete corresponding
|
|
88
|
+
source ("the scripts used to control compilation and installation of the
|
|
89
|
+
executable", GPLv2 section 3), so that whoever receives the binary can rebuild
|
|
90
|
+
it. The full licence text is in infra/ffmpeg/LICENSE. Each of those files
|
|
91
|
+
carries `SPDX-License-Identifier: MIT`.
|
|
92
|
+
|
|
93
|
+
infra/ffmpeg/keys/ holds the OpenPGP public keys of FFmpeg's release signer and
|
|
94
|
+
of zlib's maintainer, unmodified, so that the build can check their signatures.
|
|
95
|
+
They are their owners'; nothing in this file licenses them.
|
|
96
|
+
|
|
97
|
+
The FFmpeg binary those scripts produce is not covered by any part of this
|
|
98
|
+
file. It is FFmpeg, x264 and zlib under the GNU General Public License version
|
|
99
|
+
2 or later, and every download carries their licences in its LICENSE file.
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
THIRD PARTY COMPONENTS
|
|
103
|
+
|
|
104
|
+
This software depends on components that others own, and `xplainer setup`
|
|
105
|
+
downloads more of them onto the machine it runs on, each under its own licence.
|
|
106
|
+
The Apache-2.0 grant in Part One covers this software only and grants you
|
|
107
|
+
nothing in respect of any of them. The NOTICE file names them and their terms.
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
Questions: rishav@brewmytech.com
|
package/NOTICE
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
xplainer.video
|
|
2
|
+
Copyright 2026 BrewMyTech
|
|
3
|
+
|
|
4
|
+
This product includes software developed by BrewMyTech (https://xplainer.video).
|
|
5
|
+
|
|
6
|
+
The packages published to npm — those under the `@xplainer/` scope and the
|
|
7
|
+
unscoped `xplainer`, which is an alias for `@xplainer/cli` — are licensed under
|
|
8
|
+
the Apache Licence, Version 2.0. See the LICENSE file distributed with each
|
|
9
|
+
package, or LICENSE-APACHE-2.0 in the source repository.
|
|
10
|
+
|
|
11
|
+
--------------------------------------------------------------------------------
|
|
12
|
+
|
|
13
|
+
THIRD PARTY COMPONENTS
|
|
14
|
+
|
|
15
|
+
This software depends on components owned by others, each under its own
|
|
16
|
+
licence. Those licences govern those components.
|
|
17
|
+
|
|
18
|
+
`@xplainer/render-core` redistributes the CMU Pronouncing Dictionary
|
|
19
|
+
(`cmudict.dict`), Copyright (C) 1993-2015 Carnegie Mellon University, under the
|
|
20
|
+
2-clause BSD licence reproduced verbatim beside it at
|
|
21
|
+
`packages/render-core/src/g2p/data/cmudict.LICENSE` and shipped in the package
|
|
22
|
+
at `dist/g2p/data/cmudict.LICENSE`. That licence's clause 1 requires the notice
|
|
23
|
+
and the disclaimer to travel with the source, which is why the file is copied
|
|
24
|
+
into the tarball rather than referenced.
|
|
25
|
+
|
|
26
|
+
`@xplainer/render-core` also redistributes the tokenizer of
|
|
27
|
+
`onnx-community/Kokoro-82M-v1.0-ONNX-timestamped` (`kokoro-tokenizer.json`),
|
|
28
|
+
Apache-2.0, as the authoritative list of the symbols the speech model accepts.
|
|
29
|
+
The model weights themselves are neither bundled nor redistributed here; they
|
|
30
|
+
are fetched from their upstream home, pinned by revision and digest.
|
|
31
|
+
|
|
32
|
+
`@xplainer/cli` depends on xz-decompress
|
|
33
|
+
(https://github.com/httptoolkit/xz-decompress), MIT, to unpack the `.tar.xz`
|
|
34
|
+
FFmpeg builds `xplainer setup` downloads on Linux. It is installed from the npm
|
|
35
|
+
registry as a declared dependency, not bundled. It contains, compiled to
|
|
36
|
+
WebAssembly, xzwasm (Copyright (c) Steve Sanderson, MIT), XZ Embedded by Lasse
|
|
37
|
+
Collin and Igor Pavlov (public domain) and walloc (Copyright (c) 2020 Igalia,
|
|
38
|
+
S.L., MIT). Its package carries no licence file; those are the terms its
|
|
39
|
+
`package.json` and the header of its own code state.
|
|
40
|
+
|
|
41
|
+
`xplainer setup` fetches two more components onto the machine it runs on, and
|
|
42
|
+
neither is bundled in or redistributed by any package here. The speech model
|
|
43
|
+
weights and voice pack of `onnx-community/Kokoro-82M-v1.0-ONNX-timestamped` are
|
|
44
|
+
Apache-2.0 and come from that repository, pinned by revision and digest. ONNX
|
|
45
|
+
Runtime (`onnxruntime-node` and `onnxruntime-common`, Copyright (c) Microsoft
|
|
46
|
+
Corporation) is MIT and comes from the npm registry, pinned by version and
|
|
47
|
+
digest; only the host platform's build is kept. `setup` is the one command that
|
|
48
|
+
downloads, it says what it is fetching and what each artefact must hash to, and
|
|
49
|
+
nothing is installed behind your back.
|
|
50
|
+
|
|
51
|
+
`xplainer setup` also acquires FFmpeg (https://ffmpeg.org), which xplainer
|
|
52
|
+
runs as a separate program and does not link, modify or bundle. On macOS,
|
|
53
|
+
`xplainer setup` downloads an FFmpeg program built by xplainer.video from
|
|
54
|
+
unmodified FFmpeg 9.0.2, x264 b35605ace3ddf7c1a5d67a2eb553f034aef41d55 and zlib
|
|
55
|
+
1.3.2, licensed under the GNU General Public License version 2 or later. Its
|
|
56
|
+
complete corresponding source is listed at
|
|
57
|
+
https://cdn.xplainer.video/toolchain/v1/ffmpeg/9.0.2/source/README.txt. On
|
|
58
|
+
Linux and Windows it downloads the GPL build BtbN publishes as FFmpeg-Builds
|
|
59
|
+
(https://github.com/FFmpeg-Builds/FFmpeg-Builds), licensed under the GNU
|
|
60
|
+
General Public License version 3 or later, from that project's own release.
|
|
61
|
+
The GPL texts travel with each download, not in these packages.
|
|
62
|
+
docs/third-party-components.md in the source repository lists every
|
|
63
|
+
component `setup` acquires. FFmpeg is a trademark of Fabrice Bellard,
|
|
64
|
+
originator of the FFmpeg project.
|
|
65
|
+
|
|
66
|
+
Apache-2.0 governs this software. It does not govern the components named above
|
|
67
|
+
— the FFmpeg builds and everything else `xplainer setup` acquires among them —
|
|
68
|
+
and nothing here grants you any right to them.
|
package/README.md
CHANGED
|
@@ -1,3 +1,79 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @xplainer/motion
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**The API explainer scenes are written against, and the page-side harness the xplainer renderer
|
|
4
|
+
drives one frame at a time.** A scene is ordinary React: it reads the frame, computes its picture
|
|
5
|
+
from it, and the renderer captures that picture once per frame.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm i @xplainer/motion react react-dom
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
```tsx
|
|
12
|
+
import { AbsoluteFill, Easing, interpolate, spring, useCurrentFrame, useVideoConfig } from "@xplainer/motion";
|
|
13
|
+
|
|
14
|
+
export const Title: React.FC<{ text: string }> = ({ text }) => {
|
|
15
|
+
const frame = useCurrentFrame();
|
|
16
|
+
const { fps } = useVideoConfig();
|
|
17
|
+
const opacity = interpolate(frame, [0, 15], [0, 1], { extrapolateRight: "clamp" });
|
|
18
|
+
const scale = spring({ frame, fps, config: { damping: 12 } });
|
|
19
|
+
const y = interpolate(frame, [0, 30], [40, 0], {
|
|
20
|
+
easing: Easing.out(Easing.cubic),
|
|
21
|
+
extrapolateRight: "clamp",
|
|
22
|
+
});
|
|
23
|
+
return (
|
|
24
|
+
<AbsoluteFill style={{ justifyContent: "center", alignItems: "center" }}>
|
|
25
|
+
<h1 style={{ opacity, transform: `translateY(${y}px) scale(${scale})` }}>{text}</h1>
|
|
26
|
+
</AbsoluteFill>
|
|
27
|
+
);
|
|
28
|
+
};
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## What is in it
|
|
32
|
+
|
|
33
|
+
| Kind | Exports |
|
|
34
|
+
|---|---|
|
|
35
|
+
| Frame and video | `useCurrentFrame`, `useVideoConfig` |
|
|
36
|
+
| Motion | `interpolate`, `Easing`, `spring`, `measureSpring`, `random` |
|
|
37
|
+
| Timing and layout | `Sequence`, `Series`, `Loop`, `Freeze`, `AbsoluteFill` |
|
|
38
|
+
| Media | `Img`, `Audio` (the narration marker), `staticFile` |
|
|
39
|
+
| Render holds | `delayRender`, `continueRender`, `cancelRender` |
|
|
40
|
+
| The video itself | `registerRoot`, `Composition`, `registerVideo`, `CalculateMetadataFunction` |
|
|
41
|
+
| Captions | `paginateCaptions`, `Caption`, `TikTokPage` |
|
|
42
|
+
|
|
43
|
+
Every motion function is a pure function of the frame, so a frame rendered out of order, or a
|
|
44
|
+
single still, is the same picture the full render shows. `spring` is the closed-form solution of a
|
|
45
|
+
damped harmonic oscillator; `Easing` holds the textbook closed forms; `random(seed)` is
|
|
46
|
+
deterministic per seed.
|
|
47
|
+
|
|
48
|
+
`<Video>` and `<OffthreadVideo>` throw `NOT_SUPPORTED_IN_V1` when rendered: video assets are not
|
|
49
|
+
supported by this renderer yet, so use `<Img>` stills. A second `<Audio>` beside the narration fails
|
|
50
|
+
the same way, because the narration is the only audio track the video gets. `staticFile()` takes a
|
|
51
|
+
name inside the video's public directory and refuses one that starts with `/` or climbs out of it
|
|
52
|
+
with `..`.
|
|
53
|
+
|
|
54
|
+
## The harness
|
|
55
|
+
|
|
56
|
+
`@xplainer/motion/harness` is a separate entry point with side effects, imported only by the
|
|
57
|
+
renderer's generated bundle, before the scene code. It runs the page on film time — `Date`,
|
|
58
|
+
`performance.now`, `setTimeout`, `setInterval` and `requestAnimationFrame` all advance only when the
|
|
59
|
+
renderer asks for the next frame — and before each frame is captured it waits for render holds,
|
|
60
|
+
images and fonts, and for the page to stop changing, so an image a scene's effects mount a few
|
|
61
|
+
React updates after the frame is still in that frame; a frame that never stops changing is released
|
|
62
|
+
with a warning in the job log. `Math.random` in the page is seeded, so it repeats from run to run.
|
|
63
|
+
A scene never imports it.
|
|
64
|
+
|
|
65
|
+
The exported surface of the main entry point is recorded in `api/motion.api.md` in the repository.
|
|
66
|
+
|
|
67
|
+
## Docs
|
|
68
|
+
|
|
69
|
+
- [Architecture][architecture] — the members and the dependency direction
|
|
70
|
+
- [Decision records][adr]
|
|
71
|
+
- [Roadmap][roadmap] — what is built and what is not
|
|
72
|
+
|
|
73
|
+
## Licence
|
|
74
|
+
|
|
75
|
+
Apache-2.0. See `LICENSE` and `NOTICE`, both shipped inside this package.
|
|
76
|
+
|
|
77
|
+
[architecture]: https://github.com/BrewMyTech/xplainer.video/blob/main/docs/ARCHITECTURE.md
|
|
78
|
+
[adr]: https://github.com/BrewMyTech/xplainer.video/blob/main/docs/adr/README.md
|
|
79
|
+
[roadmap]: https://github.com/BrewMyTech/xplainer.video/blob/main/docs/ROADMAP.md
|
package/package.json
CHANGED
|
@@ -1,6 +1,59 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xplainer/motion",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"description": "
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "The authoring API explainer scenes are written against — frame hooks, interpolate, Easing, spring, Sequence — and the page-side capture harness the xplainer renderer drives one frame at a time.",
|
|
6
|
+
"homepage": "https://xplainer.video",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/BrewMyTech/xplainer.video.git",
|
|
10
|
+
"directory": "packages/motion"
|
|
11
|
+
},
|
|
12
|
+
"author": "Rishav Anand <rishav@brewmytech.com>",
|
|
13
|
+
"license": "Apache-2.0",
|
|
14
|
+
"publishConfig": {
|
|
15
|
+
"access": "public"
|
|
16
|
+
},
|
|
17
|
+
"xplainer": {
|
|
18
|
+
"tier": "open-later"
|
|
19
|
+
},
|
|
20
|
+
"sideEffects": [
|
|
21
|
+
"./dist/harness.js"
|
|
22
|
+
],
|
|
23
|
+
"exports": {
|
|
24
|
+
".": {
|
|
25
|
+
"types": "./dist/index.d.ts",
|
|
26
|
+
"default": "./dist/index.js"
|
|
27
|
+
},
|
|
28
|
+
"./harness": {
|
|
29
|
+
"types": "./dist/harness.d.ts",
|
|
30
|
+
"default": "./dist/harness.js"
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"files": [
|
|
34
|
+
"dist/**/*.js",
|
|
35
|
+
"dist/**/*.d.ts",
|
|
36
|
+
"LICENSE",
|
|
37
|
+
"NOTICE"
|
|
38
|
+
],
|
|
39
|
+
"peerDependencies": {
|
|
40
|
+
"react": "^19.2.0",
|
|
41
|
+
"react-dom": "^19.2.0"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@types/node": "26.4.1",
|
|
45
|
+
"@types/react": "19.2.18",
|
|
46
|
+
"@types/react-dom": "19.2.7",
|
|
47
|
+
"@xplainer/config": "0.0.0",
|
|
48
|
+
"react": "19.2.8",
|
|
49
|
+
"react-dom": "19.2.8",
|
|
50
|
+
"typescript": "7.0.2",
|
|
51
|
+
"vitest": "5.0.0"
|
|
52
|
+
},
|
|
53
|
+
"scripts": {
|
|
54
|
+
"build": "tsc -p tsconfig.build.json && xplainer-minify-dist",
|
|
55
|
+
"lint": "biome check .",
|
|
56
|
+
"typecheck": "tsc --noEmit",
|
|
57
|
+
"test": "vitest run"
|
|
58
|
+
}
|
|
6
59
|
}
|