diff --git a/apps/web/src/rendering/NOTES.md b/apps/web/src/rendering/NOTES.md deleted file mode 100644 index 38055c14..00000000 --- a/apps/web/src/rendering/NOTES.md +++ /dev/null @@ -1,27 +0,0 @@ -# Notes - -## `Transform` is misplaced - -`Transform` is currently defined in `apps/web/src/rendering/index.ts`. It's -exported from the rendering domain because rendering happens to be one of its -consumers — but every other domain that touches scene geometry consumes it too -(`@/timeline`, `@/preview`, `@/animation/values`, `@/text`, etc.). It's not -"of" rendering any more than `Vector2` would be "of" math. - -`Transform` is closer to a primitive than a domain concept. It's infrastructure: -a small value type with no behavior, no dependencies, no domain-specific -invariants. Anything that wants to position something on a 2D canvas needs it. - -The codebase should be refactored so it's defined lower-level, rather than -sitting in a domain. Candidate homes: - -- `apps/web/src/primitives/transform.ts` (new dir for these value types) -- `apps/web/src/geometry/transform.ts` if `Vector2` and friends end up there -- `apps/web/src/rendering/transform.ts` is acceptable only if `@/rendering` -becomes a primitives folder rather than a domain (it's borderline today — -it also exports `BlendMode`, which has the same problem). - -Side effect of fixing this: `@/rendering/animation-values.ts` (which exists -only because `Transform` lives next to it) can move into `@/animation/values.ts` -alongside the other resolve-at-time helpers, since `Transform` would no longer -pull in a domain dependency. \ No newline at end of file diff --git a/notes/primitives-vs-domains.md b/notes/primitives-vs-domains.md new file mode 100644 index 00000000..6708246c --- /dev/null +++ b/notes/primitives-vs-domains.md @@ -0,0 +1,57 @@ +# Primitives vs domains + +The codebase has a recurring smell: **primitive value types defined inside +domain folders**. The clearest current example is `Transform`, which lives in +`apps/web/src/rendering/index.ts`. Rendering happens to consume it — but so do +`@/timeline`, `@/preview`, `@/animation`, `@/text`, and anything else that +positions things on a 2D canvas. It's not "of" rendering; rendering just owns +the file. + +## The test + +If a type can be described without mentioning clips, tracks, effects, layers, +keyframes, or any other product concept — and it has no behavior beyond shape +— it's a **primitive**. The moment a type needs to know what a clip is, it +has crossed into domain territory. + +Primitives have: + +- No domain-specific invariants (a 2D position doesn't care that it's a clip's +position; it's just `{ x, y }`). +- No dependencies on other parts of the app — they're leaves. +- Multiple unrelated consumers across domains. +- A name that would make sense in any 2D editor / video tool / graphics lib. + +Domains, in contrast, can name things that only make sense given the rest of +the product (`TimelineElement`, `Effect`, `GraphicDefinition`, `MediaAsset`). + +## Why it matters + +When a primitive lives in a domain folder, every other domain that consumes it +takes a misleading dependency — `@/timeline` ends up importing from +`@/rendering` not because timeline needs rendering, but because that's where +`Transform` happens to sit. The dependency graph lies, and pieces that should +move freely become anchored to the wrong layer. + +## The refactor + +Move primitives out of domain folders into a primitives location (somewhere +like `apps/web/src/primitives/`, or split by concern — `geometry/`, `time/`, +`color/`, etc.). Whatever the bucket, the rule is "no product concepts, no +behavior, no upward dependencies". + +Don't bulk-move. Each move is deliberate — the right destination depends on +what other primitives already exist and what naming convention has emerged. + +## Side effects to watch for + +Files often end up parked next to misplaced primitives because they had nowhere +better to live. Example: `apps/web/src/rendering/animation-values.ts` exists +only because `Transform` lives next door. Once `Transform` moves to a primitive +location, that file collapses back into `apps/web/src/animation/values.ts` +alongside the other resolve-at-time helpers — there's no remaining reason to +split them. + +When moving a primitive, look at what *else* in its current folder only exists +because of that primitive. Those usually want to move too (or merge somewhere +else once the anchor is gone). \ No newline at end of file