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,169 @@
|
|
|
1
|
+
# The `"json"` prop type + typed-output templates
|
|
2
|
+
|
|
3
|
+
Two additive capabilities that unblock structured-config props and typed
|
|
4
|
+
data-fetcher templates. Both are **shipped and current** — verified against
|
|
5
|
+
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/template-utils/src/template,
|
|
6
|
+
and `validateTemplateProps`.
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 1. `type: "json"`
|
|
11
|
+
|
|
12
|
+
`"json"` is a member of `MosaicTemplatePropType`, alongside the string / number /
|
|
13
|
+
boolean / media / structural (`group`, `list`) and m0-family (`m0`, `m0c`, `m0p`)
|
|
14
|
+
entries.
|
|
15
|
+
|
|
16
|
+
### When to reach for it
|
|
17
|
+
|
|
18
|
+
Use `"json"` when a prop's value is a **structured object or array that maps to a
|
|
19
|
+
TypeScript interface**:
|
|
20
|
+
|
|
21
|
+
- `filter` / `sceneFilter` — a remote API's filter input passed wholesale
|
|
22
|
+
- `{ low, high, mode }` clip-duration configs
|
|
23
|
+
- `Array<MosaicTimeRangeMs>` — the multi-range clip seam (see §3)
|
|
24
|
+
- Per-tile decoration bundles
|
|
25
|
+
|
|
26
|
+
**Don't** use it for:
|
|
27
|
+
|
|
28
|
+
| Instead of `"json"` | Use |
|
|
29
|
+
|---|---|
|
|
30
|
+
| a primitive that merely *looks* like JSON stringified | `"string"` / `"number"` / `"boolean"` |
|
|
31
|
+
| an array of primitives | `"string[]"` / `"number[]"` |
|
|
32
|
+
| a media reference | `"media"` |
|
|
33
|
+
| a fixed set of named sub-fields you want as individual controls | `"group"` with `fields` |
|
|
34
|
+
|
|
35
|
+
That last row is the common mistake: a `"group"` **without** `fields` degrades to a
|
|
36
|
+
raw JSON bag in the editor, which is strictly worse than declaring `"json"` on
|
|
37
|
+
purpose.
|
|
38
|
+
|
|
39
|
+
### Validator behavior — permissive by design
|
|
40
|
+
|
|
41
|
+
`validateTemplateProps` accepts **any non-undefined value** when `type === "json"`.
|
|
42
|
+
The engine boundary does not parse, shape-check, or reject. That is deliberate:
|
|
43
|
+
editors may deliver an already-parsed object *or* a raw JSON string, and both are
|
|
44
|
+
legal at the boundary.
|
|
45
|
+
|
|
46
|
+
**Consequence for template authors:** render-time parsing and shape-checking is
|
|
47
|
+
**your** job. Call `JSON.parse` if the editor handed you a string, then validate
|
|
48
|
+
however you like (Zod, Ajv, hand-rolled). Do not assume you received an object.
|
|
49
|
+
|
|
50
|
+
There is intentionally no `JSON_PROP_SCHEMA_MISMATCH` diagnostic. If shape drift
|
|
51
|
+
becomes a recurring failure mode, wiring one up would be additive.
|
|
52
|
+
|
|
53
|
+
### `meta.constraints.jsonSchema` — an editor hint, never a gate
|
|
54
|
+
|
|
55
|
+
Optional, two forms:
|
|
56
|
+
|
|
57
|
+
| Form | Meaning |
|
|
58
|
+
|---|---|
|
|
59
|
+
| `{ ref: "<host-resolved-id>" }` | Points into a shared JSON-schema registry the host owns. Use when several templates share a payload shape. |
|
|
60
|
+
| inline `Record<string, unknown>` | A JSON-Schema-ish object describing the payload. |
|
|
61
|
+
|
|
62
|
+
Editors that understand the schema may render a structured form; those that don't
|
|
63
|
+
fall back to a plain code editor. **The engine never validates this field.**
|
|
64
|
+
|
|
65
|
+
### ⚠️ `as never` is NOT required — and existing casts are stale
|
|
66
|
+
|
|
67
|
+
Several shipped templates write `type: "json" as never`
|
|
68
|
+
(`charts/bar-graph/v1` + `v2`, `charts/line-chart/v1`, `internal/bars-stack`). **The
|
|
69
|
+
cast is unnecessary.** Those are leftovers from before `"json"` joined the union.
|
|
70
|
+
|
|
71
|
+
`definePropsSchema<P>` is typed as `Record<keyof P, MosaicTemplatePropDefinition>` —
|
|
72
|
+
it constrains only the *key set*, never the relationship between a prop's TS type and
|
|
73
|
+
its declared `type`. So this compiles clean, no casts:
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
type P = { barColor?: string | string[]; spec: Record<string, unknown> };
|
|
77
|
+
|
|
78
|
+
const propsSchema = definePropsSchema<P>({
|
|
79
|
+
barColor: { type: "json", required: false },
|
|
80
|
+
spec: { type: "json", required: true },
|
|
81
|
+
});
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
(Verified 2026-07-26 with the repo's own `tsc -p https://github.com/m0saic-project/m0saic-packages/blob/main/packages/templates/tsconfig.json.)
|
|
85
|
+
`brand/qr-stamp/video/v2` (`luminanceBuckets`) is the correct, cast-free reference.
|
|
86
|
+
|
|
87
|
+
**Do not copy the `as never` pattern into new templates**, and drop it opportunistically
|
|
88
|
+
when you touch one of the offenders. The same goes for the neighbouring
|
|
89
|
+
`type: "group" as any` casts — check whether they're still load-bearing before
|
|
90
|
+
propagating them.
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## 2. The 5-generic `defineMosaicTemplate`
|
|
95
|
+
|
|
96
|
+
`MosaicTemplate` has carried 5 generics for a while; the helper now matches:
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
defineMosaicTemplate<
|
|
100
|
+
P extends MosaicTemplateProps,
|
|
101
|
+
O extends MosaicTemplateOutputs = MosaicTemplateOutputs,
|
|
102
|
+
U extends MosaicTemplateUpstreamVariables = MosaicTemplateUpstreamVariables,
|
|
103
|
+
D extends MosaicTemplateUpstreamData = MosaicTemplateUpstreamData,
|
|
104
|
+
S extends MosaicTemplateSidecars = MosaicTemplateSidecars,
|
|
105
|
+
>(template: MosaicTemplate<P, O, U, D, S>): MosaicTemplate<P, O, U, D, S>
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Defaults preserve full back-compat — every existing 1-generic call site still
|
|
109
|
+
compiles unchanged.
|
|
110
|
+
|
|
111
|
+
**Use the full form when** your template (1) publishes typed outputs via
|
|
112
|
+
`outputsSchema`, (2) publishes typed sidecars via `sidecarsSchema`, or (3) reads
|
|
113
|
+
`ctx.upstreamData.<alias>` and wants type-checked access. Otherwise stay on
|
|
114
|
+
`defineMosaicTemplate<P>` — it remains the recommendation for ordinary renderables.
|
|
115
|
+
|
|
116
|
+
### Gotcha — don't narrow `U` / `D` to an empty shape
|
|
117
|
+
|
|
118
|
+
A fetcher that reads no upstream is tempted to tighten `U` / `D` to
|
|
119
|
+
`Record<string, never>`. **Don't.** `registerTemplate` accepts only the loose form
|
|
120
|
+
(`Record<string, unknown>`), and narrowing reverses contravariance — TS rejects the
|
|
121
|
+
registration.
|
|
122
|
+
|
|
123
|
+
Pass the loose defaults explicitly for `U` and `D`; tighten only `O` and `S`.
|
|
124
|
+
Consumer templates that *do* read upstream are the right place to tighten `U` / `D`,
|
|
125
|
+
because there the context is an **input** to the bound, not an output.
|
|
126
|
+
|
|
127
|
+
```ts
|
|
128
|
+
export const RepoFetcher = defineMosaicTemplate<
|
|
129
|
+
Props,
|
|
130
|
+
Outputs,
|
|
131
|
+
MosaicTemplateUpstreamVariables, // loose — narrowing breaks registerTemplate
|
|
132
|
+
MosaicTemplateUpstreamData, // (contravariance)
|
|
133
|
+
Sidecars
|
|
134
|
+
>({
|
|
135
|
+
id: asTemplateId("@example/github/repo-fetcher/v1"),
|
|
136
|
+
role: "data-fetcher",
|
|
137
|
+
capabilities: { tier: "capability", caps: { net: { fetch: true } } },
|
|
138
|
+
propsSchema: {
|
|
139
|
+
apiUrl: { type: "string", required: true },
|
|
140
|
+
tokenRef: { type: "string", required: false },
|
|
141
|
+
filter: {
|
|
142
|
+
type: "json",
|
|
143
|
+
required: false,
|
|
144
|
+
meta: { constraints: { jsonSchema: { ref: "@example/repo-filter/v1" } } },
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
defaultProps: { apiUrl: "https://api.github.com" },
|
|
148
|
+
async render(props, ctx) { /* … */ },
|
|
149
|
+
});
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## 3. Cross-references
|
|
155
|
+
|
|
156
|
+
- **Data-fetcher pattern** — `../data-pipeline.md`. The five-generic
|
|
157
|
+
`defineMosaicTemplate<Props, Outputs, …, Sidecars>` signature its fetcher contract
|
|
158
|
+
relies on was aspirational when first documented; it is valid TypeScript today.
|
|
159
|
+
- **Multi-range clip picker** — `picker: "time-ranges"` is declared on a **single**
|
|
160
|
+
`type: "json"` prop whose value is `Array<MosaicTimeRangeMs>`
|
|
161
|
+
(`{ startMs, endMs, label? }`, integer ms, source-relative, sorted ascending;
|
|
162
|
+
overlaps allowed, empty array = no selection). Unlike the paired `"time-range"`
|
|
163
|
+
picker there is no prop pairing — the editor reads and writes the whole array
|
|
164
|
+
through that one prop in a single write. Boundary reader:
|
|
165
|
+
`parseTimeRangesValue` in `template-utils/src/media/timeRanges.ts` — use it rather
|
|
166
|
+
than hand-parsing, precisely because the value may arrive as object *or* string.
|
|
167
|
+
- **Prop-shape consistency** — `npm run audit:props` in https://github.com/m0saic-project/m0saic-packages/blob/main/packages/templates emits
|
|
168
|
+
`PROPS-SHAPE.md`, a cross-template prop-shape matrix. Run it after adding a
|
|
169
|
+
`"json"` prop to see how the shelf compares.
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# MosaicColor
|
|
2
|
+
|
|
3
|
+
> **Source of truth:** [https://github.com/m0saic-project/m0saic-packages/blob/main/packages/types/src/colors/mosaicColor.ts](https://github.com/m0saic-project/m0saic-packages/blob/main/packages/types/src/colors/mosaicColor.ts) (the type), https://github.com/m0saic-project/m0saic-packages/blob/main/packages/types/src/colors/parseMosaicColors.ts (the validators), https://github.com/m0saic-project/m0saic-packages/blob/main/packages/types/src/colors/ffmpegNamedColors.ts (the named-color set).
|
|
4
|
+
|
|
5
|
+
## The type
|
|
6
|
+
|
|
7
|
+
Verbatim from `mosaicColor.ts:25`:
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
export type MosaicColor =
|
|
11
|
+
| "none"
|
|
12
|
+
| FfmpegNamedColor
|
|
13
|
+
| HexColor
|
|
14
|
+
| `${FfmpegNamedColor}${AlphaSuffix}`
|
|
15
|
+
| `${HexColor}${AlphaSuffix}`
|
|
16
|
+
| `none${AlphaSuffix}`;
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Accepted: ffmpeg named colors (`"white"`, `"darkgray"`), hex (`"#fff"`,
|
|
20
|
+
`"#ffffff"`, `"#ff00ffaa"`), optional alpha suffix (`"white@0.5"`), and
|
|
21
|
+
`"none"` for transparency. `HexColor` is just `` `#${string}` `` — the type is
|
|
22
|
+
a **shape contract, not a full validator** (no hex well-formedness, alpha
|
|
23
|
+
range, or casing checks). Runtime validation is required on production paths.
|
|
24
|
+
|
|
25
|
+
## Validate with the real exports — never hand-roll
|
|
26
|
+
|
|
27
|
+
`@m0saic/types` ships the canonical pair; use them instead of local regexes
|
|
28
|
+
(a naive "has an `@` suffix" check accepts `"garbage@0.5"` — the real one
|
|
29
|
+
re-validates the base):
|
|
30
|
+
|
|
31
|
+
- **`toMosaicColor(input, ctx?)`** (`parseMosaicColors.ts:16`) — throws on
|
|
32
|
+
invalid; returns a normalized (lowercased) `MosaicColor`. Splits any `@alpha`
|
|
33
|
+
suffix, requires alpha finite and in `[0, 1]` (`:39-41`), then validates the
|
|
34
|
+
**base** as `"none"`, a named color, or well-formed hex. `ctx` names the error.
|
|
35
|
+
- **`isMosaicColor(input)`** (`parseMosaicColors.ts:75`) — non-throwing type guard.
|
|
36
|
+
- **`FFMPEG_NAMED_COLORS_SET`** (`ffmpegNamedColors.ts:157`) — the membership
|
|
37
|
+
set behind named-color validation.
|
|
38
|
+
|
|
39
|
+
Real caller: https://github.com/m0saic-project/m0saic-packages/blob/main/packages/templates/src/m0saic/charts/bar-graph/v1/internal/plot-area.ts#L30
|
|
40
|
+
imports it and uses it as `toMosaicColor("#ffffff", "PlotArea.BASELINE_COLOR")` (:83).
|
|
41
|
+
|
|
42
|
+
Where to validate: primitives validate incoming color props before passing them
|
|
43
|
+
to sources; heroes normalize early; template-utils must never emit invalid
|
|
44
|
+
`MosaicColor`. Never widen a field to `string` to silence the compiler.
|
|
45
|
+
|
|
46
|
+
## `"none"` and alpha
|
|
47
|
+
|
|
48
|
+
- `"none"` means transparent. The engine mapping to an ffmpeg color string
|
|
49
|
+
lives in the render engine source (not published) (`ffmpegColor()`) —
|
|
50
|
+
templates use `"none"` as intent, never hand-encoding the ffmpeg form.
|
|
51
|
+
- Prefer `visual.opacity` for compositing; use an alpha suffix only when
|
|
52
|
+
transparency is part of the color's identity — never encode opacity in both.
|
|
53
|
+
|
|
54
|
+
## Ternary widening (common pitfall)
|
|
55
|
+
|
|
56
|
+
When assigning a `MosaicColor` via a conditional, TypeScript widens the literal
|
|
57
|
+
branches to `string` and the assignment fails:
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
const style = {
|
|
61
|
+
borderColor: isDark ? "#fff" : "#000", // ❌ widens to string — type error
|
|
62
|
+
};
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
✅ Use `as const` on the literals:
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
const style = {
|
|
69
|
+
borderColor: (isDark ? ("#fff" as const) : ("#000" as const)),
|
|
70
|
+
};
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
✅ Or extract a shared style record so each value is a known literal:
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
const COLORS = { light: "#fff", dark: "#000" } as const;
|
|
77
|
+
const style = { borderColor: COLORS[isDark ? "dark" : "light"] };
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
The same trap fires on every `MosaicColor`-typed field reached via a ternary
|
|
81
|
+
(`borderColor`, `fillColor`, …). Fix at the literal site, never by widening.
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# MosaicPlacementProps
|
|
2
|
+
|
|
3
|
+
> **Source of truth:** [https://github.com/m0saic-project/m0saic-packages/blob/main/packages/types/src/source/source.ts#L99-188`](https://github.com/m0saic-project/m0saic-packages/blob/main/packages/types/src/source/source.ts); runtime validation in https://github.com/m0saic-project/m0saic-packages/blob/main/packages/platform/src/mosaic/validate/validateSources.ts; cover-crop math in the render engine source (not published).
|
|
4
|
+
|
|
5
|
+
## The union
|
|
6
|
+
|
|
7
|
+
`MosaicPlacementProps = MosaicPlacementContain | MosaicPlacementCover`
|
|
8
|
+
(`source.ts:188`) — a discriminated union on `fit`. Fields that are meaningless
|
|
9
|
+
on one fit are declared `?: never` on that variant, so misuse is a **compile
|
|
10
|
+
error**, not a silent no-op:
|
|
11
|
+
|
|
12
|
+
| Field | Contain (`fit?: "contain"`, default) | Cover (`fit: "cover"`) |
|
|
13
|
+
|---|---|---|
|
|
14
|
+
| `inset` | ✅ (`source.ts:128`, on the shared base) | ✅ |
|
|
15
|
+
| `padding` | ✅ (`source.ts:152`) | ❌ `padding?: never` (:166) |
|
|
16
|
+
| `hAlign` / `vAlign` | ✅ (:133-134) | ❌ `hAlign?: never` / `vAlign?: never` (:162-163) |
|
|
17
|
+
| `focusX` / `focusY` | ❌ `focusX?: never` / `focusY?: never` (:155-156) | ✅ (:177, :185) |
|
|
18
|
+
|
|
19
|
+
Defaults when omitted: `fit="contain"`, `hAlign="center"`, `vAlign="middle"`,
|
|
20
|
+
no `inset`, no `padding`; on cover, focus defaults to centered (`0.5`).
|
|
21
|
+
|
|
22
|
+
## Boxes: tile rect → inset → padding → content box
|
|
23
|
+
|
|
24
|
+
- **Tile rect**: the rectangle the layout engine allocates to the source.
|
|
25
|
+
- **`inset?: MosaicBoxFrac`** (both fits): shrinks the destination rect **before**
|
|
26
|
+
fit math. Role: the **slot-level gutter**, typically owned by the composing
|
|
27
|
+
layer. Fractions of **tile size**.
|
|
28
|
+
- **`padding?: MosaicBoxFrac`** (contain-only): extra dead space reserved
|
|
29
|
+
**inside** the inset box, before contain math. Role: content-level breathing
|
|
30
|
+
room, composing with (not fighting) the slot's `inset`. Fractions of the
|
|
31
|
+
**inset box** (= of tile size when `inset` is unset; the engine resolves
|
|
32
|
+
`padLeft = insetBox.width * padding.left`). Cover forbids it — "cover +
|
|
33
|
+
padding would create intentional dead space" — enforced by the type AND the
|
|
34
|
+
`*_COVER_PADDING` validator (`validateSources.ts:561`).
|
|
35
|
+
- **`MosaicBoxFrac`** (`source.ts:85-97`): `0.02` (all sides) | `{x, y}`
|
|
36
|
+
(symmetric per axis) | `{top, right, bottom, left}` (per-side overrides win).
|
|
37
|
+
All fractions 0..1; validators require each side in `[0, 0.49]`.
|
|
38
|
+
- **Content box**: the tile rect after `inset` (and, for contain, `padding`).
|
|
39
|
+
|
|
40
|
+
⚠️ **Both are applied BEFORE the per-tile effects chain.** Quoting the `inset`
|
|
41
|
+
JSDoc (`source.ts:117-121`): "Applied before the per-tile effects chain — the
|
|
42
|
+
content's buffer IS the shrunk box, so effects that need headroom
|
|
43
|
+
(`effects.rotate`) clip against it. Rotation headroom must be real geometry
|
|
44
|
+
instead: a nested child whose declared `size` equals the padded box (see
|
|
45
|
+
watermark page-mode `buildPaddedInstanceChild`)."
|
|
46
|
+
|
|
47
|
+
## Contain
|
|
48
|
+
|
|
49
|
+
Uniform scale, aspect preserved, so the media fits entirely inside the content
|
|
50
|
+
box. Leftover per axis: `leftoverX = contentW - scaledW`, `leftoverY = contentH - scaledH`.
|
|
51
|
+
|
|
52
|
+
Alignment maps to factors — `left/top = 0`, `center/middle = 0.5` (default),
|
|
53
|
+
`right/bottom = 1` — and placement is:
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
x = contentX + (leftoverX > 0 ? leftoverX * hFactor(hAlign) : 0)
|
|
57
|
+
y = contentY + (leftoverY > 0 ? leftoverY * vFactor(vAlign) : 0)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**Exact-fit invariant (still observable, and required):** on an axis with zero
|
|
61
|
+
leftover, varying the alignment MUST NOT change output — byte-identical frames.
|
|
62
|
+
This is the surviving observability check now that cover-side misuse is
|
|
63
|
+
unrepresentable.
|
|
64
|
+
|
|
65
|
+
## Cover
|
|
66
|
+
|
|
67
|
+
Uniform scale, aspect preserved, so the media fully covers the content box;
|
|
68
|
+
overflow is cropped to exactly `contentW × contentH`; placed at
|
|
69
|
+
`(contentX, contentY)`. No leftover space, so alignment is unrepresentable.
|
|
70
|
+
|
|
71
|
+
### Crop anchor: `focusX` / `focusY`
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
placement: { fit: "cover", focusX?: number, focusY?: number } // 0..1 each
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**Offset per axis = `(scaled - content) * focus`.** `0` keeps the leading edge
|
|
78
|
+
(left/top), `0.5` centers (default), `1` keeps the trailing edge. Motivating
|
|
79
|
+
case: portrait photos put faces near the top — `focusY: 0` keeps the head.
|
|
80
|
+
|
|
81
|
+
- **Byte-identity guarantee.** Focus absent or exactly `0.5` emits the exact
|
|
82
|
+
legacy `(in_w-W)/2` string — helper `coverCropOffsetExpr`
|
|
83
|
+
(the render engine source (not published)). Existing goldens do not move.
|
|
84
|
+
- **Enforced twice.** Type level: `focusX?: never` on contain. Runtime:
|
|
85
|
+
`*_FOCUS_REQUIRES_COVER` (https://github.com/m0saic-project/m0saic-packages/blob/main/packages/platform/src/mosaic/validate/validateSources.ts#L575)
|
|
86
|
+
plus range checks `*_INVALID_FOCUSX` / `*_INVALID_FOCUSY` in `[0, 1]`
|
|
87
|
+
(`validateFocus`, `validateSources.ts:502`). Note these live in **platform**,
|
|
88
|
+
not core.
|
|
89
|
+
- **Also steered by focus:** `zoomInPercent`'s zoom crop on cover tiles
|
|
90
|
+
(contain + zoom stays centered), and `doc.backgroundImage`'s cover fill.
|
|
91
|
+
- **Not `effects.camera`.** Same focus vocabulary, different layer: the camera
|
|
92
|
+
is the animatable zoom/pan downstream on the already-cropped content box;
|
|
93
|
+
placement focus is the static, plan-time fit-crop anchor. They compose.
|
|
94
|
+
- **Web parity:** `GeometricPreview` maps cover focus to CSS
|
|
95
|
+
`object-position: ${fx*100}% ${fy*100}%` — identical percentage math.
|
|
96
|
+
|
|
97
|
+
## Historical note
|
|
98
|
+
|
|
99
|
+
Pre-v2 versions of this spec carried "for `fit="cover"`, `hAlign`/`vAlign`
|
|
100
|
+
MUST NOT affect output" invariants. The union now declares those fields `never`
|
|
101
|
+
on cover (verified against `source.ts` 2026-07-27), so the misuse is
|
|
102
|
+
unrepresentable and those invariants are moot — only the contain exact-fit
|
|
103
|
+
invariant above remains testable.
|