m0saic 0.2.1 → 0.3.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.
Files changed (292) hide show
  1. package/LICENSE +22 -7
  2. package/README.md +23 -5
  3. package/dist/browseE2e.js +1 -1
  4. package/dist/connectionsFromEnv.js +1 -1
  5. package/dist/e2eTemplateVariants.js +1 -1
  6. package/dist/frontDoor.js +1 -1
  7. package/dist/index.js +1 -1
  8. package/dist/inlineDsl.js +1 -1
  9. package/dist/mcp/bridgeClient.js +1 -0
  10. package/dist/mcp/server.js +1 -0
  11. package/dist/mcp/tools.js +1 -0
  12. package/dist/mosaicxRunner.js +1 -1
  13. package/dist/outputPattern.js +1 -1
  14. package/dist/showcaseFeed.js +1 -1
  15. package/dist/templateDoctor.js +1 -1
  16. package/dist/utils/checkFeasibility.js +1 -1
  17. package/dist/utils/collectRenderErrors.js +1 -1
  18. package/dist/utils/enrichImageAlphaFromDoc.js +1 -1
  19. package/dist/utils/ensureFfmpeg.js +1 -1
  20. package/dist/utils/extractLayoutMeta.js +1 -1
  21. package/dist/utils/failureHints.js +1 -1
  22. package/dist/utils/ffmpegProbe.js +1 -1
  23. package/dist/utils/formatM0saicForCli.js +1 -1
  24. package/dist/utils/hashFile.js +1 -1
  25. package/dist/utils/helpGroups.js +1 -1
  26. package/dist/utils/installContext.js +1 -0
  27. package/dist/utils/invocation.js +1 -1
  28. package/dist/utils/licenseActivation.js +1 -0
  29. package/dist/utils/licenseActivationWorker.js +1 -0
  30. package/dist/utils/mosaicSpinner.js +1 -1
  31. package/dist/utils/parseDimensions.js +1 -1
  32. package/dist/utils/pathInfo.js +1 -1
  33. package/dist/utils/readJsonArg.js +1 -1
  34. package/dist/utils/renderOutcome.js +1 -1
  35. package/dist/utils/renderReport.js +1 -1
  36. package/dist/utils/renderSignals.js +1 -1
  37. package/dist/utils/renderWorkspace.js +1 -1
  38. package/dist/utils/reportOutputFormat.js +1 -0
  39. package/dist/utils/setupFfmpeg.js +1 -1
  40. package/dist/utils/telemetry.js +1 -1
  41. package/dist/utils/telemetryFlushWorker.js +1 -1
  42. package/dist/utils/telemetryUpstream.js +1 -1
  43. package/dist/utils/telemetryUsage.js +1 -1
  44. package/dist/utils/toolchainConfig.js +1 -1
  45. package/dist/utils/tutorialDuration.js +1 -1
  46. package/dist/utils/updateCheck.js +1 -1
  47. package/dist/utils/updateCheckWorker.js +1 -1
  48. package/dist/utils/validateSourceCounts.js +1 -1
  49. package/dist/utils/versions.js +1 -1
  50. package/dist/webCustomizeLink.js +1 -1
  51. package/node_modules/@m0saic/community-m/NOTICE +9 -0
  52. package/node_modules/@m0saic/community-m/release.json +2 -2
  53. package/node_modules/@m0saic/core/dist/core/buildChildMosaicSource.js +1 -1
  54. package/node_modules/@m0saic/core/dist/core/buildChunkCommands.js +1 -1
  55. package/node_modules/@m0saic/core/dist/core/buildEncodeCommands.js +1 -1
  56. package/node_modules/@m0saic/core/dist/core/buildLavfiSource.js +1 -1
  57. package/node_modules/@m0saic/core/dist/core/buildMediaSource.js +1 -1
  58. package/node_modules/@m0saic/core/dist/core/buildMosaicNode.js +1 -1
  59. package/node_modules/@m0saic/core/dist/core/buildMosaicPlanFromFile.js +1 -1
  60. package/node_modules/@m0saic/core/dist/core/buildSvgTextSource.js +1 -1
  61. package/node_modules/@m0saic/core/dist/core/buildTextRenderCommand.js +1 -1
  62. package/node_modules/@m0saic/core/dist/core/collectRefTargets.js +1 -1
  63. package/node_modules/@m0saic/core/dist/core/index.js +1 -1
  64. package/node_modules/@m0saic/core/dist/core/maskCacheDir.js +1 -1
  65. package/node_modules/@m0saic/core/dist/core/maskWorkerBridge.js +1 -1
  66. package/node_modules/@m0saic/core/dist/core/playbackPlaySpeed.js +1 -1
  67. package/node_modules/@m0saic/core/dist/core/prepareProps.js +1 -1
  68. package/node_modules/@m0saic/core/dist/core/primaryOutput.js +1 -1
  69. package/node_modules/@m0saic/core/dist/core/rasterizeMaskPng.js +1 -1
  70. package/node_modules/@m0saic/core/dist/core/rasterizeSvgMediaPng.js +1 -1
  71. package/node_modules/@m0saic/core/dist/core/refTargetTap.js +1 -1
  72. package/node_modules/@m0saic/core/dist/core/resolveMasks.js +1 -1
  73. package/node_modules/@m0saic/core/dist/core/resolveMasksSync.js +1 -1
  74. package/node_modules/@m0saic/core/dist/core/resolveStrokeRingsSync.js +1 -1
  75. package/node_modules/@m0saic/core/dist/core/roundedRectMask.js +1 -1
  76. package/node_modules/@m0saic/core/dist/core/strokeRing.js +1 -1
  77. package/node_modules/@m0saic/core/dist/core/svgRaster.js +1 -1
  78. package/node_modules/@m0saic/core/dist/defaults.js +1 -1
  79. package/node_modules/@m0saic/core/dist/ffmpeg/backgroundImageInput.js +1 -1
  80. package/node_modules/@m0saic/core/dist/ffmpeg/bufferGuard.js +1 -1
  81. package/node_modules/@m0saic/core/dist/ffmpeg/ffmpegCommands.js +1 -1
  82. package/node_modules/@m0saic/core/dist/ffmpeg/filters/applyBackdropBlur.js +1 -1
  83. package/node_modules/@m0saic/core/dist/ffmpeg/filters/applyBlur.js +1 -1
  84. package/node_modules/@m0saic/core/dist/ffmpeg/filters/applyBorderRadius.js +1 -1
  85. package/node_modules/@m0saic/core/dist/ffmpeg/filters/applyCamera.js +1 -1
  86. package/node_modules/@m0saic/core/dist/ffmpeg/filters/applyChromaKey.js +1 -1
  87. package/node_modules/@m0saic/core/dist/ffmpeg/filters/applyFade.js +1 -1
  88. package/node_modules/@m0saic/core/dist/ffmpeg/filters/applyGrade.js +1 -1
  89. package/node_modules/@m0saic/core/dist/ffmpeg/filters/applyMask.js +1 -1
  90. package/node_modules/@m0saic/core/dist/ffmpeg/filters/applyNoise.js +1 -1
  91. package/node_modules/@m0saic/core/dist/ffmpeg/filters/applyPixelize.js +1 -1
  92. package/node_modules/@m0saic/core/dist/ffmpeg/filters/applyRotate.js +1 -1
  93. package/node_modules/@m0saic/core/dist/ffmpeg/filters/applyStroke.js +1 -1
  94. package/node_modules/@m0saic/core/dist/ffmpeg/filters/applyTileEffects.js +1 -1
  95. package/node_modules/@m0saic/core/dist/ffmpeg/filters/coverCrop.js +1 -1
  96. package/node_modules/@m0saic/core/dist/ffmpeg/filters/index.js +1 -1
  97. package/node_modules/@m0saic/core/dist/ffmpeg/filters/sourceRectCrop.js +1 -1
  98. package/node_modules/@m0saic/core/dist/ffmpeg/gridLowering.js +1 -1
  99. package/node_modules/@m0saic/core/dist/ffmpeg/index.js +1 -1
  100. package/node_modules/@m0saic/core/dist/ffmpeg/splitAvMux.js +1 -1
  101. package/node_modules/@m0saic/core/dist/ffmpeg/threadGuard.js +1 -1
  102. package/node_modules/@m0saic/core/dist/flatten/index.js +1 -1
  103. package/node_modules/@m0saic/core/dist/fs/index.js +1 -1
  104. package/node_modules/@m0saic/core/dist/fs/tempWorkspace.js +1 -1
  105. package/node_modules/@m0saic/core/dist/index.js +1 -1
  106. package/node_modules/@m0saic/core/dist/media/buildAssetManifestFromInputs.js +1 -1
  107. package/node_modules/@m0saic/core/dist/media/buildMediaRegistryFromInput.js +1 -1
  108. package/node_modules/@m0saic/core/dist/media/collectMediaInputsFromInvocationProps.js +1 -1
  109. package/node_modules/@m0saic/core/dist/media/collectMediaInputsFromMosaicRenderableFile.js +1 -1
  110. package/node_modules/@m0saic/core/dist/media/collectMediaInputsFromProps.js +1 -1
  111. package/node_modules/@m0saic/core/dist/media/index.js +1 -1
  112. package/node_modules/@m0saic/core/dist/media/internalMintAsset.js +1 -1
  113. package/node_modules/@m0saic/core/dist/media/remoteUrl.js +1 -1
  114. package/node_modules/@m0saic/core/dist/media/stageUnsafeFilenames.js +1 -1
  115. package/node_modules/@m0saic/core/dist/media/types.js +1 -1
  116. package/node_modules/@m0saic/core/dist/output/index.js +1 -1
  117. package/node_modules/@m0saic/core/dist/output/resolveOutputFormat.js +1 -1
  118. package/node_modules/@m0saic/core/dist/output/types.js +1 -1
  119. package/node_modules/@m0saic/core/dist/probe/cellLuminanceProbe.js +1 -1
  120. package/node_modules/@m0saic/core/dist/probe/extractSubtitleCues.js +1 -1
  121. package/node_modules/@m0saic/core/dist/probe/helpers.js +1 -1
  122. package/node_modules/@m0saic/core/dist/probe/index.js +1 -1
  123. package/node_modules/@m0saic/core/dist/probe/luminanceProbe.js +1 -1
  124. package/node_modules/@m0saic/core/dist/probe/probeMedia.js +1 -1
  125. package/node_modules/@m0saic/core/dist/probe/runFFprobe.js +1 -1
  126. package/node_modules/@m0saic/core/dist/probe/types.js +1 -1
  127. package/node_modules/@m0saic/core/dist/runtime/engineRedaction.js +1 -1
  128. package/node_modules/@m0saic/core/dist/runtime/ffmpegFailure.js +1 -1
  129. package/node_modules/@m0saic/core/dist/runtime/filterPreflight.js +1 -1
  130. package/node_modules/@m0saic/core/dist/runtime/hashFile.js +1 -1
  131. package/node_modules/@m0saic/core/dist/runtime/index.js +1 -1
  132. package/node_modules/@m0saic/core/dist/runtime/pathInfo.js +1 -1
  133. package/node_modules/@m0saic/core/dist/runtime/perfHeatmap.js +1 -1
  134. package/node_modules/@m0saic/core/dist/runtime/perfReport.js +1 -1
  135. package/node_modules/@m0saic/core/dist/runtime/pipelineM0p.js +1 -1
  136. package/node_modules/@m0saic/core/dist/runtime/renderCostModel.constants.js +1 -1
  137. package/node_modules/@m0saic/core/dist/runtime/renderCostModel.js +1 -1
  138. package/node_modules/@m0saic/core/dist/runtime/renderReport.js +1 -1
  139. package/node_modules/@m0saic/core/dist/runtime/renderSidecars.js +1 -1
  140. package/node_modules/@m0saic/core/dist/runtime/resolveMosaicx.js +1 -1
  141. package/node_modules/@m0saic/core/dist/runtime/runPlan.js +1 -1
  142. package/node_modules/@m0saic/core/dist/runtime/types.js +1 -1
  143. package/node_modules/@m0saic/core/dist/runtime/upstream.js +1 -1
  144. package/node_modules/@m0saic/core/dist/runtime/writeSidecars.js +1 -1
  145. package/node_modules/@m0saic/core/dist/types/chunk.js +1 -1
  146. package/node_modules/@m0saic/core/dist/types/index.js +1 -1
  147. package/node_modules/@m0saic/core/dist/types/mosaic-plan.js +1 -1
  148. package/node_modules/@m0saic/core/dist/utils/assertTiming.js +1 -1
  149. package/node_modules/@m0saic/core/dist/utils/command.js +1 -1
  150. package/node_modules/@m0saic/core/dist/utils/createEngineContext.js +1 -1
  151. package/node_modules/@m0saic/core/dist/utils/createTemplateRenderCache.js +1 -1
  152. package/node_modules/@m0saic/core/dist/utils/ffmpegColor.js +1 -1
  153. package/node_modules/@m0saic/core/dist/utils/formatDuration.js +1 -1
  154. package/node_modules/@m0saic/core/dist/utils/fsSafeId.js +1 -1
  155. package/node_modules/@m0saic/core/dist/utils/index.js +1 -1
  156. package/node_modules/@m0saic/core/dist/utils/lowerRenderableToMosaicDocument.js +1 -1
  157. package/node_modules/@m0saic/core/dist/utils/movSafeCodec.js +1 -1
  158. package/node_modules/@m0saic/core/dist/utils/resolveBoxFrac.js +1 -1
  159. package/node_modules/@m0saic/core/dist/validate/index.js +1 -1
  160. package/node_modules/@m0saic/core/scripts/mask-rasterize-core.js +1 -1
  161. package/node_modules/@m0saic/core/scripts/mask-rasterize-worker.js +1 -1
  162. package/node_modules/@m0saic/core/scripts/mask-worker-thread.js +1 -1
  163. package/node_modules/@m0saic/dictionary/NOTICE +9 -0
  164. package/node_modules/@m0saic/dictionary/README.md +315 -0
  165. package/node_modules/@m0saic/dictionary/package.json +1 -1
  166. package/node_modules/@m0saic/dsl/package.json +1 -1
  167. package/node_modules/@m0saic/dsl-file-formats/dist/cjs/agent.js +6 -0
  168. package/node_modules/@m0saic/dsl-file-formats/dist/cjs/m0/parseM0File.js +1 -1
  169. package/node_modules/@m0saic/dsl-file-formats/dist/cjs/m0/serializeM0File.js +2 -2
  170. package/node_modules/@m0saic/dsl-file-formats/dist/cjs/m0c/m0cFile.js +3 -3
  171. package/node_modules/@m0saic/dsl-file-formats/dist/cjs/types.js +1 -1
  172. package/node_modules/@m0saic/dsl-file-formats/package.json +1 -1
  173. package/node_modules/@m0saic/dsl-stdlib/dist/cjs/builders/bakeM0cInsets.js +1 -0
  174. package/node_modules/@m0saic/dsl-stdlib/dist/cjs/builders/index.js +1 -1
  175. package/node_modules/@m0saic/dsl-stdlib/package.json +1 -1
  176. package/node_modules/@m0saic/knowledge/LICENSE +21 -0
  177. package/node_modules/@m0saic/knowledge/README.md +71 -0
  178. package/node_modules/@m0saic/knowledge/dist/index.js +1 -0
  179. package/node_modules/@m0saic/knowledge/docs/README.md +60 -0
  180. package/node_modules/@m0saic/knowledge/docs/file-formats/m0-iteration-protocol.md +120 -0
  181. package/node_modules/@m0saic/knowledge/docs/file-formats/m0p-and-custom-field.md +195 -0
  182. package/node_modules/@m0saic/knowledge/docs/handbook/README.md +27 -0
  183. package/node_modules/@m0saic/knowledge/docs/handbook/composition-arithmetic.md +278 -0
  184. package/node_modules/@m0saic/knowledge/docs/handbook/dsl-complexity.md +75 -0
  185. package/node_modules/@m0saic/knowledge/docs/handbook/dsl-rules.md +367 -0
  186. package/node_modules/@m0saic/knowledge/docs/handbook/feasibility-precision-quantization.md +591 -0
  187. package/node_modules/@m0saic/knowledge/docs/handbook/m0-construction-methods.md +201 -0
  188. package/node_modules/@m0saic/knowledge/docs/handbook/precision-tiers.md +84 -0
  189. package/node_modules/@m0saic/knowledge/docs/m0saic-thesis.md +95 -0
  190. package/node_modules/@m0saic/knowledge/docs/runtime/README.md +17 -0
  191. package/node_modules/@m0saic/knowledge/docs/runtime/cli-usage.md +447 -0
  192. package/node_modules/@m0saic/knowledge/docs/runtime/ffmpeg-expression-limits.md +117 -0
  193. package/node_modules/@m0saic/knowledge/docs/runtime/reduce-to-one.md +96 -0
  194. package/node_modules/@m0saic/knowledge/docs/skills/README.md +40 -0
  195. package/node_modules/@m0saic/knowledge/docs/skills/axis-and-geometry.md +103 -0
  196. package/node_modules/@m0saic/knowledge/docs/skills/dsl-stdlib-method-catalog.md +7 -0
  197. package/node_modules/@m0saic/knowledge/docs/skills/identity.md +123 -0
  198. package/node_modules/@m0saic/knowledge/docs/skills/labels-and-masks.md +170 -0
  199. package/node_modules/@m0saic/knowledge/docs/skills/m0saic-string-generation.md +251 -0
  200. package/node_modules/@m0saic/knowledge/docs/skills/more-atoms-not-bigger-atoms.md +77 -0
  201. package/node_modules/@m0saic/knowledge/docs/skills/overlay-semantics.md +194 -0
  202. package/node_modules/@m0saic/knowledge/docs/skills/parse-apis.md +79 -0
  203. package/node_modules/@m0saic/knowledge/docs/skills/passthrough-semantics.md +136 -0
  204. package/node_modules/@m0saic/knowledge/docs/skills/structural-construction.md +86 -0
  205. package/node_modules/@m0saic/knowledge/docs/skills/text-in-templates.md +126 -0
  206. package/node_modules/@m0saic/knowledge/docs/skills/zero-overlay-analysis.md +87 -0
  207. package/node_modules/@m0saic/knowledge/docs/templates/README.md +65 -0
  208. package/node_modules/@m0saic/knowledge/docs/templates/capability-templates.md +72 -0
  209. package/node_modules/@m0saic/knowledge/docs/templates/construction-strategy.md +329 -0
  210. package/node_modules/@m0saic/knowledge/docs/templates/data-pipeline.md +324 -0
  211. package/node_modules/@m0saic/knowledge/docs/templates/emission-patterns.md +130 -0
  212. package/node_modules/@m0saic/knowledge/docs/templates/geometry-recipes.md +248 -0
  213. package/node_modules/@m0saic/knowledge/docs/templates/layout-contract.md +168 -0
  214. package/node_modules/@m0saic/knowledge/docs/templates/output-resolution-tree.md +202 -0
  215. package/node_modules/@m0saic/knowledge/docs/templates/patterns/case-study-lessons.md +69 -0
  216. package/node_modules/@m0saic/knowledge/docs/templates/patterns/perf-authoring-rules.md +100 -0
  217. package/node_modules/@m0saic/knowledge/docs/templates/patterns/primitive-extraction-pattern.md +103 -0
  218. package/node_modules/@m0saic/knowledge/docs/templates/philosophy-and-contract.md +310 -0
  219. package/node_modules/@m0saic/knowledge/docs/templates/recursion-nested-rendering.md +154 -0
  220. package/node_modules/@m0saic/knowledge/docs/templates/reference/grid.md +104 -0
  221. package/node_modules/@m0saic/knowledge/docs/templates/reference/json-prop-type.md +169 -0
  222. package/node_modules/@m0saic/knowledge/docs/templates/reference/mosaic-color.md +81 -0
  223. package/node_modules/@m0saic/knowledge/docs/templates/reference/mosaic-placement-props.md +103 -0
  224. package/node_modules/@m0saic/knowledge/docs/templates/reference/prop-bindings.md +324 -0
  225. package/node_modules/@m0saic/knowledge/docs/templates/reference/template-flags.md +224 -0
  226. package/node_modules/@m0saic/knowledge/docs/templates/render-lifecycle.md +117 -0
  227. package/node_modules/@m0saic/knowledge/docs/templates/rendering-model-contract.md +392 -0
  228. package/node_modules/@m0saic/knowledge/docs/templates/standalone-pack-authoring.md +299 -0
  229. package/node_modules/@m0saic/knowledge/docs/templates/theming.md +81 -0
  230. package/node_modules/@m0saic/knowledge/docs/templates/ui-controls.md +150 -0
  231. package/node_modules/@m0saic/knowledge/package.json +6 -0
  232. package/node_modules/@m0saic/momo-types/README.md +109 -0
  233. package/node_modules/@m0saic/momo-types/dist/agent.js +1 -6
  234. package/node_modules/@m0saic/momo-types/dist/context.js +1 -1
  235. package/node_modules/@m0saic/momo-types/package.json +1 -1
  236. package/node_modules/@m0saic/platform/README.md +3 -0
  237. package/node_modules/@m0saic/platform/dist/cjs/index.js +1 -1
  238. package/node_modules/@m0saic/platform/dist/cjs/mosaic/outputKind/outputKind.js +1 -1
  239. package/node_modules/@m0saic/platform/dist/cjs/mosaic/propBindings/index.js +1 -1
  240. package/node_modules/@m0saic/platform/dist/cjs/mosaic/propBindings/propBindings.js +1 -1
  241. package/node_modules/@m0saic/platform/dist/cjs/mosaic/validate/validateSources.js +1 -1
  242. package/node_modules/@m0saic/platform/dist/cjs/packages/mosaicPackages.js +1 -0
  243. package/node_modules/@m0saic/platform/dist/cjs/paths/m0saicRoot.js +1 -1
  244. package/node_modules/@m0saic/platform/dist/cjs/telemetry/lifecycle.js +1 -1
  245. package/node_modules/@m0saic/platform/dist/cjs/telemetry/preview.js +1 -1
  246. package/node_modules/@m0saic/platform/dist/cjs/telemetry/sender.js +1 -1
  247. package/node_modules/@m0saic/platform/dist/cjs/telemetry/usageRecorder.js +1 -1
  248. package/node_modules/@m0saic/platform/dist/cjs/telemetry/usageStore.js +3 -3
  249. package/node_modules/@m0saic/platform/dist/cjs/toolchain/ffmpeg/baseline.json +25 -97
  250. package/node_modules/@m0saic/platform/dist/cjs/toolchain/ffmpeg/index.js +1 -1
  251. package/node_modules/@m0saic/platform/dist/cjs/toolchain/ffmpeg/install.js +2 -2
  252. package/node_modules/@m0saic/platform/dist/cjs/toolchain/goldenFfmpeg.js +6 -6
  253. package/node_modules/@m0saic/platform/package.json +1 -1
  254. package/node_modules/@m0saic/product/dist/communityRelease.js +1 -1
  255. package/node_modules/@m0saic/product/dist/freeTierLicense.js +1 -1
  256. package/node_modules/@m0saic/product/dist/index.js +1 -1
  257. package/node_modules/@m0saic/product/dist/licenseActivationNotice.js +1 -0
  258. package/node_modules/@m0saic/product/dist/licenseFile.js +1 -0
  259. package/node_modules/@m0saic/product/dist/licenseToken.js +1 -1
  260. package/node_modules/@m0saic/product/dist/makeScratchPath.js +1 -0
  261. package/node_modules/@m0saic/product/dist/postRenderWrapper.js +1 -1
  262. package/node_modules/@m0saic/product/dist/publicKeys.js +1 -1
  263. package/node_modules/@m0saic/product/dist/revokedKeys.js +1 -1
  264. package/node_modules/@m0saic/product/dist/upstreamDefaults.js +1 -1
  265. package/node_modules/@m0saic/product/dist/workspaceScaffold.js +1 -0
  266. package/node_modules/@m0saic/template-utils/dist/brand/hello-world/helloWorld.js +1 -1
  267. package/node_modules/@m0saic/template-utils/dist/geometry-contract/index.js +1 -1
  268. package/node_modules/@m0saic/template-utils/dist/geometry-contract/layoutConstraint.js +2 -2
  269. package/node_modules/@m0saic/template-utils/dist/m0saic/loadSession.js +1 -1
  270. package/node_modules/@m0saic/template-utils/dist/render/createDesignContext.js +1 -1
  271. package/node_modules/@m0saic/template-utils/dist/sources/makeErrorMosaic.js +2 -2
  272. package/node_modules/@m0saic/template-utils/dist/sources/svgTextSource.js +1 -1
  273. package/node_modules/@m0saic/template-utils/dist/template/auditRenderedTemplate.js +5 -5
  274. package/node_modules/@m0saic/template-utils/dist/template/templateConventions.js +3 -3
  275. package/node_modules/@m0saic/template-utils/dist/template/validateTemplateProps.js +1 -1
  276. package/node_modules/@m0saic/template-utils/dist/text/fitText.js +6 -6
  277. package/node_modules/@m0saic/template-utils/package.json +1 -1
  278. package/node_modules/@m0saic/templates/NOTICE +9 -0
  279. package/node_modules/@m0saic/templates/dist/m0saic/media/blur-regions/v1/tutorial.js +1 -1
  280. package/node_modules/@m0saic/templates/package.json +1 -1
  281. package/node_modules/@m0saic/templates-advanced/NOTICE +9 -0
  282. package/node_modules/@m0saic/text/package.json +1 -1
  283. package/node_modules/@m0saic/types/dist/analytics/consent.js +1 -1
  284. package/node_modules/@m0saic/types/dist/analytics/event.js +1 -1
  285. package/node_modules/@m0saic/types/dist/analytics/usageMetrics.js +1 -1
  286. package/node_modules/@m0saic/types/dist/identifiers/identifiers.js +1 -1
  287. package/node_modules/@m0saic/types/dist/telemetry/ffmpegFailure.js +1 -1
  288. package/node_modules/@m0saic/types/package.json +1 -1
  289. package/node_modules/@m0saic/types-internal/dist/analytics/featureKeys.js +1 -1
  290. package/package.json +13 -11
  291. package/resources/starter-base/starter-base.json +10 -0
  292. package/resources/starter-base/starter-base.tgz +0 -0
