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.
- package/LICENSE +22 -7
- package/README.md +23 -5
- package/dist/browseE2e.js +1 -1
- package/dist/connectionsFromEnv.js +1 -1
- package/dist/e2eTemplateVariants.js +1 -1
- package/dist/frontDoor.js +1 -1
- package/dist/index.js +1 -1
- package/dist/inlineDsl.js +1 -1
- package/dist/mcp/bridgeClient.js +1 -0
- package/dist/mcp/server.js +1 -0
- package/dist/mcp/tools.js +1 -0
- package/dist/mosaicxRunner.js +1 -1
- package/dist/outputPattern.js +1 -1
- package/dist/showcaseFeed.js +1 -1
- package/dist/templateDoctor.js +1 -1
- package/dist/utils/checkFeasibility.js +1 -1
- package/dist/utils/collectRenderErrors.js +1 -1
- package/dist/utils/enrichImageAlphaFromDoc.js +1 -1
- package/dist/utils/ensureFfmpeg.js +1 -1
- package/dist/utils/extractLayoutMeta.js +1 -1
- package/dist/utils/failureHints.js +1 -1
- package/dist/utils/ffmpegProbe.js +1 -1
- package/dist/utils/formatM0saicForCli.js +1 -1
- package/dist/utils/hashFile.js +1 -1
- package/dist/utils/helpGroups.js +1 -1
- package/dist/utils/installContext.js +1 -0
- package/dist/utils/invocation.js +1 -1
- package/dist/utils/licenseActivation.js +1 -0
- package/dist/utils/licenseActivationWorker.js +1 -0
- package/dist/utils/mosaicSpinner.js +1 -1
- package/dist/utils/parseDimensions.js +1 -1
- package/dist/utils/pathInfo.js +1 -1
- package/dist/utils/readJsonArg.js +1 -1
- package/dist/utils/renderOutcome.js +1 -1
- package/dist/utils/renderReport.js +1 -1
- package/dist/utils/renderSignals.js +1 -1
- package/dist/utils/renderWorkspace.js +1 -1
- package/dist/utils/reportOutputFormat.js +1 -0
- package/dist/utils/setupFfmpeg.js +1 -1
- package/dist/utils/telemetry.js +1 -1
- package/dist/utils/telemetryFlushWorker.js +1 -1
- package/dist/utils/telemetryUpstream.js +1 -1
- package/dist/utils/telemetryUsage.js +1 -1
- package/dist/utils/toolchainConfig.js +1 -1
- package/dist/utils/tutorialDuration.js +1 -1
- package/dist/utils/updateCheck.js +1 -1
- package/dist/utils/updateCheckWorker.js +1 -1
- package/dist/utils/validateSourceCounts.js +1 -1
- package/dist/utils/versions.js +1 -1
- package/dist/webCustomizeLink.js +1 -1
- package/node_modules/@m0saic/community-m/NOTICE +9 -0
- package/node_modules/@m0saic/community-m/release.json +2 -2
- package/node_modules/@m0saic/core/dist/core/buildChildMosaicSource.js +1 -1
- package/node_modules/@m0saic/core/dist/core/buildChunkCommands.js +1 -1
- package/node_modules/@m0saic/core/dist/core/buildEncodeCommands.js +1 -1
- package/node_modules/@m0saic/core/dist/core/buildLavfiSource.js +1 -1
- package/node_modules/@m0saic/core/dist/core/buildMediaSource.js +1 -1
- package/node_modules/@m0saic/core/dist/core/buildMosaicNode.js +1 -1
- package/node_modules/@m0saic/core/dist/core/buildMosaicPlanFromFile.js +1 -1
- package/node_modules/@m0saic/core/dist/core/buildSvgTextSource.js +1 -1
- package/node_modules/@m0saic/core/dist/core/buildTextRenderCommand.js +1 -1
- package/node_modules/@m0saic/core/dist/core/collectRefTargets.js +1 -1
- package/node_modules/@m0saic/core/dist/core/index.js +1 -1
- package/node_modules/@m0saic/core/dist/core/maskCacheDir.js +1 -1
- package/node_modules/@m0saic/core/dist/core/maskWorkerBridge.js +1 -1
- package/node_modules/@m0saic/core/dist/core/playbackPlaySpeed.js +1 -1
- package/node_modules/@m0saic/core/dist/core/prepareProps.js +1 -1
- package/node_modules/@m0saic/core/dist/core/primaryOutput.js +1 -1
- package/node_modules/@m0saic/core/dist/core/rasterizeMaskPng.js +1 -1
- package/node_modules/@m0saic/core/dist/core/rasterizeSvgMediaPng.js +1 -1
- package/node_modules/@m0saic/core/dist/core/refTargetTap.js +1 -1
- package/node_modules/@m0saic/core/dist/core/resolveMasks.js +1 -1
- package/node_modules/@m0saic/core/dist/core/resolveMasksSync.js +1 -1
- package/node_modules/@m0saic/core/dist/core/resolveStrokeRingsSync.js +1 -1
- package/node_modules/@m0saic/core/dist/core/roundedRectMask.js +1 -1
- package/node_modules/@m0saic/core/dist/core/strokeRing.js +1 -1
- package/node_modules/@m0saic/core/dist/core/svgRaster.js +1 -1
- package/node_modules/@m0saic/core/dist/defaults.js +1 -1
- package/node_modules/@m0saic/core/dist/ffmpeg/backgroundImageInput.js +1 -1
- package/node_modules/@m0saic/core/dist/ffmpeg/bufferGuard.js +1 -1
- package/node_modules/@m0saic/core/dist/ffmpeg/ffmpegCommands.js +1 -1
- package/node_modules/@m0saic/core/dist/ffmpeg/filters/applyBackdropBlur.js +1 -1
- package/node_modules/@m0saic/core/dist/ffmpeg/filters/applyBlur.js +1 -1
- package/node_modules/@m0saic/core/dist/ffmpeg/filters/applyBorderRadius.js +1 -1
- package/node_modules/@m0saic/core/dist/ffmpeg/filters/applyCamera.js +1 -1
- package/node_modules/@m0saic/core/dist/ffmpeg/filters/applyChromaKey.js +1 -1
- package/node_modules/@m0saic/core/dist/ffmpeg/filters/applyFade.js +1 -1
- package/node_modules/@m0saic/core/dist/ffmpeg/filters/applyGrade.js +1 -1
- package/node_modules/@m0saic/core/dist/ffmpeg/filters/applyMask.js +1 -1
- package/node_modules/@m0saic/core/dist/ffmpeg/filters/applyNoise.js +1 -1
- package/node_modules/@m0saic/core/dist/ffmpeg/filters/applyPixelize.js +1 -1
- package/node_modules/@m0saic/core/dist/ffmpeg/filters/applyRotate.js +1 -1
- package/node_modules/@m0saic/core/dist/ffmpeg/filters/applyStroke.js +1 -1
- package/node_modules/@m0saic/core/dist/ffmpeg/filters/applyTileEffects.js +1 -1
- package/node_modules/@m0saic/core/dist/ffmpeg/filters/coverCrop.js +1 -1
- package/node_modules/@m0saic/core/dist/ffmpeg/filters/index.js +1 -1
- package/node_modules/@m0saic/core/dist/ffmpeg/filters/sourceRectCrop.js +1 -1
- package/node_modules/@m0saic/core/dist/ffmpeg/gridLowering.js +1 -1
- package/node_modules/@m0saic/core/dist/ffmpeg/index.js +1 -1
- package/node_modules/@m0saic/core/dist/ffmpeg/splitAvMux.js +1 -1
- package/node_modules/@m0saic/core/dist/ffmpeg/threadGuard.js +1 -1
- package/node_modules/@m0saic/core/dist/flatten/index.js +1 -1
- package/node_modules/@m0saic/core/dist/fs/index.js +1 -1
- package/node_modules/@m0saic/core/dist/fs/tempWorkspace.js +1 -1
- package/node_modules/@m0saic/core/dist/index.js +1 -1
- package/node_modules/@m0saic/core/dist/media/buildAssetManifestFromInputs.js +1 -1
- package/node_modules/@m0saic/core/dist/media/buildMediaRegistryFromInput.js +1 -1
- package/node_modules/@m0saic/core/dist/media/collectMediaInputsFromInvocationProps.js +1 -1
- package/node_modules/@m0saic/core/dist/media/collectMediaInputsFromMosaicRenderableFile.js +1 -1
- package/node_modules/@m0saic/core/dist/media/collectMediaInputsFromProps.js +1 -1
- package/node_modules/@m0saic/core/dist/media/index.js +1 -1
- package/node_modules/@m0saic/core/dist/media/internalMintAsset.js +1 -1
- package/node_modules/@m0saic/core/dist/media/remoteUrl.js +1 -1
- package/node_modules/@m0saic/core/dist/media/stageUnsafeFilenames.js +1 -1
- package/node_modules/@m0saic/core/dist/media/types.js +1 -1
- package/node_modules/@m0saic/core/dist/output/index.js +1 -1
- package/node_modules/@m0saic/core/dist/output/resolveOutputFormat.js +1 -1
- package/node_modules/@m0saic/core/dist/output/types.js +1 -1
- package/node_modules/@m0saic/core/dist/probe/cellLuminanceProbe.js +1 -1
- package/node_modules/@m0saic/core/dist/probe/extractSubtitleCues.js +1 -1
- package/node_modules/@m0saic/core/dist/probe/helpers.js +1 -1
- package/node_modules/@m0saic/core/dist/probe/index.js +1 -1
- package/node_modules/@m0saic/core/dist/probe/luminanceProbe.js +1 -1
- package/node_modules/@m0saic/core/dist/probe/probeMedia.js +1 -1
- package/node_modules/@m0saic/core/dist/probe/runFFprobe.js +1 -1
- package/node_modules/@m0saic/core/dist/probe/types.js +1 -1
- package/node_modules/@m0saic/core/dist/runtime/engineRedaction.js +1 -1
- package/node_modules/@m0saic/core/dist/runtime/ffmpegFailure.js +1 -1
- package/node_modules/@m0saic/core/dist/runtime/filterPreflight.js +1 -1
- package/node_modules/@m0saic/core/dist/runtime/hashFile.js +1 -1
- package/node_modules/@m0saic/core/dist/runtime/index.js +1 -1
- package/node_modules/@m0saic/core/dist/runtime/pathInfo.js +1 -1
- package/node_modules/@m0saic/core/dist/runtime/perfHeatmap.js +1 -1
- package/node_modules/@m0saic/core/dist/runtime/perfReport.js +1 -1
- package/node_modules/@m0saic/core/dist/runtime/pipelineM0p.js +1 -1
- package/node_modules/@m0saic/core/dist/runtime/renderCostModel.constants.js +1 -1
- package/node_modules/@m0saic/core/dist/runtime/renderCostModel.js +1 -1
- package/node_modules/@m0saic/core/dist/runtime/renderReport.js +1 -1
- package/node_modules/@m0saic/core/dist/runtime/renderSidecars.js +1 -1
- package/node_modules/@m0saic/core/dist/runtime/resolveMosaicx.js +1 -1
- package/node_modules/@m0saic/core/dist/runtime/runPlan.js +1 -1
- package/node_modules/@m0saic/core/dist/runtime/types.js +1 -1
- package/node_modules/@m0saic/core/dist/runtime/upstream.js +1 -1
- package/node_modules/@m0saic/core/dist/runtime/writeSidecars.js +1 -1
- package/node_modules/@m0saic/core/dist/types/chunk.js +1 -1
- package/node_modules/@m0saic/core/dist/types/index.js +1 -1
- package/node_modules/@m0saic/core/dist/types/mosaic-plan.js +1 -1
- package/node_modules/@m0saic/core/dist/utils/assertTiming.js +1 -1
- package/node_modules/@m0saic/core/dist/utils/command.js +1 -1
- package/node_modules/@m0saic/core/dist/utils/createEngineContext.js +1 -1
- package/node_modules/@m0saic/core/dist/utils/createTemplateRenderCache.js +1 -1
- package/node_modules/@m0saic/core/dist/utils/ffmpegColor.js +1 -1
- package/node_modules/@m0saic/core/dist/utils/formatDuration.js +1 -1
- package/node_modules/@m0saic/core/dist/utils/fsSafeId.js +1 -1
- package/node_modules/@m0saic/core/dist/utils/index.js +1 -1
- package/node_modules/@m0saic/core/dist/utils/lowerRenderableToMosaicDocument.js +1 -1
- package/node_modules/@m0saic/core/dist/utils/movSafeCodec.js +1 -1
- package/node_modules/@m0saic/core/dist/utils/resolveBoxFrac.js +1 -1
- package/node_modules/@m0saic/core/dist/validate/index.js +1 -1
- package/node_modules/@m0saic/core/scripts/mask-rasterize-core.js +1 -1
- package/node_modules/@m0saic/core/scripts/mask-rasterize-worker.js +1 -1
- package/node_modules/@m0saic/core/scripts/mask-worker-thread.js +1 -1
- package/node_modules/@m0saic/dictionary/NOTICE +9 -0
- package/node_modules/@m0saic/dictionary/README.md +315 -0
- package/node_modules/@m0saic/dictionary/package.json +1 -1
- package/node_modules/@m0saic/dsl/package.json +1 -1
- package/node_modules/@m0saic/dsl-file-formats/dist/cjs/agent.js +6 -0
- package/node_modules/@m0saic/dsl-file-formats/dist/cjs/m0/parseM0File.js +1 -1
- package/node_modules/@m0saic/dsl-file-formats/dist/cjs/m0/serializeM0File.js +2 -2
- package/node_modules/@m0saic/dsl-file-formats/dist/cjs/m0c/m0cFile.js +3 -3
- package/node_modules/@m0saic/dsl-file-formats/dist/cjs/types.js +1 -1
- package/node_modules/@m0saic/dsl-file-formats/package.json +1 -1
- package/node_modules/@m0saic/dsl-stdlib/dist/cjs/builders/bakeM0cInsets.js +1 -0
- package/node_modules/@m0saic/dsl-stdlib/dist/cjs/builders/index.js +1 -1
- package/node_modules/@m0saic/dsl-stdlib/package.json +1 -1
- package/node_modules/@m0saic/knowledge/LICENSE +21 -0
- package/node_modules/@m0saic/knowledge/README.md +71 -0
- package/node_modules/@m0saic/knowledge/dist/index.js +1 -0
- package/node_modules/@m0saic/knowledge/docs/README.md +60 -0
- package/node_modules/@m0saic/knowledge/docs/file-formats/m0-iteration-protocol.md +120 -0
- package/node_modules/@m0saic/knowledge/docs/file-formats/m0p-and-custom-field.md +195 -0
- package/node_modules/@m0saic/knowledge/docs/handbook/README.md +27 -0
- package/node_modules/@m0saic/knowledge/docs/handbook/composition-arithmetic.md +278 -0
- package/node_modules/@m0saic/knowledge/docs/handbook/dsl-complexity.md +75 -0
- package/node_modules/@m0saic/knowledge/docs/handbook/dsl-rules.md +367 -0
- package/node_modules/@m0saic/knowledge/docs/handbook/feasibility-precision-quantization.md +591 -0
- package/node_modules/@m0saic/knowledge/docs/handbook/m0-construction-methods.md +201 -0
- package/node_modules/@m0saic/knowledge/docs/handbook/precision-tiers.md +84 -0
- package/node_modules/@m0saic/knowledge/docs/m0saic-thesis.md +95 -0
- package/node_modules/@m0saic/knowledge/docs/runtime/README.md +17 -0
- package/node_modules/@m0saic/knowledge/docs/runtime/cli-usage.md +447 -0
- package/node_modules/@m0saic/knowledge/docs/runtime/ffmpeg-expression-limits.md +117 -0
- package/node_modules/@m0saic/knowledge/docs/runtime/reduce-to-one.md +96 -0
- package/node_modules/@m0saic/knowledge/docs/skills/README.md +40 -0
- package/node_modules/@m0saic/knowledge/docs/skills/axis-and-geometry.md +103 -0
- package/node_modules/@m0saic/knowledge/docs/skills/dsl-stdlib-method-catalog.md +7 -0
- package/node_modules/@m0saic/knowledge/docs/skills/identity.md +123 -0
- package/node_modules/@m0saic/knowledge/docs/skills/labels-and-masks.md +170 -0
- package/node_modules/@m0saic/knowledge/docs/skills/m0saic-string-generation.md +251 -0
- package/node_modules/@m0saic/knowledge/docs/skills/more-atoms-not-bigger-atoms.md +77 -0
- package/node_modules/@m0saic/knowledge/docs/skills/overlay-semantics.md +194 -0
- package/node_modules/@m0saic/knowledge/docs/skills/parse-apis.md +79 -0
- package/node_modules/@m0saic/knowledge/docs/skills/passthrough-semantics.md +136 -0
- package/node_modules/@m0saic/knowledge/docs/skills/structural-construction.md +86 -0
- package/node_modules/@m0saic/knowledge/docs/skills/text-in-templates.md +126 -0
- package/node_modules/@m0saic/knowledge/docs/skills/zero-overlay-analysis.md +87 -0
- package/node_modules/@m0saic/knowledge/docs/templates/README.md +65 -0
- package/node_modules/@m0saic/knowledge/docs/templates/capability-templates.md +72 -0
- package/node_modules/@m0saic/knowledge/docs/templates/construction-strategy.md +329 -0
- package/node_modules/@m0saic/knowledge/docs/templates/data-pipeline.md +324 -0
- package/node_modules/@m0saic/knowledge/docs/templates/emission-patterns.md +130 -0
- package/node_modules/@m0saic/knowledge/docs/templates/geometry-recipes.md +248 -0
- package/node_modules/@m0saic/knowledge/docs/templates/layout-contract.md +168 -0
- package/node_modules/@m0saic/knowledge/docs/templates/output-resolution-tree.md +202 -0
- package/node_modules/@m0saic/knowledge/docs/templates/patterns/case-study-lessons.md +69 -0
- package/node_modules/@m0saic/knowledge/docs/templates/patterns/perf-authoring-rules.md +100 -0
- package/node_modules/@m0saic/knowledge/docs/templates/patterns/primitive-extraction-pattern.md +103 -0
- package/node_modules/@m0saic/knowledge/docs/templates/philosophy-and-contract.md +310 -0
- package/node_modules/@m0saic/knowledge/docs/templates/recursion-nested-rendering.md +154 -0
- package/node_modules/@m0saic/knowledge/docs/templates/reference/grid.md +104 -0
- package/node_modules/@m0saic/knowledge/docs/templates/reference/json-prop-type.md +169 -0
- package/node_modules/@m0saic/knowledge/docs/templates/reference/mosaic-color.md +81 -0
- package/node_modules/@m0saic/knowledge/docs/templates/reference/mosaic-placement-props.md +103 -0
- package/node_modules/@m0saic/knowledge/docs/templates/reference/prop-bindings.md +324 -0
- package/node_modules/@m0saic/knowledge/docs/templates/reference/template-flags.md +224 -0
- package/node_modules/@m0saic/knowledge/docs/templates/render-lifecycle.md +117 -0
- package/node_modules/@m0saic/knowledge/docs/templates/rendering-model-contract.md +392 -0
- package/node_modules/@m0saic/knowledge/docs/templates/standalone-pack-authoring.md +299 -0
- package/node_modules/@m0saic/knowledge/docs/templates/theming.md +81 -0
- package/node_modules/@m0saic/knowledge/docs/templates/ui-controls.md +150 -0
- package/node_modules/@m0saic/knowledge/package.json +6 -0
- package/node_modules/@m0saic/momo-types/README.md +109 -0
- package/node_modules/@m0saic/momo-types/dist/agent.js +1 -6
- package/node_modules/@m0saic/momo-types/dist/context.js +1 -1
- package/node_modules/@m0saic/momo-types/package.json +1 -1
- package/node_modules/@m0saic/platform/README.md +3 -0
- package/node_modules/@m0saic/platform/dist/cjs/index.js +1 -1
- package/node_modules/@m0saic/platform/dist/cjs/mosaic/outputKind/outputKind.js +1 -1
- package/node_modules/@m0saic/platform/dist/cjs/mosaic/propBindings/index.js +1 -1
- package/node_modules/@m0saic/platform/dist/cjs/mosaic/propBindings/propBindings.js +1 -1
- package/node_modules/@m0saic/platform/dist/cjs/mosaic/validate/validateSources.js +1 -1
- package/node_modules/@m0saic/platform/dist/cjs/packages/mosaicPackages.js +1 -0
- package/node_modules/@m0saic/platform/dist/cjs/paths/m0saicRoot.js +1 -1
- package/node_modules/@m0saic/platform/dist/cjs/telemetry/lifecycle.js +1 -1
- package/node_modules/@m0saic/platform/dist/cjs/telemetry/preview.js +1 -1
- package/node_modules/@m0saic/platform/dist/cjs/telemetry/sender.js +1 -1
- package/node_modules/@m0saic/platform/dist/cjs/telemetry/usageRecorder.js +1 -1
- package/node_modules/@m0saic/platform/dist/cjs/telemetry/usageStore.js +3 -3
- package/node_modules/@m0saic/platform/dist/cjs/toolchain/ffmpeg/baseline.json +25 -97
- package/node_modules/@m0saic/platform/dist/cjs/toolchain/ffmpeg/index.js +1 -1
- package/node_modules/@m0saic/platform/dist/cjs/toolchain/ffmpeg/install.js +2 -2
- package/node_modules/@m0saic/platform/dist/cjs/toolchain/goldenFfmpeg.js +6 -6
- package/node_modules/@m0saic/platform/package.json +1 -1
- package/node_modules/@m0saic/product/dist/communityRelease.js +1 -1
- package/node_modules/@m0saic/product/dist/freeTierLicense.js +1 -1
- package/node_modules/@m0saic/product/dist/index.js +1 -1
- package/node_modules/@m0saic/product/dist/licenseActivationNotice.js +1 -0
- package/node_modules/@m0saic/product/dist/licenseFile.js +1 -0
- package/node_modules/@m0saic/product/dist/licenseToken.js +1 -1
- package/node_modules/@m0saic/product/dist/makeScratchPath.js +1 -0
- package/node_modules/@m0saic/product/dist/postRenderWrapper.js +1 -1
- package/node_modules/@m0saic/product/dist/publicKeys.js +1 -1
- package/node_modules/@m0saic/product/dist/revokedKeys.js +1 -1
- package/node_modules/@m0saic/product/dist/upstreamDefaults.js +1 -1
- package/node_modules/@m0saic/product/dist/workspaceScaffold.js +1 -0
- package/node_modules/@m0saic/template-utils/dist/brand/hello-world/helloWorld.js +1 -1
- package/node_modules/@m0saic/template-utils/dist/geometry-contract/index.js +1 -1
- package/node_modules/@m0saic/template-utils/dist/geometry-contract/layoutConstraint.js +2 -2
- package/node_modules/@m0saic/template-utils/dist/m0saic/loadSession.js +1 -1
- package/node_modules/@m0saic/template-utils/dist/render/createDesignContext.js +1 -1
- package/node_modules/@m0saic/template-utils/dist/sources/makeErrorMosaic.js +2 -2
- package/node_modules/@m0saic/template-utils/dist/sources/svgTextSource.js +1 -1
- package/node_modules/@m0saic/template-utils/dist/template/auditRenderedTemplate.js +5 -5
- package/node_modules/@m0saic/template-utils/dist/template/templateConventions.js +3 -3
- package/node_modules/@m0saic/template-utils/dist/template/validateTemplateProps.js +1 -1
- package/node_modules/@m0saic/template-utils/dist/text/fitText.js +6 -6
- package/node_modules/@m0saic/template-utils/package.json +1 -1
- package/node_modules/@m0saic/templates/NOTICE +9 -0
- package/node_modules/@m0saic/templates/dist/m0saic/media/blur-regions/v1/tutorial.js +1 -1
- package/node_modules/@m0saic/templates/package.json +1 -1
- package/node_modules/@m0saic/templates-advanced/NOTICE +9 -0
- package/node_modules/@m0saic/text/package.json +1 -1
- package/node_modules/@m0saic/types/dist/analytics/consent.js +1 -1
- package/node_modules/@m0saic/types/dist/analytics/event.js +1 -1
- package/node_modules/@m0saic/types/dist/analytics/usageMetrics.js +1 -1
- package/node_modules/@m0saic/types/dist/identifiers/identifiers.js +1 -1
- package/node_modules/@m0saic/types/dist/telemetry/ffmpegFailure.js +1 -1
- package/node_modules/@m0saic/types/package.json +1 -1
- package/node_modules/@m0saic/types-internal/dist/analytics/featureKeys.js +1 -1
- package/package.json +13 -11
- package/resources/starter-base/starter-base.json +10 -0
- 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,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.
|