create-effect-motion 0.4.0 → 0.5.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/dist/create.js +1 -1
- package/package.json +1 -1
- package/templates/default/AGENTS.md +22 -16
- package/templates/default/render.ts +14 -0
- package/templates/default/src/main.ts +2 -2
- package/templates/default/src/scenes/hello-world.ts +7 -5
- package/templates/default/studio.ts +16 -0
- package/templates/default/tsconfig.json +1 -1
- package/templates/default/motion.config.ts +0 -20
package/dist/create.js
CHANGED
|
@@ -127,7 +127,7 @@ const handler = (input) => Effect.gen(function* () {
|
|
|
127
127
|
`${name} is ready.`,
|
|
128
128
|
dir === cwd ? "" : ` cd ${path.relative(cwd, dir)}`,
|
|
129
129
|
` ${pm === "npm" ? "npm run" : pm} studio # preview scenes with hot reload`,
|
|
130
|
-
` ${pm === "npm" ? "npm run" : pm} render # render
|
|
130
|
+
` ${pm === "npm" ? "npm run" : pm} render # execute render.ts (the render program)`,
|
|
131
131
|
]
|
|
132
132
|
.filter((line) => line !== "")
|
|
133
133
|
.join("\n"));
|
package/package.json
CHANGED
|
@@ -4,14 +4,15 @@ This is an [effect-motion](https://github.com/julia-script/effect-motion) projec
|
|
|
4
4
|
|
|
5
5
|
## Layout and commands
|
|
6
6
|
|
|
7
|
-
- `src/scenes/*.ts` — one scene per module, each exporting `scene`.
|
|
7
|
+
- `src/scenes/*.ts` — one scene per module, each exporting `scene`. `Scene.make("Display Name", gen, meta?)` optionally names a scene for the studio picker.
|
|
8
8
|
- `src/main.ts` — the movie: an ordinary scene that sequences the others (`Scene.play` + `handle.finished`). Nothing is special about it.
|
|
9
|
-
- `
|
|
9
|
+
- `studio.ts` — the studio registration: `studioConfig({ scenes, layers })`. Record keys are unique identifiers; ONLY registered scenes appear in the picker, so add an import + entry for every new scene. Scenes with typed resources (fonts, images) need their loaders in `layers` — the file will not compile until every registered scene is covered.
|
|
10
|
+
- `render.ts` — an ordinary program default-exporting a `Video.render(...)` effect. More outputs are more calls; loader layers are provided here with `Effect.provide` (compile-checked). Knobs (paths, fps, seed) live in this code — there are no CLI flags.
|
|
10
11
|
- `src/assets/` — static files (images, fonts).
|
|
11
|
-
- `motion studio` — browser preview with hot reload
|
|
12
|
-
- `motion render [
|
|
12
|
+
- `motion studio [file]` — browser preview with hot reload of `studio.ts` (or the given entrypoint).
|
|
13
|
+
- `motion render [file]` — execute `render.ts` (or the given entrypoint) with the platform provided. `--verbose` prints full error cause chains. The same file runs standalone via `tsx render.ts` by piping through `NodeServices` from `@effect/platform-node`.
|
|
13
14
|
|
|
14
|
-
Verify a scene change by rendering it (`motion render
|
|
15
|
+
Verify a scene change by rendering it (`motion render`) or checking it in the running studio — not by reading code alone.
|
|
15
16
|
|
|
16
17
|
## Writing scenes
|
|
17
18
|
|
|
@@ -39,21 +40,26 @@ export const scene = Scene.make(function* () {
|
|
|
39
40
|
|
|
40
41
|
- **Never** use `Math.random()`, `Date.now()`, or any wall-clock/OS state in a scene — every run must be byte-identical. Use the provided seeded random (`Effect.random`, seeded from `settings.seed`).
|
|
41
42
|
- Durations land exactly on target on the final frame; springs snap on settle. Don't add "fudge" frames.
|
|
42
|
-
- Scene coordinates are the `
|
|
43
|
+
- Scene coordinates are the scene's OWN comp config — `Scene.make(gen, { width, height, backgroundColor })` (this template: 1920×1080). `dpr` (a `Video.render` option) scales output pixels, not coordinates.
|
|
43
44
|
- The `effect` dependency is pinned **exactly** — upgrading it can change seeded-random sequences. Never bump it casually; upgrade `effect` and `effect-motion` together, deliberately.
|
|
44
45
|
|
|
45
|
-
##
|
|
46
|
+
## Entrypoints
|
|
46
47
|
|
|
47
48
|
```ts
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
scene
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
49
|
+
// studio.ts — what the studio previews
|
|
50
|
+
export default studioConfig({
|
|
51
|
+
scenes: {
|
|
52
|
+
intro, // key = identifier, label = scene name ?? key
|
|
53
|
+
fancy: { scene: fancy, fps: 30 }, // per-entry player options
|
|
54
|
+
},
|
|
55
|
+
// layers: Layer.mergeAll(Font.layer(...), …) // REQUIRED once a scene declares resources
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// render.ts — what `motion render` executes
|
|
59
|
+
export default Effect.gen(function* () {
|
|
60
|
+
yield* Video.render(intro, "./output/intro.mp4", { settings: { frameRate: 60 } });
|
|
61
|
+
// yield* Video.render(intro, "./output/intro-hd.mp4", { dpr: 2 }); // more outputs = more calls
|
|
56
62
|
});
|
|
57
63
|
```
|
|
58
64
|
|
|
59
|
-
|
|
65
|
+
Render the same scene several times for variants (resolutions, dpr). An infinite scene (one that never finishes) must pass `frames` in its `Video.render` options, or rendering would never end.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Video } from "@effect-motion/export";
|
|
2
|
+
import * as Effect from "effect/Effect";
|
|
3
|
+
import { scene as main } from "./src/main";
|
|
4
|
+
|
|
5
|
+
// An ordinary program: `motion render` executes this default export with
|
|
6
|
+
// the platform provided (it also runs standalone via `tsx render.ts` by
|
|
7
|
+
// piping through NodeServices from @effect/platform-node). More outputs
|
|
8
|
+
// are more Video.render calls; scenes with typed resources provide their
|
|
9
|
+
// loader layers right here with Effect.provide — checked at compile time.
|
|
10
|
+
export default Effect.gen(function* () {
|
|
11
|
+
yield* Video.render(main, "./output/main.mp4", {
|
|
12
|
+
settings: { frameRate: 60 },
|
|
13
|
+
});
|
|
14
|
+
});
|
|
@@ -2,8 +2,8 @@ import { Scene } from "effect-motion";
|
|
|
2
2
|
import { scene as helloWorld } from "./scenes/hello-world";
|
|
3
3
|
|
|
4
4
|
// The movie: an ordinary scene that sequences the scenes in src/scenes.
|
|
5
|
-
// Nothing is special about this file —
|
|
6
|
-
//
|
|
5
|
+
// Nothing is special about this file — studio.ts registers it and
|
|
6
|
+
// render.ts renders it like any other scene. Add scenes and chain them here.
|
|
7
7
|
export const scene = Scene.make(function* () {
|
|
8
8
|
const hello = yield* Scene.play(helloWorld);
|
|
9
9
|
yield* hello.finished;
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import { Color, Motion, Scene, Shapes } from "effect-motion";
|
|
2
2
|
|
|
3
3
|
// A scene is a generator: instantiate entities, then yield animations.
|
|
4
|
-
//
|
|
5
|
-
|
|
4
|
+
// The leading string is a DISPLAY name (the studio picker label); the
|
|
5
|
+
// studio.ts record key is its identifier. Preview with `motion studio`,
|
|
6
|
+
// render with `motion render`.
|
|
7
|
+
export const scene = Scene.make("Hello World", function* () {
|
|
6
8
|
const circle = yield* Scene.instantiate(Shapes.Circle, {
|
|
7
|
-
x:
|
|
8
|
-
y:
|
|
9
|
+
x: -660,
|
|
10
|
+
y: 0,
|
|
9
11
|
radius: 80,
|
|
10
12
|
fill: Color.hex("#7f5af0"),
|
|
11
13
|
});
|
|
12
14
|
|
|
13
|
-
yield* Motion.tweenTo(circle, { x:
|
|
15
|
+
yield* Motion.tweenTo(circle, { x: 660 }, "1200 millis", "easeInOutCubic");
|
|
14
16
|
yield* Motion.fadeTo(circle, 0, "400 millis");
|
|
15
17
|
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { studioConfig } from "@effect-motion/cli";
|
|
2
|
+
import { scene as main } from "./src/main";
|
|
3
|
+
import { scene as helloWorld } from "./src/scenes/hello-world";
|
|
4
|
+
|
|
5
|
+
// The studio's registration: keys are the picker's unique identifiers
|
|
6
|
+
// (labels come from Scene.make's display name when set). Register every
|
|
7
|
+
// scene you want to preview — `motion studio` serves exactly this record.
|
|
8
|
+
// When a scene declares typed resources (fonts, images), provide their
|
|
9
|
+
// loaders here as one `layers` (Layer.mergeAll(Font.layer(...), ...)) —
|
|
10
|
+
// the file will not compile until every registered scene is covered.
|
|
11
|
+
export default studioConfig({
|
|
12
|
+
scenes: {
|
|
13
|
+
"hello-world": helloWorld,
|
|
14
|
+
main,
|
|
15
|
+
},
|
|
16
|
+
});
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from "@effect-motion/cli";
|
|
2
|
-
|
|
3
|
-
// Each target is one rendered video: <output>/<name>.mp4
|
|
4
|
-
// `motion render` renders all of them; `motion render <name>` picks one.
|
|
5
|
-
export default defineConfig({
|
|
6
|
-
targets: [
|
|
7
|
-
{
|
|
8
|
-
name: "hello-world",
|
|
9
|
-
scene: "./src/scenes/hello-world.ts",
|
|
10
|
-
settings: { width: 1920, height: 1080, frameRate: 60 },
|
|
11
|
-
output: "./output",
|
|
12
|
-
},
|
|
13
|
-
{
|
|
14
|
-
name: "main",
|
|
15
|
-
scene: "./src/main.ts",
|
|
16
|
-
settings: { width: 1920, height: 1080, frameRate: 60 },
|
|
17
|
-
output: "./output",
|
|
18
|
-
},
|
|
19
|
-
],
|
|
20
|
-
});
|