Compiling
What runs before a reader sees anything: an attribute refined from the text it was written as, the semantic pass over the result, the manifest a plugin declares, and the service that compiles a document.
@internote/canvas-sdk@internote/canvas-sdk/compile#Functions
(node: ChalkElement, identifier: string): string | nulleditable: graphs, where there is no compiler in the loop.(
identifier: string,
values: Record<string, string>,
instanceId: string,
): BuiltElementOk | BuiltElementErrorValues arrive per attribute ({ x: '2', y: '3' }), as the controls in a footer produce them. This does what the compiler would have done with them: resolves aliases, fills declared defaults, and refines every value through its declared type. The product is indistinguishable from an authored element downstream, which is the point — the surface renders one code path, not two.
!cue.to chains are refused: a keyframe anchors to the narrative's steps, and the reader is not writing the narrative.
(content: unknown): ChalkElement[]colour attribute value, storing it in its canonical spelling or refusing it with a message listing the colours allowed.(input: string): RefineResult(node: ChalkElement, identifier: string): ChalkAttribute | undefined(diagnostic: SemanticDiagnostic): stringcolourValue, but accepting only the plain hues and the hex(…) and rgb(…) literals.(input: string): RefineResult(1, 2), (t, t^2) — each half a number or a parametised expression.(input: string): RefineResultreference attribute names.(value: unknown): string | null#id or #id.member reference written as text, such as #gdp.value inside a keyframe chain, into the binding object the renderer resolves.(input: string): RefineResult(identifier: string, name: string, text: string): {
ok: true;
value: unknown;
} | {
ok: false;
error: string;
}(document: ChalkDocument): RefineDocumentResultIn order: deduplicates the header's tags (more than seven is an error), refines every attribute in the body (including !cue.to keyframe chains), points bindings at pack-scoped datasets (name~n) where the name alone is unambiguous, and writes document.citations from the cite declarations. Idempotent: an already-refined document passes through unchanged. The compile service runs it before the canvas semantic pass.
(document: ChalkDocument): SemanticPassResultWalks every scene, checking: unique ids and continue: targets, at most two environments per scene, cue anchors within the scene's steps, !cue.to only on animatable attributes, children within their environment's vocabulary, suspicious implicit products in expressions, and that each graph mark suits its plane and axes. Never modifies the document. The compile service fails on the first error and passes warnings through on success.
(1, 2), (t+1, 2t) into [x, y] text pairs, or returns an error if the brackets do not pair up.(input: string): { pairs: Array<[string, string]>; } | { error: string; }IntervalParts.(input: string): IntervalParts | { error: string; }(input: string): string[](m: unknown): asserts m is CanvasPluginManifest#Classes
typeof DotchalkCompilationService#Constants
RegExpRegExpDotchalkCompilationService; the service holds no state, so one instance serves every caller.DotchalkCompilationService#Interfaces
buildCanvasElement could not build an element.errorstringokfalsebuildCanvasElement built.dataChalkElementoktrueattributesRecord<string, CanvasAttrSpec>environmentgraph → canvas.graph).stringvocabularyRecord<string, CanvasNodeSpec>The plugin's code default-exports a defineEnvironment definition, loaded by loadEnvironmentFromManifest. Registration works today; plugin distribution does not exist yet, and runtime: 'worker' is reserved for a sandboxed runtime for untrusted plugins.
authorstringchalkCanvasPluginChalkSpecdescriptionstringidstringnamestringpermissionsstring[]runtimedefineEnvironment definition (trusted/reviewed). - 'worker' — future: sandboxed Web Worker runtime (untrusted).moduleworkersrcstringversionstringThe brackets are decoration: [a, b] and (a, b) say the same thing, and either kind may be used as long as it balances — which is the whole reason this reads markers instead of brackets. [a, b) is the notation everyone knows and the compiler will not accept it: it counts brackets before it ever reaches an attribute value, and an unmatched [ ends the document.
So each END carries its own mark, and both combinations are writable:
[0, 8]is 0 ≤ x ≤ 8: an end with no mark is IN the interval.[0, <8]is 0 ≤ x < 8:<is up to but not including.[>0, 8]is 0 < x ≤ 8:>is from but not including.[>0, <8]is 0 < x < 8.[=0, 8]is 0 ≤ x ≤ 8:=says "and equal to", if you want it said.
An end left empty is unbounded, which is how a one-sided interval is written — the mark on the end that IS there still applies:
[, =4]is x ≤ 4: everything up to and including 4.[, <4]is x < 4.[=-5, ]is x ≥ -5.[>-5, ]is x > -5.
Splitting is done by counting depth rather than by matching, so an endpoint may be any expression: [0, exp(1)] and [>k, <2 * k] both read.
endinf where it was left empty.stringinclusiveEnd< and for an unbounded end.booleaninclusiveStart> and for an unbounded end.booleanstart-inf where it was left empty.stringcodestringfilestringlinenumbermessagestringseverityerror) or rides along with a successful one (warning).errorwarningerrorsSemanticDiagnostic[]warningsSemanticDiagnostic[]#Types
refineInternoteDocument: success, or the first refinement error as a message.{ ok: true } | { ok: false; error: string }ok is true, or an error message when it is false.{
ok: true;
data: ChalkDocument;
warnings?: SemanticDiagnostic[];
} | {
ok: false;
error: string;
details?: ChalkError;
}