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,117 @@
|
|
|
1
|
+
# Template render lifecycle — the four entry points
|
|
2
|
+
|
|
3
|
+
`render` is required. The other three are optional, opt-in, and **editor-only** —
|
|
4
|
+
none of them is ever on the `m0saic make` / CLI path.
|
|
5
|
+
|
|
6
|
+
> **Source of truth:** the four members + their JSDoc in
|
|
7
|
+
> [https://github.com/m0saic-project/m0saic-packages/blob/main/packages/types/src/template/template.ts](https://github.com/m0saic-project/m0saic-packages/blob/main/packages/types/src/template/template.ts);
|
|
8
|
+
> the wrapper in https://github.com/m0saic-project/m0saic-packages/blob/main/packages/template-utils/src/template/defineMosaicTemplate.ts;
|
|
9
|
+
> the dispatch helpers in https://github.com/m0saic-project/m0saic-packages/blob/main/packages/template-utils/src/render/renderTemplate{Lite,Cover,Tutorial}.ts`;
|
|
10
|
+
> the shipped exemplar https://github.com/m0saic-project/m0saic-packages/blob/main/packages/templates/src/m0saic/media/screencap_grid/v2.
|
|
11
|
+
|
|
12
|
+
| Function | Who calls it | When absent |
|
|
13
|
+
|---|---|---|
|
|
14
|
+
| `render` | the engine, for real output | — (required) |
|
|
15
|
+
| `renderLite` | preview hosts, on the design hot path | falls back to `render` |
|
|
16
|
+
| `renderCover` | the editor, on a pure-default first open | **nothing happens** |
|
|
17
|
+
| `renderTutorial` | the editor, when the user clicks the "?" pill | **nothing happens** |
|
|
18
|
+
|
|
19
|
+
Tier is orthogonal. A core-tier template may declare any of the three optional
|
|
20
|
+
members; `renderLite`'s *capability* rationale (and the RenderHero wiring that
|
|
21
|
+
goes with it) lives in
|
|
22
|
+
[`capability-templates.md`](capability-templates.md).
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## The dispatch asymmetry (the thing to get right)
|
|
27
|
+
|
|
28
|
+
`renderTemplateLite(tmpl, props, ctx)` falls back to `render` — historical
|
|
29
|
+
behavior, and correct: a preview must always show *something*.
|
|
30
|
+
|
|
31
|
+
`renderTemplateCover` / `renderTemplateTutorial` return `null` and **never** fall
|
|
32
|
+
back. Absence means "behave exactly as before this feature existed". Hosts must
|
|
33
|
+
not synthesize a generic cover or tutorial; the seam encodes that so no host has
|
|
34
|
+
to remember it.
|
|
35
|
+
|
|
36
|
+
Copying the `renderLite` helper when adding the next surface is the mistake to
|
|
37
|
+
avoid — it silently re-introduces "every template gets a cover", which is
|
|
38
|
+
precisely what the opt-in design forbids.
|
|
39
|
+
|
|
40
|
+
## Error semantics differ per surface, on purpose
|
|
41
|
+
|
|
42
|
+
- **Cover** error or absence → `null` → the host falls through to its normal
|
|
43
|
+
preview path, silently. An error card *about the cover* would recreate the
|
|
44
|
+
broken-first-impression problem the cover exists to fix.
|
|
45
|
+
- **Tutorial** error → `makeErrorMosaic`, rendered inside the tutorial view. The
|
|
46
|
+
user explicitly clicked; a silent no-op reads as a dead button.
|
|
47
|
+
|
|
48
|
+
Both hosts (the Mosaic Desktop / Web app source (not published),
|
|
49
|
+
the Mosaic Desktop / Web app source (not published)) implement this pair
|
|
50
|
+
identically. The desktop bridge methods are **optional** on the channel, so an
|
|
51
|
+
older shell paired with newer web code degrades to "no cover, no pill" rather
|
|
52
|
+
than throwing.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Authoring checklist
|
|
57
|
+
|
|
58
|
+
- **Deterministic and side-effect-free.** No `Date.now`, no `Math.random`.
|
|
59
|
+
- **Browser-safe** if the template ships in https://github.com/m0saic-project/m0saic-packages/blob/main/packages/templates/src/web.ts — no
|
|
60
|
+
node-only imports.
|
|
61
|
+
- **Never read `ctx.media`.** Both hosts pass `{}` (no ffprobe pass), so these
|
|
62
|
+
surfaces are self-contained by contract.
|
|
63
|
+
- **Size to `ctx.target`.** It carries the editor's canvas dimensions.
|
|
64
|
+
- **Real geometry.** A cover page's bands and a tutorial's diagram are known
|
|
65
|
+
rects — carve m0 cells, don't float drawtext over a full-canvas source. The
|
|
66
|
+
Rect Thesis does not get a pass for onboarding content (see
|
|
67
|
+
[`construction-strategy.md`](construction-strategy.md), "Hard rule: real
|
|
68
|
+
geometry first").
|
|
69
|
+
- **ASCII-only copy.** drawtext renders `→ · — ×` from the bundled font as tofu
|
|
70
|
+
— the same reason `makeErrorMosaic` runs an `asciiOnly()` pass. See
|
|
71
|
+
[`../skills/text-in-templates.md`](../skills/text-in-templates.md).
|
|
72
|
+
- **A tutorial owns its timing.** Declare per-step `durationMs`; never read
|
|
73
|
+
`ctx.target.durationMs`. The host passes no form duration, and a tutorial is
|
|
74
|
+
watched, not rendered into a window.
|
|
75
|
+
- **Invocation props**: the tutorial gets the template's OWN `defaultProps`
|
|
76
|
+
(stable regardless of editor state); the cover gets the working props, which at
|
|
77
|
+
the only moment it shows ARE the defaults — so a cover may ignore props
|
|
78
|
+
entirely.
|
|
79
|
+
- `defineMosaicTemplate` wraps all three with the **capability gate ONLY** — no
|
|
80
|
+
autoCompact, no stamping, no `assertTiming`. Ephemeral preview material, like
|
|
81
|
+
`renderLite`. (Stamping a tutorial would be actively wrong: it declares its own
|
|
82
|
+
per-step durations.)
|
|
83
|
+
- **No new CLI E2E case.** These are unit-tested; they never reach `m0saic make`.
|
|
84
|
+
Same posture as `renderLite`.
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Host lifecycle (the Make page)
|
|
89
|
+
|
|
90
|
+
- The cover shows iff `hasRenderCover && !coverDismissed`. `coverDismissed`
|
|
91
|
+
starts `true`, is set at template load from "did this open carry
|
|
92
|
+
caller-supplied props" (so `m0saic open --props` skips the cover), and is
|
|
93
|
+
flipped permanently by the first user prop edit. Deliberately **not** derived
|
|
94
|
+
from `props === defaults` — edit-then-undo must not resurrect it.
|
|
95
|
+
- A cover is a **stand-in**, like a `renderLite` card: it must stay out of the
|
|
96
|
+
render-progress hero filmstrip. Note a template can have a cover *without* a
|
|
97
|
+
`renderLite`, so a hero guard written against `hasRenderLite` alone misses it.
|
|
98
|
+
- The tutorial substitutes only the STAGE (a `stageRenderable` + a
|
|
99
|
+
`tutorial:<id>` doc key). The real document keeps feeding save, geometry-edit,
|
|
100
|
+
doc-stats, and `renderRequest`, so view-only holds by construction rather than
|
|
101
|
+
by discipline — the Make button always renders the real template.
|
|
102
|
+
|
|
103
|
+
## Meta flags
|
|
104
|
+
|
|
105
|
+
`templates:get` reports `hasRenderLite` / `hasRenderCover` / `hasRenderTutorial`,
|
|
106
|
+
with field-for-field parity in the web `getTemplate` and in the `TemplateMeta`
|
|
107
|
+
type. UI affordances gate on these flags, never on making the call and seeing
|
|
108
|
+
what comes back.
|
|
109
|
+
|
|
110
|
+
## Exemplar
|
|
111
|
+
|
|
112
|
+
`@m0saic/media/screencap_grid/v2` — `screencap-grid-cover.ts` (a weighted band
|
|
113
|
+
split) and `screencap-grid-tutorial.ts` (six pages, two of them real diagrams:
|
|
114
|
+
an actual gutter-separated 4×4 grid, and an actual pane band over chipped tiles).
|
|
115
|
+
Its `render` keeps its zero-input `makeErrorMosaic` fail-fast contract untouched
|
|
116
|
+
— that is the point. The cover exists so the fail-fast contract can stay strict
|
|
117
|
+
without costing the template its first impression.
|
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
# Rendering-model contract
|
|
2
|
+
|
|
3
|
+
**Anchor doc for the 12-rule contract spanning `MosaicDocument`, `MosaicDocumentPipeline`, `MosaicOutputEncode`, `MosaicEngineContext`, the engine planner, and the CLI.**
|
|
4
|
+
|
|
5
|
+
Verified against (at promotion time, 2026-05-15):
|
|
6
|
+
- https://github.com/m0saic-project/m0saic-packages/blob/main/packages/types/src/document/document.ts (MosaicDocument)
|
|
7
|
+
- https://github.com/m0saic-project/m0saic-packages/blob/main/packages/types/src/document/document-pipeline.ts (MosaicDocumentPipeline, PipelineStepBase)
|
|
8
|
+
- https://github.com/m0saic-project/m0saic-packages/blob/main/packages/types/src/output/encode.ts (MosaicOutputEncode)
|
|
9
|
+
- https://github.com/m0saic-project/m0saic-packages/blob/main/packages/types/src/output/format.ts / `audio-config.ts` / `color-config.ts` / `container-metadata.ts` / `target.ts` (sub-field types)
|
|
10
|
+
- https://github.com/m0saic-project/m0saic-packages/blob/main/packages/types/src/engine-context/engine-context.ts (MosaicEngineContext)
|
|
11
|
+
- https://github.com/m0saic-project/m0saic-packages/blob/main/packages/types/src/document/pipeline-helpers.ts (helpers + predicates)
|
|
12
|
+
- the render engine source (not published) (planner)
|
|
13
|
+
- the render engine source (not published) (output-format precedence chain)
|
|
14
|
+
- the render engine source (not published) (ctx assembly)
|
|
15
|
+
- the render engine source (not published) (multi-encode transcode passes)
|
|
16
|
+
- the render engine source (not published) (workspace + multi-output handling)
|
|
17
|
+
- the CLI source (not published) (capability fixtures gating each rule)
|
|
18
|
+
- the CLI source (not published) (E2E gate)
|
|
19
|
+
- the render engine source (not published) (visual gate)
|
|
20
|
+
|
|
21
|
+
## Core architectural insights
|
|
22
|
+
|
|
23
|
+
Two facts drive the whole contract:
|
|
24
|
+
|
|
25
|
+
1. **A `MosaicDocument` has exactly one `m0` string → exactly one geometry.** Width, height, fps, durationMs, target preset, format, audio, color, metadata, backgroundColor are properties of the *one render* the doc describes. A doc cannot have "multiple outputs at different geometries"; that's a contradiction with one `m0`.
|
|
26
|
+
|
|
27
|
+
2. **A `MosaicDocumentPipeline` is a sequence of `MosaicDocument`s, each with their own `m0`.** Multi-geometry is therefore a natural property of pipelines (not just of `emit:"multi"`). Different steps can have different canvases; in `emit:"single"` the engine concatenates them onto one pipeline-level canvas (letterbox / element-wise-max default), in `emit:"multi"` each step emits its own file at its own canvas.
|
|
28
|
+
|
|
29
|
+
The shape of the types reflects this directly: output knobs are flattened onto Document and Pipeline (no map of "named outputs"), and multi-encode is a separate top-level field.
|
|
30
|
+
|
|
31
|
+
## Shape
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
type MosaicDocument = {
|
|
35
|
+
kind: "mosaic_document";
|
|
36
|
+
version: 1;
|
|
37
|
+
m0: M0String;
|
|
38
|
+
assets: MosaicAssetManifest;
|
|
39
|
+
sources: MosaicSource[];
|
|
40
|
+
children?: Record<string, MosaicRenderable>;
|
|
41
|
+
meta?: MosaicFileMeta;
|
|
42
|
+
labels?: ...; // out of rendering-model scope
|
|
43
|
+
variables?: ...; sidecars?: ...;
|
|
44
|
+
editor?: ...; engine?: ...;
|
|
45
|
+
created?: string; app?: ...; appVersion?: ...;
|
|
46
|
+
|
|
47
|
+
// -- Rendering-model output knobs (one config per doc) --
|
|
48
|
+
size?: { width: number; height: number };
|
|
49
|
+
fps?: number;
|
|
50
|
+
durationMs?: number;
|
|
51
|
+
target?: MosaicOutputTarget;
|
|
52
|
+
format?: MosaicOutputFormat;
|
|
53
|
+
audio?: MosaicAudioConfig;
|
|
54
|
+
color?: MosaicColorConfig;
|
|
55
|
+
metadata?: MosaicContainerMetadata;
|
|
56
|
+
backgroundColor?: MosaicColor;
|
|
57
|
+
|
|
58
|
+
// -- Multi-deliverable transcode pass (post-render) --
|
|
59
|
+
encodes?: Record<string, MosaicOutputEncode>;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
type MosaicDocumentPipeline = {
|
|
63
|
+
kind: "mosaic_pipeline";
|
|
64
|
+
version: 1;
|
|
65
|
+
steps: MosaicPipelineStep[];
|
|
66
|
+
defaultTransition?: MosaicPipelineTransition;
|
|
67
|
+
meta?: ...; created?: ...; app?: ...; appVersion?: ...;
|
|
68
|
+
variables?: ...; sidecars?: ...;
|
|
69
|
+
editor?: ...; engine?: ...;
|
|
70
|
+
|
|
71
|
+
// -- Rendering-model output knobs (one config per pipeline) --
|
|
72
|
+
size?: { width: number; height: number };
|
|
73
|
+
fps?: number;
|
|
74
|
+
durationMs?: number;
|
|
75
|
+
target?: MosaicOutputTarget;
|
|
76
|
+
format?: MosaicOutputFormat;
|
|
77
|
+
audio?: MosaicAudioConfig;
|
|
78
|
+
color?: MosaicColorConfig;
|
|
79
|
+
metadata?: MosaicContainerMetadata;
|
|
80
|
+
backgroundColor?: MosaicColor;
|
|
81
|
+
|
|
82
|
+
// -- Pipeline-specific --
|
|
83
|
+
emit?: "single" | "multi"; // single = concat to 1 file; multi = N files
|
|
84
|
+
|
|
85
|
+
encodes?: Record<string, MosaicOutputEncode>;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
type MosaicOutputEncode = {
|
|
89
|
+
size?: { width: number; height: number }; // optional ffmpeg `scale` (stretches)
|
|
90
|
+
format?: MosaicOutputFormat;
|
|
91
|
+
audio?: MosaicAudioConfig;
|
|
92
|
+
color?: MosaicColorConfig;
|
|
93
|
+
metadata?: MosaicContainerMetadata;
|
|
94
|
+
// NOT settable: fps, durationMs, target, emit (inherited from master)
|
|
95
|
+
};
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
The `outputs: Record<string, MosaicOutput>` map and the `MosaicOutput` type are **gone**.
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Rule 1 — Top-level return types
|
|
103
|
+
|
|
104
|
+
A template returns exactly one of:
|
|
105
|
+
|
|
106
|
+
MosaicDocument | MosaicDocumentPipeline
|
|
107
|
+
|
|
108
|
+
- `MosaicDocument` → always exactly 1 master render at 1 geometry.
|
|
109
|
+
- `MosaicDocumentPipeline` → a sequence of documents, possibly with different geometries.
|
|
110
|
+
|
|
111
|
+
Runtime discrimination: `isPipelineFile()` / `isDocumentFile()`.
|
|
112
|
+
|
|
113
|
+
## Rule 2 — Pipeline emit mode
|
|
114
|
+
|
|
115
|
+
A pipeline declares `emit?: "single" | "multi"` (default `"single"`).
|
|
116
|
+
|
|
117
|
+
- `"single"` → render every step, concatenate the output-steps into 1 video. Step geometries reconcile to the pipeline's canvas (explicit `pipeline.size`, or element-wise max of step canvases).
|
|
118
|
+
- `"multi"` → render every step, emit each output-step as its own file at its own step's geometry. **Top-level only**: nested pipelines silently downgrade to `"single"` (`PIPELINE_EMIT_MULTI_DOWNGRADED`).
|
|
119
|
+
|
|
120
|
+
The relevant fan-out test:
|
|
121
|
+
|
|
122
|
+
isMultiOutputCapable = pipeline is top-level
|
|
123
|
+
&& emit === "multi"
|
|
124
|
+
&& outputStepCount > 1
|
|
125
|
+
|
|
126
|
+
## Rule 3 — Step model
|
|
127
|
+
|
|
128
|
+
Each pipeline step:
|
|
129
|
+
|
|
130
|
+
- has `durationMs: number` — exact rendered length.
|
|
131
|
+
- may carry `intermediate?: boolean` (default `false`).
|
|
132
|
+
- may carry `name?: string` — friendly-slug used for filename basis under `emit:"multi"` and for CLI per-step addressing. Falls back to `step-{index}`.
|
|
133
|
+
- may carry `label?: string` — template-author hint for `{{label}}` token in the CLI's `--output-pattern` (e.g. the user-supplied input filename when a template fans 1→N variants).
|
|
134
|
+
|
|
135
|
+
Derived:
|
|
136
|
+
|
|
137
|
+
outputSteps = steps.filter(s => !s.intermediate)
|
|
138
|
+
outputCount = outputSteps.length
|
|
139
|
+
|
|
140
|
+
At least one step must be non-intermediate (`PIPELINE_NO_OUTPUT_STEPS` otherwise).
|
|
141
|
+
|
|
142
|
+
## Rule 4 — Pipeline execution
|
|
143
|
+
|
|
144
|
+
**Top-level pipeline:**
|
|
145
|
+
- Renders all steps (intermediates included — they back ref-sources).
|
|
146
|
+
- `emit:"single"` → concat output-steps; pipeline-level output knobs govern the concat canvas + final format.
|
|
147
|
+
- `emit:"multi"` → each output-step emits its own file at its own step's canvas. Pipeline-level knobs are mostly inert for canvas/fps/duration (steps win); pipeline-level `encodes` apply to **each** emitted file.
|
|
148
|
+
|
|
149
|
+
Each step renders at its own declared `step.file.size`; the pipeline-level / CLI `-w/-h` target is the default canvas, used only when a step doesn't declare its own (`buildMosaicPlanFromFile.ts` step loop).
|
|
150
|
+
|
|
151
|
+
**Per-cell tap intermediates (Phase 3c.4).** When a `media`-source cell is the target of one or more `MosaicRefSource`s, the planner emits an additional per-cell `.mov` render (the "tap") via `tapNodeIdFor(stepIndex, flattenedStableKey)`. The tap captures that cell's post-decoration, pre-composite pixel stream; ref consumers (same-doc and cross-step) read from it. Cells that aren't ref targets are unaffected — the tap is opt-in via a pre-pass (`collectRefTargets`) that scans the whole renderable once before plan-build. `text` and `mosaic` ref targets reuse their existing per-cell intermediates; `lavfi` ref targets re-emit the same lavfi expression at the consumer (hash-deduped by graph string).
|
|
152
|
+
|
|
153
|
+
**Nested pipeline** (appears in a parent's `children`):
|
|
154
|
+
- Must produce exactly one clip for the parent slot's effective duration `T`.
|
|
155
|
+
- Engine sums step durations to meet `T`; trims last step; falls back to embedding source's `MosaicPlaybackProps.loopMode` (`"loop"` / `"freeze"` / `"cut"`) when the pipeline is shorter.
|
|
156
|
+
- Per-step canvases are overridden under nesting; parent slot's canvas wins (`PIPELINE_NESTED_CANVAS_COLLAPSED`).
|
|
157
|
+
- `emit:"multi"` silently downgrades to `"single"`.
|
|
158
|
+
|
|
159
|
+
## Rule 5 — Output resolution (single render)
|
|
160
|
+
|
|
161
|
+
Applies to:
|
|
162
|
+
- `MosaicDocument` (always — a doc is always one render).
|
|
163
|
+
- `MosaicDocumentPipeline` with `emit:"single"` or `outputCount === 1` (the pipeline produces one concatenated file).
|
|
164
|
+
|
|
165
|
+
Each output field resolves via a **3-tier chain** (highest first):
|
|
166
|
+
|
|
167
|
+
1. User intent (CLI flags + .m0v defaults, assembled by the CLI)
|
|
168
|
+
2. Template intent (the fields set on doc / pipeline by render())
|
|
169
|
+
3. Engine default (target preset → engine hardcoded defaults)
|
|
170
|
+
|
|
171
|
+
`.m0v` is CLI-consumed default user input — not part of the template/engine contract. Templates never read `.m0v` files. The CLI loads `.m0v` (when supplied) and uses its named output presets as the User tier's default layer; CLI flags override `.m0v` defaults within the same tier; the merged result is the User tier for the document/pipeline.
|
|
172
|
+
|
|
173
|
+
### Rule 5b — Size off `ctx.target`, never `ctx.output`
|
|
174
|
+
|
|
175
|
+
**`ctx.target.{width,height}` is THIS template's canvas. `ctx.output` is the top-level
|
|
176
|
+
render envelope.** They are not the same thing once a template is nested.
|
|
177
|
+
|
|
178
|
+
| | `ctx.target` | `ctx.output` |
|
|
179
|
+
|---|---|---|
|
|
180
|
+
| Means | the canvas *this* template is drawing into | the root render's envelope (codec / container / pixel format + root dims) |
|
|
181
|
+
| Top level | identical to `ctx.output` | identical to `ctx.target` |
|
|
182
|
+
| Nested via `renderNestedTemplate(id, props, ctx, { slot })` | **the slot** (e.g. 640×216) | **still the parent root** (e.g. 1920×1080) |
|
|
183
|
+
|
|
184
|
+
`renderNestedTemplate` deliberately overrides **only** `ctx.target`
|
|
185
|
+
(https://github.com/m0saic-project/m0saic-packages/blob/main/packages/template-utils/src/render/renderNestedTemplate.ts — `fps` and `durationMs`
|
|
186
|
+
default to the parent's target too). Time already comes from `ctx.target.durationMs` by
|
|
187
|
+
convention; **size must come from `ctx.target` for the same reason.**
|
|
188
|
+
|
|
189
|
+
**Use `ctx.target` for:**
|
|
190
|
+
- font sizes — `Math.round(ctx.target.height * FRAC)`
|
|
191
|
+
- px → fraction conversions
|
|
192
|
+
- `makeErrorMosaic` / `makeStubMosaic` dimensions
|
|
193
|
+
|
|
194
|
+
**Use `ctx.output` only for** format / codec / alpha decisions — never geometry.
|
|
195
|
+
|
|
196
|
+
#### ⚠️ Why this hides
|
|
197
|
+
|
|
198
|
+
At top level `ctx.target === ctx.output`, so a template that reads `ctx.output` looks
|
|
199
|
+
completely correct — every standalone render, every preview, every golden. The bug
|
|
200
|
+
appears **only** when someone composes it: the child sizes to the parent's canvas and
|
|
201
|
+
blows out of its cell. `stat-card` rendered ~5× too large this way.
|
|
202
|
+
|
|
203
|
+
That means **a passing test suite is not evidence.** The check is a grep, not a render:
|
|
204
|
+
|
|
205
|
+
```
|
|
206
|
+
grep -rn "ctx.output.width\|ctx.output.height" https://github.com/m0saic-project/m0saic-packages/blob/main/packages/templates/src
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
Every hit is either an error-card dimension (should be `ctx.target`) or geometry (must
|
|
210
|
+
be `ctx.target`). As of 2026-07-26 this still returns hits across ~23 template files —
|
|
211
|
+
including `charts/donut/v4`, which is `primitive: true` (i.e. explicitly meant to be
|
|
212
|
+
composed) and sets `const W = ctx.output.width` for its entire layout. Latent today
|
|
213
|
+
because nothing nests it in-repo; a live 5× bug the moment something does.
|
|
214
|
+
|
|
215
|
+
## Rule 6 — Multi-output (pipelines only)
|
|
216
|
+
|
|
217
|
+
Multi-output happens only when a top-level pipeline has `emit:"multi"` and more than one output-step. There is no multi-output for individual documents (one m0 = one geometry).
|
|
218
|
+
|
|
219
|
+
Rules:
|
|
220
|
+
- The template authors a pipeline with N output-steps; each step is its own `MosaicDocument` with its own geometry.
|
|
221
|
+
- The engine emits N files, named by `step.name` (or `step-{index}` fallback): `{base}-{stepName}.{ext}`.
|
|
222
|
+
- Pipeline-level `encodes` apply to each emitted file (each file → N transcoded variants).
|
|
223
|
+
- User intent (`ctx.userIntent.outputs`) is surfaced to templates that want to map presets to specific steps (rule 8).
|
|
224
|
+
|
|
225
|
+
## Rule 7 — Exact per-output override
|
|
226
|
+
|
|
227
|
+
Special case for pipeline `emit:"multi"`:
|
|
228
|
+
|
|
229
|
+
if (Object.keys(userIntent.outputs).length === outputStepCount)
|
|
230
|
+
|
|
231
|
+
Then user overrides are applied **positionally** to each output-step (joined by index, not name). This overrides whatever the template authored on each step's MosaicDocument output fields. The CLI also emits an `OUTPUT_NAME_NOT_FOUND` warning per stale key when the user's keys drift from the template's step names — the override still fires (because count matched), but the warning surfaces the drift.
|
|
232
|
+
|
|
233
|
+
## Rule 8 — Preset semantics
|
|
234
|
+
|
|
235
|
+
The user can supply (via CLI flags directly, or via `.m0v` defaults the CLI loads):
|
|
236
|
+
- A default output config.
|
|
237
|
+
- Named presets (e.g. `"desktop"`, `"mobile"`, `"alpha-master"`).
|
|
238
|
+
|
|
239
|
+
Behavior:
|
|
240
|
+
- **Single render (document, or pipeline emit:single)** → presets resolve directly through the 3-tier chain (rule 5). Only one preset's worth of fields is actually applied.
|
|
241
|
+
- **Multi render (pipeline emit:multi)** → presets are input to the template via `ctx.userIntent.outputs`. The template decides how to map preset names onto its own step `name`s. The exact-override path (rule 7) is the only hard-override.
|
|
242
|
+
|
|
243
|
+
## Rule 9 — Intermediate steps + back-edge refs
|
|
244
|
+
|
|
245
|
+
Steps with `intermediate: true`:
|
|
246
|
+
- DO render. The engine produces a real video file in `workspaceDir`.
|
|
247
|
+
- The workspace file is deleted at the end of the render job — not delivered to the user.
|
|
248
|
+
- ARE available to later steps via `MosaicRefSource` (back-edge invariant; see below).
|
|
249
|
+
- Do NOT count toward `outputCount`.
|
|
250
|
+
- Are NOT concatenated under `emit:"single"`.
|
|
251
|
+
- Are NOT exposed as per-file under `emit:"multi"`.
|
|
252
|
+
- Their `transitionToNext` is ignored.
|
|
253
|
+
|
|
254
|
+
**`MosaicRefSource` scope (post-3c.4).** Refs are back-edge mirrors of another cell's pixels. They work in both directions intermediate steps unlock — but the surface is broader than pipelines:
|
|
255
|
+
|
|
256
|
+
- **Locality**: same-document (`stepIndex` omitted) AND cross-step (`stepIndex` set; must be strictly earlier).
|
|
257
|
+
- **Targets**: any cell that produces pixels — `media`, `text`, `mosaic`, top-level same-doc `lavfi`, and overlay frames (`r/.../ovNcN`). Inner cells of nested mosaics resolve at any depth via `flattenedStableKey` (e.g. `r/gcolc0/fc1`, `r/growc0/fc0`).
|
|
258
|
+
- **Not targets**: `data` sources (structurally hidden from layout), other ref sources (chains — editor flattens them; engine rejects with `MOSAIC_REF_TARGET_NOT_SUPPORTED`), cross-step lavfi (deferred — same code emits `MOSAIC_REF_TARGET_NOT_SUPPORTED` and falls back to placeholder).
|
|
259
|
+
- **Matrix normalization**: when the ref's slot dims / fps / duration / pixfmt differ from the target's, the consumer's own filter chain inserts `scale=` / `fps=` / `setpts=` / `format=` to bridge. Ref's own `placement` / `playback` / `effects` / `mask` then apply on top.
|
|
260
|
+
|
|
261
|
+
Use case: a "header strip" rendered once into workspace, referenced from multiple downstream steps for pixel reuse. Or: a hero clip rendered in step 0 echoed at a different size in step 3 with audio sync preserved. Or: a same-doc overlay frame reused as the visual content of another cell.
|
|
262
|
+
|
|
263
|
+
### Note — `MosaicRefSource` lavfi-target gap (v1)
|
|
264
|
+
|
|
265
|
+
Lavfi ref targets have a narrower v1 surface than the other source kinds: they resolve only when the target cell is at the root of the same doc (`descendPath.length === 0`). Refs to lavfi cells at deeper nesting silently fall back to black placeholders with a `MOSAIC_REF_TARGET_NOT_SUPPORTED` warning — only surfaced in `--validate-only` or `--report` output. Media / mosaic / text-with-image-render-mode targets all walk nested depth fine (see the `ref-same-doc-multi-level-inner-cell` and `ref-cross-step-nested-inner-cell` fixtures).
|
|
266
|
+
|
|
267
|
+
For "one solid colour reused across many cells", prefer N independent `MosaicLavfiSource` entries — ffmpeg's `color=` generator is essentially free, so the ref optimization has no payoff there. Reserve refs for targets with a real intermediate to share (media files, text-as-image PNGs, nested mosaics).
|
|
268
|
+
|
|
269
|
+
If a use case for nested-lavfi refs surfaces (e.g. mirroring a complex procedural gradient across deep cells), the gate at the render engine source (not published) is where the resolver is deferred. Verify with: `grep -nE "descendPath\.length > 0" the render engine source (not published).
|
|
270
|
+
|
|
271
|
+
### Solid-colour tile sources — use `makeColorTile`
|
|
272
|
+
|
|
273
|
+
Full section (API forms, why lavfi `color=` beats an empty text source, adoption list) moved to
|
|
274
|
+
[`construction-strategy.md`](construction-strategy.md) § "Solid-colour tile sources — use `makeColorTile`". Source: https://github.com/m0saic-project/m0saic-packages/blob/main/packages/template-utils/src/sources/makeColorTile.ts#L52.
|
|
275
|
+
|
|
276
|
+
## Rule 10 — Single vs multi render
|
|
277
|
+
|
|
278
|
+
| Mode | Source | User authority |
|
|
279
|
+
|---------|------------------------------------------------------------------|----------------|
|
|
280
|
+
| Single | `MosaicDocument`, or pipeline with `emit:"single"` / 1 output | Full (rule 5) |
|
|
281
|
+
| Multi | Pipeline with top-level `emit:"multi"` and `outputCount > 1` | Template-driven (rule 6); user only via rule 7 |
|
|
282
|
+
|
|
283
|
+
## Rule 11 — Multi-encode (separate axis)
|
|
284
|
+
|
|
285
|
+
`encodes?: Record<string, MosaicOutputEncode>` on `MosaicDocument` and `MosaicDocumentPipeline` declares N transcoded variants of the master render(s).
|
|
286
|
+
|
|
287
|
+
1 render → 1 master + N encodes
|
|
288
|
+
|
|
289
|
+
Engine implementation: master renders into a workspace `{base}.__master.{ext}` (never the user-facing path, so encodes can stream-copy/transcode from it), then post-process ffmpeg passes `ffmpeg -i master.<ext> ...` produce each encode entry. `runPlanInWorkspace` skips its "final command" sweep when `multiOutput: true`, so every command writes to its own `outputPath` hint instead of getting rerouted to the user-facing path.
|
|
290
|
+
|
|
291
|
+
### What an encode CAN change
|
|
292
|
+
- Codec, container, pixel format, encoder tuning (the primary axis).
|
|
293
|
+
- Width/height (optional `scale` filter pass — **stretches** content; no aspect-aware padding or re-layout).
|
|
294
|
+
- Audio, color tagging, container metadata.
|
|
295
|
+
|
|
296
|
+
### What an encode CANNOT change
|
|
297
|
+
- `fps`, `durationMs` (inherited from master).
|
|
298
|
+
- The render's `target` preset or `emit` mode.
|
|
299
|
+
|
|
300
|
+
### Pipeline + encodes
|
|
301
|
+
- `emit:"single"` → `encodes` apply to the one concat output (one master, N encodes).
|
|
302
|
+
- `emit:"multi"` → `encodes` apply to **each** emitted file (each of N step outputs gets N encodes — `outputCount × encodeCount` files total).
|
|
303
|
+
|
|
304
|
+
### Container/codec compatibility defaults
|
|
305
|
+
- WebM rejects AAC; when no audio override is supplied and the encode targets WebM, `buildEncodeCommand` defaults to `-c:a libopus` (master AAC can't be stream-copied into WebM).
|
|
306
|
+
- `matroska` / `quicktime` / `mpegts` are ffmpeg muxer names; `containerToExt` aliases them to `.mkv` / `.mov` / `.ts` so the writer emits valid file extensions.
|
|
307
|
+
|
|
308
|
+
## Rule 12 — Template / engine / CLI responsibilities
|
|
309
|
+
|
|
310
|
+
**Templates:**
|
|
311
|
+
- Author one `MosaicDocument` or one `MosaicDocumentPipeline` per `render()` call.
|
|
312
|
+
- Set output knobs (`size`, `fps`, etc.) on the doc/pipeline as **template intent** (tier 2 of rule 5).
|
|
313
|
+
- For multi-output (pipeline emit:multi) authors: read `ctx.userIntent.outputs` and map preset names onto step `name`s.
|
|
314
|
+
- Never read `.m0v` files directly.
|
|
315
|
+
|
|
316
|
+
**Engine:**
|
|
317
|
+
- Resolves output knobs per rule 5 (User > Template > Engine default).
|
|
318
|
+
- Branches on `emit` at top level: concat for single, fan-out for multi.
|
|
319
|
+
- Filters `intermediate` steps from output count / concat / per-file emission.
|
|
320
|
+
- Honors the exact-override path (rule 7) when triggered.
|
|
321
|
+
- Issues post-render transcode passes per `encodes` (rule 11).
|
|
322
|
+
- Concat path always emits audio (silent AAC track when sources are image-only) so downstream encodes carry an audio stream regardless of source mediaType.
|
|
323
|
+
|
|
324
|
+
**CLI:**
|
|
325
|
+
- Loads `.m0v` (when supplied) as default user input.
|
|
326
|
+
- Merges CLI flags on top (CLI flags > `.m0v` defaults within the User tier).
|
|
327
|
+
- Assembles `ctx.userIntent` and bakes user values into the doc/pipeline before plan-build.
|
|
328
|
+
|
|
329
|
+
---
|
|
330
|
+
|
|
331
|
+
## Per-rule wiring status (2026-05-15, end of Phase 5)
|
|
332
|
+
|
|
333
|
+
| # | Rule | Typed? | Wired? | Tested? | Notes |
|
|
334
|
+
|---|----------------------------|--------|--------|---------|--------------------------------------------------------------------|
|
|
335
|
+
| 1 | Top-level return types | ✓ | ✓ | ✓ | Document/Pipeline dispatch wired in `buildMosaicPlanFromFile.ts`. |
|
|
336
|
+
| 2 | Pipeline emit single/multi | ✓ | ✓ | ✓ | `multi-output-minimal` fixture; `test-templates.e2e.test.js`. |
|
|
337
|
+
| 3 | Step model (durationMs, intermediate, name, label) | ✓ | ✓ | ✓ | label honored in `--output-pattern`'s `{{label}}` token. |
|
|
338
|
+
| 4 | Pipeline execution | ✓ | ✓ | ✓ | Per-step `size` honored; nested-downgrade emits diagnostic. |
|
|
339
|
+
| 5 | Output resolution (single) | ✓ | ✓ | ✓ | 3-tier chain in `resolveOutputFormat.ts`. |
|
|
340
|
+
| 6 | Multi-output (pipeline emit:multi) | ✓ | ✓ | ✓ | Fan-out + workspace→user-facing copy in CLI. |
|
|
341
|
+
| 7 | Exact per-output override | ✓ | ✓ | ✓ | Length-match triggers positional merge; warns on key drift. |
|
|
342
|
+
| 8 | Preset semantics | ✓ | ✓ | ✓ | CLI `--m0v` + flag merge; `ctx.userIntent.outputs` surfaced. |
|
|
343
|
+
| 9 | Intermediate steps | ✓ | ✓ | ✓ | Filter in step loop; verified absent from user-facing output. |
|
|
344
|
+
| 10 | Single vs multi distinction | ✓ | ✓ | ✓ | Follows from rules 6+7. |
|
|
345
|
+
| 11 | Multi-encode (separate axis) | ✓ | ✓ | ✓ | Transcode chain + matroska alias + WebM audio default. |
|
|
346
|
+
| 12 | Template / engine / CLI responsibilities | ✓ | ✓ | ✓ | `ctx.userIntent` wired through `createEngineContext`. |
|
|
347
|
+
|
|
348
|
+
Legend: ✓ fully present · partial present-but-incomplete · ✗ absent.
|
|
349
|
+
|
|
350
|
+
---
|
|
351
|
+
|
|
352
|
+
## Test coverage by rule
|
|
353
|
+
|
|
354
|
+
> ⚠️ **Fixture set has roughly quadrupled since this table was written (2026-05-15).**
|
|
355
|
+
> As of 2026-07-26 the always-on gate renders **49 fixtures**, including **20 `ref-*`**
|
|
356
|
+
> (cross-step / same-doc mirror coverage for Rule 9), **15 `effects/*`**, the data-
|
|
357
|
+
> pipeline fixtures (`fixture-pipeline-via-mosaicx`, `github-pulse-replay`), and 4 audio
|
|
358
|
+
> fixtures with `minMeanVolumeDb` floors. The rows below name the original anchor
|
|
359
|
+
> fixtures only — the `FIXTURES` array in
|
|
360
|
+
> the CLI source (not published) is the live inventory.
|
|
361
|
+
|
|
362
|
+
| Rule | Gate type | Where |
|
|
363
|
+
|---|---|---|
|
|
364
|
+
| 1 | unit | the render engine source (not published) |
|
|
365
|
+
| 2/3/4/9/10 | E2E + visual | the CLI source (not published) (multi-output-minimal); the render engine source (not published) |
|
|
366
|
+
| 5 | unit | the render engine source (not published) |
|
|
367
|
+
| 6 | E2E | the CLI source (not published) (multi-output-minimal) |
|
|
368
|
+
| 7 | unit + E2E | the render engine source (not published) exact-override branch; the CLI source (not published) --m0v plumbing |
|
|
369
|
+
| 8 | unit | the CLI source (not published); CLI `cli.flags.test.js` |
|
|
370
|
+
| 11 | E2E | the CLI source (not published) (doc-with-encodes, pipeline-single-encodes, pipeline-multi-encodes, codec-matrix-video, codec-matrix-audio) |
|
|
371
|
+
| 12 | structural | See the render-path walkthrough (internal: `.ai/moat/templates/cli-template-lifecycle.md`) |
|
|
372
|
+
|
|
373
|
+
---
|
|
374
|
+
|
|
375
|
+
## Migration notes (what disappeared)
|
|
376
|
+
|
|
377
|
+
This contract represents a flatten refactor from a previous design:
|
|
378
|
+
|
|
379
|
+
- **`MosaicOutput` type — DELETED.** Its fields are flat on `MosaicDocument` and `MosaicDocumentPipeline` now.
|
|
380
|
+
- **`outputs: Record<string, MosaicOutput>` map — DELETED.** Documents have one output config; multi-geometry deliverables go through pipelines.
|
|
381
|
+
- **`outputsRef?: string` — DELETED.** Templates don't reference `.m0v` files; the CLI loads `.m0v` as default user input.
|
|
382
|
+
- **`labelsRef?: string` — DELETED.** Same principle as `outputsRef`. The canonical path for `.m0c` / `.m0p` content into a doc is via the template `m0c` / `m0p` prop type — the CLI/host loads the file, supplies it as a prop value, and the template extracts the labels into `doc.labels`. See `MosaicTemplatePropType` in https://github.com/m0saic-project/m0saic-packages/blob/main/packages/types/src/template/template.ts.
|
|
383
|
+
- **`encodes?: ...` — MOVED to top-level** on Document and Pipeline (was nested inside MosaicOutput).
|
|
384
|
+
- **`emit?: ...` — MOVED to top-level** on Pipeline (was on MosaicOutput).
|
|
385
|
+
- **`ctx.userIntent.requestedOutputs` — REMOVED.** Subsumed by `ctx.userIntent.outputs` (the engine reads `Object.keys(outputs)` for the count signal in rule 7).
|
|
386
|
+
|
|
387
|
+
## Forward references
|
|
388
|
+
|
|
389
|
+
- `MosaicPipelineStep / PipelineStepBase` JSDoc — full `intermediate` / `label` semantics.
|
|
390
|
+
- `MosaicOutputEncode` JSDoc — full multi-encode contract.
|
|
391
|
+
- Concrete render walkthrough for templates consulting `ctx.userIntent` — engine-internal: `.ai/moat/templates/cli-template-lifecycle.md` (absent in the shipped copy).
|
|
392
|
+
- Data-fetcher / adapter / handle patterns — rely on intermediate steps and data-only docs in pipelines. Promoted: [`data-pipeline.md`](data-pipeline.md) (sibling doc in this folder).
|