@@ -0,0 +1,299 @@
1
+ # Standalone data-viz pack authoring — the sandbox playbook
2
+
3
+ A *pack* (`@<publisher>/<pack>/<slug>/vN`) is a cohesive set of **standalone**
4
+ templates sharing one brand look. Do **not** compose the generic `@m0saic/charts/*`
5
+ primitives — **reuse their pure geometry MATH** and build your own chrome on a small
6
+ shared kit. Canonical reference: `@m0saic/alpine/*` (bar-graph · commit-feed ·
7
+ contributor-table · donut · heatmap · kpi-card · leaderboard · line-chart ·
8
+ progress-card · stat-card · timeline · treemap), a **12-template** pack (as of
9
+ 2026-07-27 — `ls` the folder) built end-to-end via the sandbox protocol. Pairs with
10
+ https://github.com/m0saic-project/m0saic-sandbox/blob/main/packages/sandbox/agent.md and this folder's `construction-strategy.md` + `reference/`.
11
+
12
+ ## 0. Constraints first — the authoring loop (founder direction, 2026-09-05)
13
+
14
+ "Template design should move towards: you start by defining your constraints and
15
+ general direction, then build layout and check against various canvases and prop
16
+ combinations in a loop. The layout contract allows you to drive towards a
17
+ solution. And the build-time check throws before you even have a chance to open
18
+ Mosaic Desktop or invoke the CLI."
19
+
20
+ 1. **Declare the contract before the layout.** Write the props schema with its
21
+ defaults (every optional boolean / closed-set knob has a `defaultProps` value,
22
+ every plain string/number a default or a placeholder — §3 "Defaults are the
23
+ contract"), tag the pieces that carry design intent, and declare their
24
+ `LayoutConstraint`s + `textFits` under `debugLayout` — canvas-independent
25
+ ratios, not pixels. State the general direction (the aspect it is designed for,
26
+ how it degrades) in the description.
27
+ 2. **Build the layout against those constraints.** Real geometry first
28
+ ([`construction-strategy.md`](construction-strategy.md)); fit text under the
29
+ same ruler the contract checks with ([`layout-contract.md`](layout-contract.md)
30
+ §"Text").
31
+ 3. **Loop: check, don't eyeball.** `assertLayout` at the 7-canvas set
32
+ (1920×1080 · 1280×720 · 1080×1920 · 1080×1080 · 3840×2160 · 640×360 · 480×270)
33
+ × the prop combinations that change geometry (long titles, max items, every
34
+ closed-set value) in the gate test; `auditDefaultProps(T)` empty. A violation is
35
+ a design decision to make (shrink, compact wording, drop), not noise — the
36
+ contract drives toward the solution. Exemplar:
37
+ https://github.com/m0saic-project/m0saic-packages/blob/main/packages/templates/src/m0saic/dsl-tutorial/v1/dsl-tutorial.gate33.test.ts.
38
+ 4. **The build is the first gate.** `npm run build` in https://github.com/m0saic-project/m0saic-packages/blob/main/packages/templates (and
39
+ in the community pack and both starter repos) ends by loading the built
40
+ registry first-party (`tools/check-registry.mjs`): a template that hides a
41
+ default throws — naming the knobs and the fix — and the build fails before the
42
+ template can load in Mosaic Desktop or the CLI. Only then does the sandbox loop
43
+ (candidate → human verdict, §4) begin.
44
+
45
+ The layout contract stays debug-only at render time (2026-08-22 ruling — a render
46
+ with slightly clipped text beats no render); the gate test and the build step are
47
+ where it bites during authoring.
48
+
49
+ ## 1. Stand up the seam first (once per pack)
50
+
51
+ Three `_shared/` files (verified 2026-07-27 in https://github.com/m0saic-project/m0saic-packages/blob/main/packages/templates/src/m0saic/alpine/_shared):
52
+
53
+ - `<pack>-theme.ts` — tokens (surface/card/border, title/subtitle/label/muted,
54
+ primary/positive/negative, grid/axis), a categorical `PALETTE`,
55
+ `PRESETS{light,dark}`, a `theme(preset)` resolver. **Dark is not an afterthought:**
56
+ every color, wash, and contrast must be retuned for it (leaderboard `MEDALS_DARK`,
57
+ heatmap `EMPTY_DARK`) — a wash tuned for white glares or vanishes on navy.
58
+ - `<pack>-card.ts` — the Node combinator kit lifted from `charts/bar-graph/v2` (the
59
+ canonical tight-rect template): `paint` / `EMPTY` / `rowSplit` / `colSplit` /
60
+ `overlay` / `insetNode` / `textCell`, plus `resolveColor`, and a
61
+ `card({theme, W, H, title, subtitle})` returning `{contentRect, compose(content,
62
+ ...extraLayers), backgroundColor}`. Every template wraps its body in this card.
63
+ - `<pack>-anim.ts` — shared reveal choreography + prop-schema field factories:
64
+ `revealGate` / `revealSlide` / `revealFade` (source and Node flavors), the `fBool`
65
+ / `fStr` / `fNum` / `fFrac` / `fEnum` schema-field helpers, and the shared
66
+ `ALPINE_ANIM_FIELDS` block every template spreads into its props schema.
67
+
68
+ A `Node` is `{ m0: string; sources: MosaicSource[] }` built together so source
69
+ emission order always matches the DSL's DFS order.
70
+
71
+ **And the front door (the hello-world convention, 2026-09-14).** Every template
72
+ repo names the template a newcomer renders first: `repo.helloWorld` on the repo
73
+ descriptor (`src/repo.ts` in the starters). The default is the canonical m0saic
74
+ card, one call from `@m0saic/template-utils`:
75
+
76
+ ```ts
77
+ const card = defineHelloWorldTemplate({ id: "@acme/basics/hello-world/v1", subline: `by ${TEMPLATE_REPO.displayName}` });
78
+ ```
79
+
80
+ The field, the M, the wordmark and the greeting stay the brand ("made with
81
+ m0saic"); `subline` is the repo's own line, seeded into the `caption` prop. A pack
82
+ that wants its own look writes its own template and points `repo.helloWorld` at
83
+ it. The gate warns (`repoFrontDoor`, record posture — never fatal) when a repo
84
+ names no front door or names an id it does not register. `m0saic hello-world
85
+ --template-repo .` renders it; the manifest carries the field zero-exec.
86
+
87
+ Two authoring facts, both learned on the starters:
88
+
89
+ - Spell the structural fields out in the repo module — a literal with
90
+ `version`, `propsSchema: { ...HELLO_WORLD_PROPS_SCHEMA }`, `defaultProps`, and a
91
+ `render` that delegates to the factory — because the no-install contract check
92
+ loads the entry with every `@m0saic/*` import stubbed to an identity proxy, under
93
+ which a bare factory call reads as an options bag. Copy either starter's
94
+ `src/basics/hello-world/v1/hello-world.ts`.
95
+ - A still of the card at t=0 is a bare navy canvas (the field wipes in, the M
96
+ assembles). Gallery stills are cut from the clip near its end — the starters'
97
+ `gen-previews.mjs` carries a per-id `STILL_AT_SEC` (hello-world → 2.45 s). The
98
+ card also WIDENS for a long line (to 92% of the canvas) before type shrinks or
99
+ truncates; the default card never widens, so the shipped fingerprint holds.
100
+
101
+ ## 2. Two construction modes — pick per template
102
+
103
+ - **Splits** (leaderboard, bar, progress) — real m0 cells via `weightedSplit`. Best
104
+ for row/column layouts. Snap nested weights to a multiple of 8 so they GCD-collapse
105
+ and stay quantization-feasible at any resolution. (Large splits with coprime pixel
106
+ weights deterministically spread the fractional remainder — that's precision, not
107
+ a bug; canonical: `handbook/feasibility-precision-quantization.md`.)
108
+ - **placeRects absolute** (donut, line, heatmap, timeline, treemap) — every cell is a
109
+ tight rect on the **SNAP_PX (4px) lattice**, packed full-canvas via `placeRects`.
110
+ Use for grids, rings, scatter, calendars, treemaps, spines — anything not a clean
111
+ split. **THE recurring bug (bit on heatmap, timeline, treemap):** pass the
112
+ placeRects body as a **full-canvas extraLayer** — `card.compose(EMPTY, body)` —
113
+ **never as the scaled `content`.** Scaled content goes through `insetNode`, which
114
+ re-quantizes the split weights into a smaller rect → uneven cells /
115
+ `SPLIT_EXCEEDS_AXIS` (0-size band). Also snap **pitch, gap, and all offsets** to
116
+ the lattice so every cell edge and gap-band boundary is grid-aligned.
117
+
118
+ ## 3. The knobs every template gets right
119
+
120
+ - **Defaults are the contract ("a knob shows what it does", 2026-09-05).** Every
121
+ optional `boolean` and closed-set knob (`constraints.oneOf` / `control.options`)
122
+ carries a `defaultProps` value; every plain `string` / `number` a default OR a
123
+ `meta.control.placeholder` naming the unset behaviour ("auto"). A fallback that
124
+ lives only in `render()` (`props.title ?? "…"`, `props.show !== false`) makes the
125
+ Make panel LIE (empty / OFF for a value the render fills in). `defineMosaicTemplate`
126
+ throws `TemplateConventionError` for a first-party violation at import; an external
127
+ pack's is recorded, never fatal. A closed-set knob whose unset state is not one
128
+ of its options gets a `"none"` option (defaulted, normalised away in `render()`).
129
+ Rule + exemptions: [`philosophy-and-contract.md`](philosophy-and-contract.md)
130
+ §"Props as a UI-renderable schema".
131
+ - **`resolveColor(value, fallback)` on EVERY color knob.** A bare `props.color ??
132
+ fallback` keeps `""` (not nullish) → renders the mark in no color → invisible. A
133
+ cleared / "none" / blank picker must fall back.
134
+ - **Dual props.** Agent-canonical knobs (`anim`, `valueMode`, `orientation`, …) plus
135
+ human-facing toggles/sliders (`animate`, `showValue`, `introLength`, `cornerRadius`)
136
+ wired via `meta.control.syncsTo` (e.g. `animate` → `anim.reduceMotion` boolInvert).
137
+ Anything a human flips or drags belongs in `consumer:"human"` — they WILL ask.
138
+ - **Labels.** Compact big numbers (`compactNum`: `4500→4.5K`); size the font
139
+ length-aware or shrink-to-fit; ellipsis-truncate only when even the min font
140
+ overflows, bounding truncation width so labels can't collide. Do **not** use
141
+ `fit:"contain"` for a single line — it scales to HEIGHT and clips width. Fit
142
+ under `textEmUnits × fontSize × em` with a `cell × 0.94 − 2px` budget and lock it
143
+ with `textFits` — [`layout-contract.md`](layout-contract.md) §"Text".
144
+ - **Contrast auto-flip.** `onColor(hex, light, dark)` via relative luminance for any
145
+ text sitting on a colored fill (white on saturated, dark on pale/amber).
146
+ - **Animation.** Opacity rides `overlay.alpha` — `makeColorTile` IGNORES `visual`.
147
+ `fadeInExpr(start, dur)` cascades; `animateNumbersInText` for count-up;
148
+ `reduceMotion` → the static board. **Overlay-depth limit (~25 nested layers):** the
149
+ engine silently drops masks (circle markers → squares, text → tofu); use a single
150
+ curtain-wipe overlay, not a per-sliver cascade.
151
+ - **Aspect-awareness.** Stress vertical / square / horizontal. A wide card may need a
152
+ different layout (timeline's `orientation:"auto"`); clamp edge content so it can't
153
+ spill the card.
154
+ - **Image or video → the same resolver (2026-09-26).** A template with a media slot
155
+ that accepts both kinds answers per props — `resolveOutputHints: (props) => ({ format })`
156
+ from a pure check on the media path's extension — and its static `outputHints.format`
157
+ is that value at `defaultProps`. An empty slot renders a still, so the honest static
158
+ answer is usually **image** (the seam's `outputHintsResolve` throw keeps the two
159
+ equal). Never let a host guess from the document: `inferOutputKind` is a last resort
160
+ for a bare `.mosaic`, not a decision. Reference: `reference/template-flags.md`
161
+ § "A canvas that is a knob".
162
+ - **A canvas that is a knob → `resolveOutputHints(props)`.** When a prop picks the
163
+ output size (a `platform` knob: YouTube 1920×1080 vs TikTok 1080×1920), declare
164
+ the resolver on the template so hosts SEED the right target before rendering
165
+ (`resolveTemplateOutputHints` is the one helper CLI / Electron / web / Make use);
166
+ `render` still reads `ctx.target` and lays out at any size. At `defaultProps` it
167
+ must agree with the static `outputHints` (`outputHintsResolve`, throw). Rules:
168
+ [`philosophy-and-contract.md`](philosophy-and-contract.md) §"Output contract".
169
+ - ⛔ **Filling the canvas: `document.backgroundColor`, never a full-frame rect.** This is
170
+ the **`canvasFill` convention, and it THROWS** (2026-09-25) — the build and
171
+ `m0saic doctor` both refuse a root document carrying a static, opaque, full-canvas colour
172
+ source. A base rect is a click target that shadows everything behind it, selected any time
173
+ the pointer is not on a smaller tile, and it is redundant: `doc.backgroundColor` fills the
174
+ canvas with no rect at all. Only a STATIC, opaque, unshaped fill counts — a curtain wipe
175
+ (`overlay.enable` / `window`), a scrim (`overlay.alpha`), a masked shape, a rounded card
176
+ (`effects`) and an inset fill (`placement`) are all legitimate and never flagged.
177
+ Templates already frozen are exempt. `bindingsDeclared` also accepts a colour prop that IS the document background
178
+ with neither a binding nor a declaration, because such a prop has no rect to bind.
179
+ - ⚠️ **The one case that needs a rect: a template COMPOSED INTO another.** The engine
180
+ lifts `backgroundColor` from the PRIMARY OUTPUT document only, so a child document's
181
+ own background is silently ignored (tracked at
182
+ (internal design history) — founder
183
+ owns the engine fix).
184
+ - **The declared escape** — an opt-in dev prop, NOT a rect in the default shape.
185
+ Defaulting it to `true` is ALSO how a template tells `canvasFill` that its rect is
186
+ deliberate; declaring it `false` is no escape:
187
+
188
+ ```ts
189
+ useNestedBackgroundColor: {
190
+ type: "boolean", required: false,
191
+ description: "Compose-time: also paint the background as a full-frame rect, for when this template is nested inside another (a child document's own backgroundColor is ignored by the engine).",
192
+ meta: { ui: { hidden: true, label: "Nested background rect" } },
193
+ }
194
+ ```
195
+
196
+ `defaultProps` leaves it **false / absent**, so a standalone render never grows the
197
+ rect. A template that composes this one passes `useNestedBackgroundColor: true` in the
198
+ child's props. Keep `backgroundColor` set as well — it costs nothing and keeps the
199
+ standalone path identical.
200
+ - **The m0 move is ONE wrap.** `F{…}` prepends exactly one full-canvas frame and the
201
+ wrapped layout follows in order (`F{2[1,1]}` → `1280x720@0,0`, `1280x360@0,0`,
202
+ `1280x360@0,360` at 720p), so frame 0 is the base and the content overlays it:
203
+
204
+ ```ts
205
+ if (props.useNestedBackgroundColor) {
206
+ return { ...doc, m0: `F{${doc.m0}}`, sources: [colorSource(bg), ...doc.sources] };
207
+ }
208
+ ```
209
+
210
+ `F` is pretty syntax: it **canonicalizes to `1{…}`**, and the file formats never emit
211
+ pretty form, so on disk the wrapper reads `1{…}`. Every source index shifts by one, so
212
+ anything keyed by `sourceIndex` (never a binding — those key by prop) moves with it.
213
+ - `meta.ui.hidden` is deliberate: this is a compose-time flag a parent sets
214
+ programmatically, not a knob a human picks (and hidden props are outside
215
+ `bindingsDeclared`'s roll call — a boolean is anyway).
216
+ - **When the engine fix lands, this prop goes away**: delete it, delete the rect, keep
217
+ `backgroundColor`. That is the whole point of it being opt-in and hidden rather than
218
+ baked into every template's shape.
219
+
220
+ - **Prop bindings — the rect that SHOWS a prop is its handle in Make.**
221
+ `bindProp(src, key)` / `bindProps(src, entries)` / `bindPropPath(src, key, path,
222
+ kind)` / `bindPropRange(...)` (`@m0saic/template-utils`) stamp `editor.binding` on
223
+ the source that displays a prop; Make resolves them per render (`bindingsSound`
224
+ throws on a binding the schema refuses — booleans, closed pickers and whole lists
225
+ are never bindable) and the preview shows one glyph per thing the tile can do (T
226
+ text · 123 number · swatch colour · move rect · picture media), collapsing to ONE
227
+ dot on a small tile. Bind even when the value is empty (the rect is a handle to
228
+ ADD). ⛔ **`bindingsDeclared` (0.3.0) THROWS** when a prop that could carry a handle
229
+ is neither bound nor named in `template.bindings.unbound` with its reason
230
+ (`{ fps: "timing" }`) — free-text and colour strings, numbers, media, one element of a
231
+ basic list, one leaf of json/list/array, and a regions-picker rect must all be
232
+ accounted for; booleans, closed sets, groups, the m0 family, code and hidden/human
233
+ props never are. Templates in `frozen.manifest.json` are exempt. On a rect that
234
+ already binds another prop the fix is `bindProps`, never a second `bindProp` — it
235
+ would replace the first. The full contract — kinds, `onClear`, `seedDraft`, `kind: "media"` (a rect
236
+ that takes a dropped file), `companion`, starter media — is
237
+ [`reference/prop-bindings.md`](reference/prop-bindings.md).
238
+ **`kind: "rect"` (2026-09-15) — a rendered cell edited IN PLACE:** a `json` prop
239
+ with `picker: "regions"` and `regions.max: 1`, bound with `bindPropRect(src, key)`
240
+ (no path). Double-click / the move badge opens the regions draw session seeded
241
+ from the cell's painted rect; drag, 8 handles, Shift = aspect lock, Delete = back
242
+ to automatic placement, Esc / Enter = done; every gesture end writes `{ canvas,
243
+ regions: [rect] }` into the prop and the template re-renders — never a
244
+ destructive post-render edit. The template must still render a correct default
245
+ placement when the prop is empty: the binding is the handle, not the layout. A
246
+ cell may carry several bindings (`bindProps` with a rect entry AND text entries) —
247
+ that is the "move the cell OR change its contents" surface. First implementer:
248
+ `@m0saic-dev/creator/drop-calendar/v1` (`facecamRegion`).
249
+
250
+ ## 4. The sandbox loop
251
+
252
+ The full iteration ritual is https://github.com/m0saic-project/m0saic-sandbox/blob/main/packages/sandbox/agent.md — read it before authoring
253
+ or iterating on any candidate; this doc does not duplicate it. Naming convention in
254
+ one line: `candidate-NNN.mosaicx` (one file = one question = one verdict), a frozen
255
+ `candidate-NNN-agent.mosaicx` snapshot before every open, and
256
+ `candidate-NNN_humanedits.mosaic` frozen from the live dist BEFORE editing the
257
+ template on negative feedback.
258
+
259
+ ## 5. The lock is the full closeout — non-negotiable
260
+
261
+ Canonical: https://github.com/m0saic-project/m0saic-sandbox/blob/main/packages/sandbox/agent.md §"Session closeout" + §"Template-build
262
+ closeout (the `.mosaicx` flavor)". This doc intentionally does not summarize the
263
+ artifact list — read agent.md and follow it. Two rules earlier summaries
264
+ dangerously omitted:
265
+
266
+ 1. **The master is `master_candidate-NN.mosaicx` until approval.** "Do NOT mint a
267
+ bare `master.mosaicx` before approval — that name is reserved for the approved
268
+ file." Rejected gates stay frozen; the fix ships as `master_candidate-02`, etc.;
269
+ only on approval is the file renamed to `master.mosaicx` + `master.mosaic`.
270
+ 2. **"Gate EVERY output aspect, not just one."** Aspect-adaptive templates pass
271
+ desktop and still fail square/mobile — the final gate is the human rendering ALL
272
+ aspects (H / V / square) from the candidate and signing off. Verify the aspects
273
+ yourself first, but the gate is theirs.
274
+ 3. **The layout contract comes BEFORE candidate-01.** Tag every fitted text source,
275
+ declare `textFits` under `debugLayout`, and sweep `assertLayout` at the 7-canvas
276
+ set in the gate test — [`layout-contract.md`](layout-contract.md)
277
+ §"Recommended". A gate that passed one aspect and clipped on portrait is the
278
+ scenario this rule was written for (gate 33).
279
+
280
+ ## 6. Cross-cutting gotchas (bit on multiple templates)
281
+
282
+ - `cornerRadius` is a **0..0.5 fraction of the cell's shorter side** → px radius
283
+ (`borderRadius * min(w, h)`). At high radius, inset top-left labels must clear
284
+ the corner curve.
285
+ - **Make `--make` open adopts the file's `size`** over the template's `outputHints`
286
+ (a 1080² candidate must open square, not 1280×800). Beware: Make's save-back
287
+ rewrites the file's size/props to the panel state — re-freeze candidates that drift.
288
+ - **The render-hero preview rounds a cell by driving `border-radius !important`** on
289
+ the matched ViewFrame cell (`Frame.tsx` wires `var(--vf-tile-radius, 0px)`, so a
290
+ plain assign is overridden). Measure the radius via `ResizeObserver` — cells can be
291
+ 0×0 on the first effect pass.
292
+ - **The 119/121 fencepost.** `weights.map(w => round(w / sum * 120))` sums to
293
+ 120 ± (bands − 1): every Alpine card carried `121×2`, the pulse heroes `121×8`,
294
+ and 121 = 11² poisons every composition (LCM with the core = 14,520). The kit
295
+ line is `weightedSplit(latticeWeights(weights, { cap: 120 }), axis, { claimants })`
296
+ (Hamilton to an exact 5-smooth total, GCD to a divisor: `[59,1802,59] → [1,28,1]`).
297
+ Since 2026-09-16 the build gate and `m0saic doctor` refuse a rough count above 12
298
+ (`latticeSmooth`, throw — [`reference/template-flags.md`](reference/template-flags.md))
299
+ — for a pack it is the publish requirement, so run the doctor before tagging.
@@ -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.
@@ -0,0 +1,6 @@
1
+ {
2
+ "name": "@m0saic/knowledge",
3
+ "version": "0.2.0",
4
+ "main": "dist/index.js",
5
+ "license": "MIT"
6
+ }
@@ -0,0 +1,109 @@
1
+ # `@m0saic/momo-types` — Vocabulary Contract for the AI-Human Work-Session Protocol
2
+
3
+ This package **is** the canonical vocabulary for how AI agents and humans collaborate on m0saic layouts. When in doubt about which word to use, this file decides — collaborators (people, agents, downstream tooling) that drift into synonyms cause real fragmentation, and adapters between half-matching APIs are the cost. Read this file once; use these nouns everywhere.
4
+
5
+ ## Why a separate package
6
+
7
+ The vocabulary is expected to grow as the AI layer matures (new categories, new evaluation kinds, future shapes none of us have named yet). Keeping it in its own publishable package — separate from the heavy `@m0saic/momo` runtime — means:
8
+
9
+ - **Any package can share the shape cheaply.** File-format layers (`@m0saic/dsl-file-formats`), tooling (`wireframe.mjs`), the desktop editor (`apps/mosaic`) — they all take a dep on `@m0saic/momo-types` without pulling in the model wrapper, tool registry, or download lifecycle.
10
+ - **Types-only / types-mostly.** Two small pure-function helpers (`gradeFromScore`, `normalizeCandidateContext`) ship alongside the types; everything else is type-only. Zero runtime baggage.
11
+ - **The file formats own the wire shapes.** `M0AgentMeta`, `M0AgentResponse`, `M0AgentComment`, the loose `CandidateContext` and the transport helpers (`mintAgentId`, `normalizeAgentProse`…) are defined in `@m0saic/dsl-file-formats` — this package depends on it and re-exports them with the typed `CandidateContext` refinement, so the language repo stays free of the agent protocol and nothing is duplicated.
12
+ - **Independent release cadence.** When the protocol churns (it will), `@m0saic/momo-types` can bump versions without dragging the rest of momo along.
13
+
14
+ The model is consciously chess-inspired (see `./candidate.ts` for the chess.com grade union, taken verbatim) — sessions are games, candidates are positions, evaluations are annotator marks, scoring is the engine eval.
15
+
16
+ ---
17
+
18
+ ## Canonical noun set
19
+
20
+ | Noun | Meaning | Lives in |
21
+ |---|---|---|
22
+ | **session** | A chronological directory of candidates exploring one problem. The "game" in the chess analogy. | `session.ts` |
23
+ | **candidate** | One `.m0` (or `.m0c`) file inside a session. The "position / move". | `session.ts`, `candidate.ts` |
24
+ | **intent** | What the writing party is *trying* to accomplish (per-candidate prose + optional closed-union verb). | `category.ts` |
25
+ | **category** | What *class* of layout problem this session is solving. Closed union + `other` escape hatch. | `category.ts` |
26
+ | **layout-intent** | The structural kind of a candidate's geometry (grid / comparison / spotlight / …). Picked by the scorer's caller. | `scoring.ts` |
27
+ | **grade** | Categorical evaluation of a candidate (chess.com vocab, verbatim). Rank order (strong → weak): `brilliant` ▸ `great` ▸ `best` ▸ `excellent` ▸ `good` ▸ `inaccuracy` ▸ `mistake` ▸ `blunder`. Plus `book` (known canon), `miss` (human-only judgment), `unevaluated`. **Note:** `best` means "engine's top pick" — `brilliant` and `great` rank *above* it. | `candidate.ts` |
28
+ | **score** / **breakdown** | The numeric automated quality signal from `scoreLayout`. `breakdown` is the per-metric view. Types here; values + scoring function in `@m0saic/momo/scoring`. | `scoring.ts` |
29
+ | **evaluation** | The grade assignment for one candidate — `grade` + optional `breakdown` + provenance. | `candidate.ts` |
30
+ | **annotation** | Any structured note attached to a candidate (a `RegionAnnotation`, a comment, a relation). | `region.ts`, `agent/meta.ts` |
31
+ | **region** | A labeled sub-area of the geometry, keyed by stableKey. | `region.ts` |
32
+ | **relation** | Lineage between candidates (`refines`, `branches-from`, `rejects`, …). | `candidate.ts` |
33
+ | **party** | Anyone who can speak in the thread — `human`, `human:<name>`, `agent:<id>`. | `party.ts` |
34
+ | **phase** | Tripartite session arc — `scaffolding` / `refining` / `finalizing`. Mosaic analog of chess opening/middlegame/endgame. | `session-summary.ts` |
35
+ | **summary** | Per-party + per-phase stats across a session. Renders as the Game Review board on the post-mortem template. | `session-summary.ts` |
36
+ | **corpus** | The union of all sessions across all sandboxes — the "book". | (concept; no type) |
37
+
38
+ ---
39
+
40
+ ## Banned synonyms
41
+
42
+ When tempted to use the left, use the right.
43
+
44
+ | Don't use | Use instead | Why |
45
+ |---|---|---|
46
+ | *background* | **context** | The `M0AgentMeta.context` field is the carrier; "background" is the same idea in different syllables. |
47
+ | *prompt* | **question** | `M0AgentMeta.question` is the specific ask field; "prompt" is overloaded with LLM-prompt-engineering jargon. |
48
+ | *attempt* | **candidate** | A candidate is one file (the position). Calling it an "attempt" loses the chess analogy. |
49
+ | *iteration* | **session** OR **candidate** | Pick one — an iteration is *either* the whole session you went through *or* the next candidate you produced. Don't conflate. |
50
+ | *rating* / *quality* (numeric) | **score** | `ScoreBreakdown.total` is "score". Use "rating" only for the per-session Elo-style number in `PartySummary.rating`. |
51
+ | *grade* | **(only for the categorical thing)** | Grade is `brilliant` / `mistake` / `blunder` — the categorical chess mark. Don't write `grade` when you mean `score`. |
52
+
53
+ ---
54
+
55
+ ## The two orthogonal axes (read carefully)
56
+
57
+ `LayoutIntent` and `SessionCategory` are the most-confused pair. They are **NOT the same thing**; they live on different axes of the same candidate.
58
+
59
+ - **`LayoutIntent`** (`../scoring`) — *structural* kind of the layout. `grid`, `comparison`, `spotlight`, `magazine`, `ranked-list`, `free`. Picked by the scorer's caller so `scoreLayout` uses the right weight row.
60
+ - **`SessionCategory`** (`./category.ts`) — *kind of exploration* the session is performing. `spacing-alignment`, `hierarchy-emphasis`, `scaffold-from-scratch`, etc. Picked by the human or agent to classify what the iteration is FOR.
61
+
62
+ ### Worked example
63
+
64
+ A user is iterating on the bar-graph template. They have a working 5-bar grid that feels visually cramped. They open a session to refine it:
65
+
66
+ - `SessionCategory`: `{ kind: "known", value: "spacing-alignment" }` — the session is exploring how to fix the cramped feeling.
67
+ - Each candidate's `layoutIntent`: `"grid"` — the geometry stays a grid throughout; only its gutters and weights vary.
68
+
69
+ The two axes co-vary in principle (a `spacing-alignment` session usually keeps `layoutIntent` constant across candidates because the geometry is what you're refining), but they're recorded independently because they answer different questions.
70
+
71
+ ---
72
+
73
+ ## Engine eval vs. annotator mark (the chess analogy is load-bearing)
74
+
75
+ A chess game has BOTH the engine's centipawn score (numeric, machine-computed) AND the annotator's `?!` (categorical, human-applied). They don't replace each other — they're shown side-by-side in any decent game review.
76
+
77
+ Same here:
78
+
79
+ - `breakdown.total` (number, 0..1) — the **engine eval**. Cheap, deterministic, available on any candidate.
80
+ - `evaluation.grade` (one of `brilliant` / `great` / … / `blunder`) — the **annotator mark**. Canonical; the human's selected answer.
81
+
82
+ When they disagree, the human wins — and the disagreement itself is interesting. The post-mortem template surfaces those moments because they're exactly where learning lives.
83
+
84
+ `gradeFromScore()` in `./candidate.ts` provides one auto-derivation path (use it for pre-fills); the human can always overwrite. **The automated grader caps at `best`** — it never returns `brilliant` or `great`, because those require insight (sacrifice, critical-moment recognition) an automated metric can't see. Same for `book` and `miss`. Those four grades are reserved for humans to award when they spot something the score didn't.
85
+
86
+ ---
87
+
88
+ ## Shared, not mirrored
89
+
90
+ This package's types are the **single source of truth**. `@m0saic/dsl-file-formats` and `@m0saic/momo` both take a workspace dep on `@m0saic/momo-types` and import the shapes directly — no parallel declarations, no CI lint to keep mirrors in sync.
91
+
92
+ (One holdover: `M0AgentMeta` itself remains mirrored between `@m0saic/momo` and `@m0saic/dsl-file-formats` — that struct predates this package and is stable enough that collapsing it isn't worth the churn.)
93
+
94
+ ---
95
+
96
+ ## Coexists with: scoring values in `@m0saic/momo/scoring`
97
+
98
+ Scoring is **split** across the two packages:
99
+
100
+ - **Types** (`ScoreBreakdown`, `LayoutIntent`, `ScoreInput`, `ScoreComponent`, `ScoreComponentKey`) live here in `./scoring.ts`.
101
+ - **Values + logic** (`WEIGHTS`, `THRESHOLDS`, the `scoreLayout` function, quality curves) live in `@m0saic/momo/scoring`.
102
+
103
+ `@m0saic/momo`'s `WEIGHTS` uses `satisfies Record<LayoutIntent, WeightTuple>` so the runtime constant and the type union stay in lockstep — adding a new intent requires editing both, with the type-check enforcing the consistency.
104
+
105
+ ---
106
+
107
+ ## Open: starter category enum
108
+
109
+ The nine `KnownCategory` entries in `./category.ts` are the Plan-agent's best guess. They'll get refined once the user has driven enough real sessions to know which buckets are over/under-represented. Promote new patterns from `{ kind: "other", label: "X" }` to first-class after a label recurs ~3 times across sessions.