@cutcraft/kit 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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Bohdan Snisar
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,90 @@
1
- # Temporary Holding Version
1
+ <p align="center"><img src="../../docs/public/logo.svg" width="64" alt="cutcut logo"></p>
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ # @cutcraft/kit
4
+
5
+ The shared core of the cutcut editor: the JSX vocabulary a model writes, the
6
+ resolver that turns a file into absolute placements, the invertible action
7
+ system the editor dispatches, and the source tools that write those actions
8
+ back into the file.
9
+
10
+ The design is in [`docs/spec.md`](docs/spec.md). The mapping to OpenReel's action
11
+ set is in [`docs/parity.md`](docs/parity.md) (`pnpm parity` regenerates it).
12
+
13
+ ## The file
14
+
15
+ ```tsx
16
+ import { z } from "zod";
17
+ import { Clip, Composition, Title, Track, Transition } from "@cutcraft/kit";
18
+
19
+ export const schema = z.object({ title: z.string(), accent: z.string() });
20
+ export const defaults = { title: "Why we built it", accent: "#ff5a1f" };
21
+
22
+ export default function Video({ title, accent }: z.infer<typeof schema>) {
23
+ return (
24
+ <Composition fps={30} width={1920} height={1080}>
25
+ <Track id="main">
26
+ <Clip id="c1" src="asset:interview" in="word:3" out="word:18" />
27
+ <Transition id="x1" type="crossfade" duration={0.5} />
28
+ <Clip id="c2" src="asset:city" duration={4} fit="cover" />
29
+ </Track>
30
+ <Track id="overlays">
31
+ <Title id="t1" anchor="c1" offset={1} duration={3} color={accent}>{title}</Title>
32
+ </Track>
33
+ </Composition>
34
+ );
35
+ }
36
+ ```
37
+
38
+ Conventions the lint enforces: every element has a literal `id`; values a
39
+ human may edit are literals or `schema` props; helpers are pure; a sequence
40
+ track derives `start` from order (use `layout="free"` for absolute starts);
41
+ `in`/`out` may reference the asset manifest (`word:N`, `shot:N.end`,
42
+ `silence:N`, `marker:ID`).
43
+
44
+ ## The pipeline
45
+
46
+ ```
47
+ file.tsx ──evaluate──▶ element tree ──collect──▶ CollectedTree ──resolve(manifest, patches)──▶ ResolvedState
48
+ ▲ │
49
+ └── fold(patch log) ◀── Executor.execute(action) ◀── timeline / inspector / preview gestures ◀──┘
50
+ ```
51
+
52
+ - `collect(element)` walks the React element tree, expands pure helpers, and
53
+ indexes every vocabulary element by id. `collectModule(mod)` does it for an
54
+ imported file.
55
+ - `resolve(tree, manifest, log?)` places everything: sequence cursors, gaps,
56
+ transitions (overlap by their duration), anchors, `fill` and `match`
57
+ durations, transcript references, multicam cuts. Errors are typed and
58
+ attached to the element that caused them.
59
+ - Cost: a resolve is linear in the number of elements, about 2 µs per node
60
+ (1,000 nodes in ~2 ms). Parsed props are cached per raw props object and the
61
+ overlay keeps every node a patch did not touch, so a drag step re-parses one
62
+ element and re-derives one trim; every placement whose timing, props and
63
+ errors did not change is returned as the same object, so consumers can
64
+ memoise on `Placement` identity.
65
+ `pnpm bench` prints per-step costs on the sample fixture and a synthetic
66
+ 500-clip project.
67
+ - `new Executor({ tree, manifest })` runs actions. Each handler has four faces:
68
+ `validate`, `apply` (appends patches), `invert` (never null), `fold`. History
69
+ groups gestures and auto-groups rapid same-target updates. `undo()` and
70
+ `redo()` re-run inverses and originals through the same path.
71
+ - `buildSourceIndex(text)` maps ids to source ranges. `foldToSource(text, log, state)`
72
+ turns the patch log's net effect into text edits: a trim becomes one changed
73
+ token, an inserted element is printed in place, a generated element is baked
74
+ into literals first.
75
+ - `lint(text, { manifest })` returns the file-contract diagnostics.
76
+
77
+ ## Status
78
+
79
+ Every action in the spec is registered, applies, and round-trips through
80
+ undo/redo against `fixtures/sample.tsx` (which uses every element).
81
+ There is
82
+ no renderer: `useT()` and `useLayer()` throw until a Player installs one.
83
+ `interpolate()`, `spring()` and `random()` are pure and work anywhere.
84
+
85
+ ```
86
+ pnpm typecheck
87
+ pnpm lint
88
+ pnpm test # vitest, node and jsdom
89
+ pnpm parity # regenerate docs/parity.md
90
+ ```