@m0saic/knowledge 0.2.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 +21 -0
- package/README.md +71 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +7 -0
- package/docs/README.md +60 -0
- package/docs/file-formats/m0-iteration-protocol.md +120 -0
- package/docs/file-formats/m0p-and-custom-field.md +195 -0
- package/docs/handbook/README.md +27 -0
- package/docs/handbook/composition-arithmetic.md +278 -0
- package/docs/handbook/dsl-complexity.md +75 -0
- package/docs/handbook/dsl-rules.md +367 -0
- package/docs/handbook/feasibility-precision-quantization.md +591 -0
- package/docs/handbook/m0-construction-methods.md +201 -0
- package/docs/handbook/precision-tiers.md +84 -0
- package/docs/m0saic-thesis.md +95 -0
- package/docs/runtime/README.md +17 -0
- package/docs/runtime/cli-usage.md +372 -0
- package/docs/runtime/ffmpeg-expression-limits.md +117 -0
- package/docs/runtime/reduce-to-one.md +96 -0
- package/docs/skills/README.md +40 -0
- package/docs/skills/axis-and-geometry.md +103 -0
- package/docs/skills/dsl-stdlib-method-catalog.md +7 -0
- package/docs/skills/identity.md +123 -0
- package/docs/skills/labels-and-masks.md +170 -0
- package/docs/skills/m0saic-string-generation.md +251 -0
- package/docs/skills/more-atoms-not-bigger-atoms.md +77 -0
- package/docs/skills/overlay-semantics.md +194 -0
- package/docs/skills/parse-apis.md +79 -0
- package/docs/skills/passthrough-semantics.md +136 -0
- package/docs/skills/structural-construction.md +86 -0
- package/docs/skills/text-in-templates.md +126 -0
- package/docs/skills/zero-overlay-analysis.md +87 -0
- package/docs/templates/README.md +65 -0
- package/docs/templates/capability-templates.md +72 -0
- package/docs/templates/construction-strategy.md +329 -0
- package/docs/templates/data-pipeline.md +324 -0
- package/docs/templates/emission-patterns.md +130 -0
- package/docs/templates/geometry-recipes.md +248 -0
- package/docs/templates/layout-contract.md +168 -0
- package/docs/templates/output-resolution-tree.md +202 -0
- package/docs/templates/patterns/case-study-lessons.md +69 -0
- package/docs/templates/patterns/perf-authoring-rules.md +100 -0
- package/docs/templates/patterns/primitive-extraction-pattern.md +103 -0
- package/docs/templates/philosophy-and-contract.md +310 -0
- package/docs/templates/recursion-nested-rendering.md +138 -0
- package/docs/templates/reference/grid.md +104 -0
- package/docs/templates/reference/json-prop-type.md +169 -0
- package/docs/templates/reference/mosaic-color.md +81 -0
- package/docs/templates/reference/mosaic-placement-props.md +103 -0
- package/docs/templates/reference/prop-bindings.md +203 -0
- package/docs/templates/reference/template-flags.md +205 -0
- package/docs/templates/render-lifecycle.md +117 -0
- package/docs/templates/rendering-model-contract.md +392 -0
- package/docs/templates/standalone-pack-authoring.md +233 -0
- package/docs/templates/theming.md +81 -0
- package/docs/templates/ui-controls.md +150 -0
- package/package.json +37 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Theming — design tokens over the upstream channel
|
|
2
|
+
|
|
3
|
+
> Templates layer. How a template consumes (or produces) shared design tokens.
|
|
4
|
+
> Landed in F4 (`charts/stat-card/v1` is the first consumer). The token
|
|
5
|
+
> plumbing lives in `@m0saic/template-utils` (`src/theming/`); the contract in
|
|
6
|
+
> `@m0saic/types`; the reference producer at `@m0saic/theming/v1`.
|
|
7
|
+
|
|
8
|
+
Theming lets a **producer** template publish design tokens that any **consumer**
|
|
9
|
+
template overlays onto its own constants. Producer and consumer agree ONLY on a
|
|
10
|
+
token SHAPE + an alias — never on a specific producer — so any conforming
|
|
11
|
+
producer is swappable under any consumer.
|
|
12
|
+
|
|
13
|
+
## The three homes
|
|
14
|
+
|
|
15
|
+
- **Contract** — `@m0saic/types`: `MosaicThemeTokens` (21 role-based keys:
|
|
16
|
+
`surface*` / `text*` / `accent*` / `positive` / `negative` / `grid*` /
|
|
17
|
+
`axis*` / `radius` / `dataPalette`), `MosaicThemeMode`
|
|
18
|
+
(`dark` | `light` | `high-contrast`), `MOSAIC_THEME_ALIAS` (`"theme"`),
|
|
19
|
+
`MOSAIC_THEME_TOKEN_KEYS`. Keys are ADDITIVE-ONLY (renames force a
|
|
20
|
+
re-checkpoint).
|
|
21
|
+
- **Plumbing** — `@m0saic/template-utils` (`src/theming/`): `publishTheme`,
|
|
22
|
+
`readTheme`, `applyTheme` (sync — ctx-read + per-key overlay), and
|
|
23
|
+
`resolveThemeTokens` (async — find-or-seed) + `ThemeSourceConfig`.
|
|
24
|
+
- **Reference producer** — `@m0saic/theming/v1`: a layered system —
|
|
25
|
+
`M0SAIC_BRAND` (reference: navy + orange) → semantic `ThemeTokens` →
|
|
26
|
+
`THEME_PRESETS` / `resolveTheme(mode)`. Publishes via `publishTheme`;
|
|
27
|
+
`preview:false` emits a data-only doc valid only as an `intermediate`
|
|
28
|
+
pipeline step.
|
|
29
|
+
|
|
30
|
+
## Consumer authoring pattern (the copyable recipe)
|
|
31
|
+
|
|
32
|
+
1. Declare your current constants as a full `MosaicThemeTokens` `LOCAL_THEME`
|
|
33
|
+
(used keys carry the current hexes VERBATIM → byte-identity; unused keys are
|
|
34
|
+
defensible locals, never read). Do NOT import the producer's `resolveTheme`
|
|
35
|
+
into the fallback — coupling the fallback to a producer preset risks a drift
|
|
36
|
+
that breaks byte-identity.
|
|
37
|
+
2. Add an opt-in `theme?: ThemeSourceConfig` prop
|
|
38
|
+
(`{ slug?, namespace?, props?, forceFetch? }`).
|
|
39
|
+
3. In `render`: `const theme = await resolveThemeTokens(LOCAL_THEME, ctx,
|
|
40
|
+
props.theme);` then read `theme.<key>` everywhere a constant was read.
|
|
41
|
+
|
|
42
|
+
## The resolution model — `theme = ctx[namespace] ?? seed(slug) ?? fallback`
|
|
43
|
+
|
|
44
|
+
The same one call serves both roles a template can play:
|
|
45
|
+
|
|
46
|
+
- **Vanilla** (no config, or a config without a `slug`): reads the default
|
|
47
|
+
`"theme"` namespace off ctx, else `LOCAL_THEME`. Un-themed → byte-identical.
|
|
48
|
+
- **Child** (nested under a producer/pipeline that published tokens): finds them
|
|
49
|
+
on `ctx.upstreamData[namespace]` → uses them. No `slug` needed.
|
|
50
|
+
- **Head** (top-level, nothing upstream, `slug` configured): INVOKES the producer
|
|
51
|
+
(`renderNestedTemplate` — a BUILD-TIME doc build, NOT ffmpeg) to seed the
|
|
52
|
+
tokens, then reads them.
|
|
53
|
+
- **`forceFetch`**: re-seed via `slug` even when the namespace is populated
|
|
54
|
+
(escape hatch for a namespace collision; the real fix is usually higher in the
|
|
55
|
+
chain).
|
|
56
|
+
|
|
57
|
+
**Swap the theme = swap `props.theme.slug` (or its `props`)** — a data change,
|
|
58
|
+
never consumer code. `applyTheme` is the sync subset (ctx-read + overlay, no
|
|
59
|
+
seeding) for consumers that never self-seed.
|
|
60
|
+
|
|
61
|
+
## Two hard rules
|
|
62
|
+
|
|
63
|
+
- Read via `applyTheme` / `resolveThemeTokens` (which read
|
|
64
|
+
`ctx.upstreamData[alias]` through `getUpstreamBlock`). NEVER hand-read
|
|
65
|
+
`ctx.upstreamVariables` for theme.
|
|
66
|
+
- `LOCAL_THEME`'s used keys = the template's current hexes, so an un-themed,
|
|
67
|
+
un-configured render is byte-identical to pre-theming. Verify with a doc
|
|
68
|
+
snapshot deep-equal.
|
|
69
|
+
|
|
70
|
+
## Pipeline alternative (production path for a chain)
|
|
71
|
+
|
|
72
|
+
To re-skin a whole chain, put the producer as an `intermediate: true` step ahead
|
|
73
|
+
of the consumers:
|
|
74
|
+
`[ @m0saic/theming/v1 preset:dark preview:false → …consumers ]`. The producer
|
|
75
|
+
threads tokens downstream at zero render cost; swapping the step's `preset`
|
|
76
|
+
re-skins everything. Consumers need no `slug` in this mode — they find the tokens
|
|
77
|
+
on ctx as children.
|
|
78
|
+
|
|
79
|
+
Reference consumer: `charts/stat-card/v1` (first `resolveThemeTokens` consumer,
|
|
80
|
+
F4). See also `data-pipeline.md`
|
|
81
|
+
§"Publish channels × read views" for the underlying upstream channel.
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# Template UI controls
|
|
2
|
+
|
|
3
|
+
Templates declare per-prop editor controls via `meta.control` on each
|
|
4
|
+
`MosaicTemplatePropDefinition`. The desktop app's prop-dispatch surfaces read those
|
|
5
|
+
declarations and render the matching widget.
|
|
6
|
+
|
|
7
|
+
⚠️ **If you are adding a new control kind: the dispatch is duplicated across TWO
|
|
8
|
+
surfaces, and a one-surface change silently no-ops on the other.** Update both.
|
|
9
|
+
(There is no `props-control-dispatch.md` yet — the writeup is still an unmerged
|
|
10
|
+
candidate at (internal design history); read
|
|
11
|
+
that for the two surface locations.)
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## The `picker` taxonomy
|
|
16
|
+
|
|
17
|
+
`MosaicPropControl.picker` is a closed union
|
|
18
|
+
(https://github.com/m0saic-project/m0saic-packages/blob/main/packages/types/src/template/template.ts#L186):
|
|
19
|
+
|
|
20
|
+
| Value | Renders | Prop shape |
|
|
21
|
+
|---|---|---|
|
|
22
|
+
| `"file"` | OS file picker | one `type: "media"` prop |
|
|
23
|
+
| `"folder"` | OS folder picker | one `type: "media"` prop |
|
|
24
|
+
| `"time-range"` | Single-range clip modal | **paired** `*StartMs` / `*EndMs` numbers |
|
|
25
|
+
| `"time-ranges"` | Multi-range Clip-Range Studio | **one** `type: "json"` prop |
|
|
26
|
+
| `"cards"` | Image-card option grid | any prop with `control.options` |
|
|
27
|
+
|
|
28
|
+
`"time-range"` and `"time-ranges"` are **both current and both in use** — the plural did
|
|
29
|
+
not supersede the singular. Pick by cardinality:
|
|
30
|
+
|
|
31
|
+
- **One window** out of a source (trim, clip, preview segment) → `"time-range"`.
|
|
32
|
+
Adopters: `media/subtitle-burn/v1`, `language/dual-sub/v1`,
|
|
33
|
+
`media/video_to_png_sequence/v1`.
|
|
34
|
+
- **N windows** (highlight reels, multi-cut) → `"time-ranges"`.
|
|
35
|
+
Adopter: `media/highlights/v1`.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## `"time-range"` — the paired-prop picker
|
|
40
|
+
|
|
41
|
+
Declared on **both** halves of a `<base>StartMs` / `<base>EndMs` numeric pair, with the
|
|
42
|
+
same control block on each:
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
clipStartMs: {
|
|
46
|
+
type: "number",
|
|
47
|
+
required: false,
|
|
48
|
+
meta: {
|
|
49
|
+
control: {
|
|
50
|
+
picker: "time-range",
|
|
51
|
+
videoFromProp: "sourceId", // sibling prop holding the video path
|
|
52
|
+
targetDurationMsFromProp: "duration", // optional — draws a "target band"
|
|
53
|
+
markersProvider: { // optional — semantic timeline ticks
|
|
54
|
+
kind: "subtitles",
|
|
55
|
+
videoFromProp: "sourceId",
|
|
56
|
+
languageFromProp: "languageCode",
|
|
57
|
+
trackIndexFromProp: "trackIndex",
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
ui: { label: "Clip start (ms)" },
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
clipEndMs: { /* mirrors clipStartMs, label "Clip end (ms)" */ },
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**Pairing rule.** The dispatch matches the two halves by name suffix
|
|
67
|
+
(`*StartMs` ↔ `*EndMs`) via `planTimeRangeEntries`
|
|
68
|
+
(the Mosaic Desktop / Web app source (not published)). Both dispatch surfaces
|
|
69
|
+
call that same planner, so pair-detection cannot drift between them.
|
|
70
|
+
|
|
71
|
+
**`{ 0, 0 }` means "full source"** — it is the documented cleared sentinel, not a
|
|
72
|
+
zero-length range. Don't treat it as an empty selection.
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## `"time-ranges"` — the multi-range studio
|
|
77
|
+
|
|
78
|
+
**One** `type: "json"` prop whose value is `Array<MosaicTimeRangeMs>`
|
|
79
|
+
(`{ startMs, endMs, label? }`; integer ms, source-relative, sorted ascending; overlaps
|
|
80
|
+
allowed; `[]` = no selection). No prop pairing — the editor reads and writes the whole
|
|
81
|
+
array in a single `onChange`.
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
clipRanges: {
|
|
85
|
+
type: "json",
|
|
86
|
+
required: false,
|
|
87
|
+
meta: { control: { picker: "time-ranges", videoFromProp: "sourceId" } },
|
|
88
|
+
},
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**Read the value with `parseTimeRangesValue`**
|
|
92
|
+
(https://github.com/m0saic-project/m0saic-packages/blob/main/packages/template-utils/src/media/timeRanges.ts) — never hand-parse. The boundary is
|
|
93
|
+
deliberately permissive (see `reference/json-prop-type.md`), so the value may arrive as a
|
|
94
|
+
parsed array *or* a JSON string.
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## Both pickers are one component underneath
|
|
99
|
+
|
|
100
|
+
The Clip-Range Studio is the single implementation; the singular picker is an adapter
|
|
101
|
+
over it.
|
|
102
|
+
|
|
103
|
+
| Component | Role |
|
|
104
|
+
|---|---|
|
|
105
|
+
| `rangestudio/ClipRangeStudio.tsx` + `ClipRangeStudioModal.tsx` | the studio |
|
|
106
|
+
| `rangestudio/SingleRangeModal.tsx` | single-range adapter — the studio at `maxRanges: 1`, legacy `{startMs, endMs}` in/out |
|
|
107
|
+
| `rangestudio/TimeRangesField.tsx` | the `"time-ranges"` form field, rendered by **both** dispatch chains |
|
|
108
|
+
|
|
109
|
+
> **Historical note:** `TimeRangePickerField.tsx` / `TimeRangePickerModal.tsx` were
|
|
110
|
+
> **deleted** in the Clip-Range Studio rebuild. `SingleRangeModal` is their drop-in
|
|
111
|
+
> replacement with the same public API. Older docs, plans, and candidates that cite
|
|
112
|
+
> those two filenames are stale — the *pattern* they describe survived, the files did
|
|
113
|
+
> not.
|
|
114
|
+
|
|
115
|
+
Consumers of `SingleRangeModal` today: `PropsSchemaForm`, `MakePage`, and
|
|
116
|
+
`compose/sources/MediaSourceEditor`.
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## Marker providers (declarative)
|
|
121
|
+
|
|
122
|
+
`markersProvider` asks the editor to overlay semantic landmarks on the timeline. The
|
|
123
|
+
union currently has **exactly one kind**:
|
|
124
|
+
|
|
125
|
+
- **`kind: "subtitles"`** — extracts cues for the resolved language/track and draws them
|
|
126
|
+
as ticks with inline labels. Chain: `subtitles:extract` IPC
|
|
127
|
+
(the Mosaic Desktop / Web app source (not published)) → cue hook → `markers` on the studio. The cues are
|
|
128
|
+
also painted as a live caption overlay on the preview `<video>`, because HTML5 video
|
|
129
|
+
cannot surface embedded MKV subtitle tracks.
|
|
130
|
+
|
|
131
|
+
**There is no fallback path.** A `kind` the dispatch doesn't recognize is *silently
|
|
132
|
+
ignored* — no warning, no error, the markers just never appear. Adding a kind
|
|
133
|
+
(`scene-cuts`, `audio-peaks`, `chapters`) means expanding the union **and** adding the
|
|
134
|
+
IPC **and** the hook **and** the dispatch wiring, in lockstep.
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## Companion props and gotchas
|
|
139
|
+
|
|
140
|
+
**Loop mode.** A time-range pairs naturally with a loop-mode enum when the selected
|
|
141
|
+
segment can be shorter or longer than the render duration. Subtitle-burn's
|
|
142
|
+
`clipLoopMode: "cut" | "loop" | "freeze"` is the reference — a plain enum via
|
|
143
|
+
`meta.control.options`, threaded into `MosaicPlaybackProps.loopMode` at render time.
|
|
144
|
+
|
|
145
|
+
**Cue-offset trap on clipped templates.** When a template offsets cues to output-time
|
|
146
|
+
(subtitle-burn's `offsetCuesToOutput(rawCues, clipStartMs, clipEndMs, durationMs)`), the
|
|
147
|
+
picked range must actually overlap where cues exist — otherwise the render is silently
|
|
148
|
+
subtitle-free. The marker overlay is the editor-side mitigation: users see where cues
|
|
149
|
+
live and aim accordingly. Surface this on any cue-bearing template rather than burying
|
|
150
|
+
it.
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@m0saic/knowledge",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"description": "The m0saic knowledge base for agents and authors: the m0 handbook, the engine mental models, and the template-authoring contract, as plain Markdown. Point your coding agent at README.md before it writes a template.",
|
|
7
|
+
"main": "dist/index.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "node test/docs.test.mjs --build",
|
|
11
|
+
"test": "node --test test/docs.test.mjs"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"m0saic",
|
|
15
|
+
"m0",
|
|
16
|
+
"templates",
|
|
17
|
+
"knowledge-base",
|
|
18
|
+
"agents",
|
|
19
|
+
"AGENTS.md"
|
|
20
|
+
],
|
|
21
|
+
"author": "m0saic LLC",
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "git+https://github.com/m0saic-project/m0saic-packages.git",
|
|
25
|
+
"directory": "packages/knowledge"
|
|
26
|
+
},
|
|
27
|
+
"homepage": "https://github.com/m0saic-project/m0saic-packages/tree/main/packages/knowledge#readme",
|
|
28
|
+
"bugs": {
|
|
29
|
+
"url": "https://github.com/m0saic-project/m0saic-packages/issues"
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"dist",
|
|
33
|
+
"docs",
|
|
34
|
+
"LICENSE",
|
|
35
|
+
"README.md"
|
|
36
|
+
]
|
|
37
|
+
}
|