@glissade/scene 0.46.0 → 0.47.0-pre.1

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.
@@ -114,6 +114,27 @@ interface DescribedHelper {
114
114
  /** Runnable example snippets — see {@link DescribedNode.examples}. */
115
115
  examples?: readonly string[];
116
116
  }
117
+ /**
118
+ * One entry in the {@link ApiManifest.surface} taxonomy (0.47 "verifiable
119
+ * ground-truth"): a single window.glissade export, tagged with how a consumer
120
+ * reaches it. This is the ONE machine-readable truth for the IIFE surface that
121
+ * both `gs describe --lint` (the drift guard vs the real `@glissade/browser`
122
+ * bundle) and `gs types --global` (the ambient `window.glissade` `.d.ts`) read —
123
+ * so the curated helper/node lists can't silently drift from what actually ships
124
+ * on `window.glissade`, and the no-build author gets a typed global surface.
125
+ */
126
+ interface SurfaceEntry {
127
+ /** The export name — also the `window.glissade.<name>` global on the IIFE. */
128
+ name: string;
129
+ /** `'value'` = a runtime binding on the bundle (a class / function / object); `'type'` = a TS type-only name that erases at runtime (opaque, referenced by signatures). */
130
+ kind: 'value' | 'type';
131
+ /** `true` when it is reachable as `window.glissade.<name>` on the single-file IIFE bundle. */
132
+ iife: boolean;
133
+ /** How to consume it: `'constructor'` needs `new`, `'function'` is a plain call, `'object'` is a value namespace (e.g. `easings`), `'type'` is type-only. */
134
+ form: 'constructor' | 'function' | 'object' | 'type';
135
+ /** Documented positional-arg count for a callable (parsed from its usage), when known — absent for value objects and types. */
136
+ arity?: number;
137
+ }
117
138
  /** The full machine-readable manifest `describe()` returns. */
118
139
  interface ApiManifest {
119
140
  version: string;
@@ -139,7 +160,27 @@ interface ApiManifest {
139
160
  subpaths: {
140
161
  [entry: string]: string;
141
162
  };
163
+ /**
164
+ * (0.47 "verifiable ground-truth") The window.glissade runtime SURFACE taxonomy:
165
+ * one machine-readable enumeration of every export a no-build `<script src>`
166
+ * author reaches on the IIFE — node constructors, helper/factory functions, the
167
+ * core callables (`timeline`/`createScene`/`track`/`evaluate`/…), value objects
168
+ * (`easings`), and the opaque type-only names signatures reference. PURELY
169
+ * ADDITIVE + generated from the same curated registries the rest of the manifest
170
+ * is (so it can't drift), and OFF the base embed (describe is tree-shaken off the
171
+ * base scene index) — zero determinism/render-path cost. Consumed by
172
+ * `gs describe --lint` and `gs types --global`. Optional so a manifest captured
173
+ * before 0.47 (no `surface`) still type-checks.
174
+ */
175
+ surface?: SurfaceEntry[];
142
176
  }
177
+ /**
178
+ * Parse the documented positional-arg count from a helper `usage` string — the
179
+ * count of top-level comma-separated params in its FIRST `(...)` call group
180
+ * (depth-tracked so nested `()`/`[]`/`{}`/`<>` in a param type don't miscount).
181
+ * Used to stamp {@link SurfaceEntry.arity} and to drift-check runtime arity.
182
+ */
183
+ declare function usageArity(usage: string): number | undefined;
143
184
  /**
144
185
  * Build the machine-readable API manifest from the live registries (§4.4). Pure
145
186
  * introspection: instantiate each built-in node once to read its registered track
@@ -165,4 +206,4 @@ declare function registerExamples(corpus: {
165
206
  }): void;
166
207
  declare function describe(opts?: DescribeOptions): ApiManifest;
167
208
  //#endregion
168
- export { ApiManifest, DescribeOptions, DescribedBuilderMethod, DescribedComponent, DescribedHelper, DescribedNode, DescribedProp, describe, registerExamples };
209
+ export { ApiManifest, DescribeOptions, DescribedBuilderMethod, DescribedComponent, DescribedHelper, DescribedNode, DescribedProp, SurfaceEntry, describe, registerExamples, usageArity };
package/dist/describe.js CHANGED
@@ -23,8 +23,227 @@ import { easings, listValueTypes } from "@glissade/core";
23
23
  * never pulled onto the base embed path — a scene that never calls `describe()`
24
24
  * pays zero bytes for it.
25
25
  */
26
- const RAW_VERSION = "0.46.0";
26
+ const RAW_VERSION = "0.47.0-pre.1";
27
27
  const PACKAGE_VERSION = RAW_VERSION.includes("GLISSADE_".concat("VERSION")) ? "0.0.0-dev" : RAW_VERSION;
28
+ /**
29
+ * Parse the documented positional-arg count from a helper `usage` string — the
30
+ * count of top-level comma-separated params in its FIRST `(...)` call group
31
+ * (depth-tracked so nested `()`/`[]`/`{}`/`<>` in a param type don't miscount).
32
+ * Used to stamp {@link SurfaceEntry.arity} and to drift-check runtime arity.
33
+ */
34
+ function usageArity(usage) {
35
+ const open = usage.indexOf("(");
36
+ if (open < 0) return void 0;
37
+ let depth = 0;
38
+ const params = [];
39
+ let cur = "";
40
+ for (let i = open; i < usage.length; i++) {
41
+ const c = usage[i];
42
+ if (c === "(" || c === "[" || c === "{" || c === "<") {
43
+ depth++;
44
+ if (depth === 1) continue;
45
+ } else if (c === ")" || c === "]" || c === "}" || c === ">") {
46
+ depth--;
47
+ if (depth === 0) {
48
+ if (cur.trim()) params.push(cur);
49
+ break;
50
+ }
51
+ }
52
+ if (depth === 1 && c === ",") {
53
+ params.push(cur);
54
+ cur = "";
55
+ continue;
56
+ }
57
+ if (depth >= 1) cur += c;
58
+ }
59
+ return params.filter((p) => p.trim().length > 0).length;
60
+ }
61
+ /**
62
+ * The window.glissade CONSTRUCTOR nodes — reached with `new` (`new glissade.Rect(…)`).
63
+ * The layout FACTORIES (Stack/Row/Column) + the build-time fan-outs (Grid/Chart/…)
64
+ * are plain calls and live in {@link HELPERS}, so they aren't here.
65
+ */
66
+ const SURFACE_CONSTRUCTORS = [
67
+ "Group",
68
+ "Rect",
69
+ "Circle",
70
+ "Path",
71
+ "Text",
72
+ "Image",
73
+ "Video",
74
+ "Layout"
75
+ ];
76
+ /**
77
+ * The core callables that are `window.glissade.<name>` globals but are neither a
78
+ * node constructor nor a curated {@link HELPERS} factory — the authoring entry
79
+ * points (`timeline`/`createScene`/`track`/`evaluate`/`stagger`) + `describe`
80
+ * itself. `arity` is the documented positional-arg count.
81
+ */
82
+ const SURFACE_CORE = [
83
+ {
84
+ name: "timeline",
85
+ arity: 1
86
+ },
87
+ {
88
+ name: "createScene",
89
+ arity: 1
90
+ },
91
+ {
92
+ name: "track",
93
+ arity: 3
94
+ },
95
+ {
96
+ name: "evaluate",
97
+ arity: 3
98
+ },
99
+ {
100
+ name: "stagger",
101
+ arity: 3
102
+ },
103
+ {
104
+ name: "describe",
105
+ arity: 0
106
+ }
107
+ ];
108
+ /**
109
+ * The remaining authoring `window.glissade.<name>` FUNCTIONS beyond the node
110
+ * constructors / {@link HELPERS} / {@link SURFACE_CORE} — the fundamentals a
111
+ * no-build author reaches for that had no home in the curated lists: the core
112
+ * primitives (`key`/`signal`/`spring`/`cubicBezier`/`namedEasing`/`springTo`), the
113
+ * SVG-path parser (`pathFromSvg`), and the motion/clip-tier helpers
114
+ * (`glow`/`morph`/`typewriter`/`pulse`/`popIn`/`slideIn`/`presence`/`highlight`).
115
+ * Their ABSENCE red-lined valid no-build code (`track('x/o','number',[key(0,0)])`)
116
+ * under the ambient .d.ts; the bidirectional describe-lint gate now keeps this set
117
+ * complete (a public window.glissade export MUST be surfaced or explicitly exempt).
118
+ * `arity` = the runtime `Function.length` (informational).
119
+ */
120
+ const SURFACE_EXTRA = [
121
+ {
122
+ name: "key",
123
+ arity: 3
124
+ },
125
+ {
126
+ name: "signal",
127
+ arity: 2
128
+ },
129
+ {
130
+ name: "spring",
131
+ arity: 1
132
+ },
133
+ {
134
+ name: "cubicBezier",
135
+ arity: 4
136
+ },
137
+ {
138
+ name: "namedEasing",
139
+ arity: 1
140
+ },
141
+ {
142
+ name: "springTo",
143
+ arity: 4
144
+ },
145
+ {
146
+ name: "pathFromSvg",
147
+ arity: 1
148
+ },
149
+ {
150
+ name: "glow",
151
+ arity: 1
152
+ },
153
+ {
154
+ name: "morph",
155
+ arity: 4
156
+ },
157
+ {
158
+ name: "typewriter",
159
+ arity: 2
160
+ },
161
+ {
162
+ name: "pulse",
163
+ arity: 1
164
+ },
165
+ {
166
+ name: "popIn",
167
+ arity: 1
168
+ },
169
+ {
170
+ name: "slideIn",
171
+ arity: 2
172
+ },
173
+ {
174
+ name: "presence",
175
+ arity: 2
176
+ },
177
+ {
178
+ name: "highlight",
179
+ arity: 1
180
+ }
181
+ ];
182
+ /** Value exports that are runtime OBJECTS (not callable): the easing registry. */
183
+ const SURFACE_VALUE_OBJECTS = ["easings"];
184
+ /**
185
+ * The opaque, type-ONLY names the API surface references (they erase at runtime —
186
+ * `window.glissade.Paint` is `undefined`). `gs types --global` emits a best-effort
187
+ * alias per name; `gs describe --lint` guards they stay type-only (a type surfaced
188
+ * as a callable value is the ClipRegion-class drift this catches).
189
+ */
190
+ const SURFACE_TYPE_ONLY = [
191
+ "Paint",
192
+ "PathValue",
193
+ "FontAxes"
194
+ ];
195
+ /**
196
+ * Assemble the {@link SurfaceEntry} taxonomy from the same curated registries the
197
+ * rest of the manifest is built from (node factories + {@link HELPERS} + the core
198
+ * callables), so it can't drift. Deterministic: deduped by name, sorted.
199
+ */
200
+ function buildSurface() {
201
+ const out = [];
202
+ for (const name of SURFACE_CONSTRUCTORS) out.push({
203
+ name,
204
+ kind: "value",
205
+ iife: true,
206
+ form: "constructor"
207
+ });
208
+ for (const h of HELPERS) {
209
+ const arity = usageArity(h.usage);
210
+ out.push({
211
+ name: h.name,
212
+ kind: "value",
213
+ iife: true,
214
+ form: "function",
215
+ ...arity !== void 0 ? { arity } : {}
216
+ });
217
+ }
218
+ for (const c of SURFACE_CORE) out.push({
219
+ name: c.name,
220
+ kind: "value",
221
+ iife: true,
222
+ form: "function",
223
+ arity: c.arity
224
+ });
225
+ for (const c of SURFACE_EXTRA) out.push({
226
+ name: c.name,
227
+ kind: "value",
228
+ iife: true,
229
+ form: "function",
230
+ arity: c.arity
231
+ });
232
+ for (const name of SURFACE_VALUE_OBJECTS) out.push({
233
+ name,
234
+ kind: "value",
235
+ iife: true,
236
+ form: "object"
237
+ });
238
+ for (const name of SURFACE_TYPE_ONLY) out.push({
239
+ name,
240
+ kind: "type",
241
+ iife: false,
242
+ form: "type"
243
+ });
244
+ const seen = /* @__PURE__ */ new Set();
245
+ return out.filter((e) => seen.has(e.name) ? false : (seen.add(e.name), true)).sort((a, b) => a.name.localeCompare(b.name));
246
+ }
28
247
  /** Arity of a value type's numeric repr: vec2/vec2-arc → 2, number → 1; others (color/paint/path/string/boolean) carry no scalar arity. */
29
248
  function arityOf(type) {
30
249
  if (type === "number") return 1;
@@ -568,8 +787,9 @@ function describe(opts = {}) {
568
787
  props: mapComponentProps(c.props)
569
788
  })),
570
789
  createScene: "createScene({ size: { w, h }, children: Node[] }): Scene — media assets are declared on the Timeline document: timeline({ assets: { <id>: { kind: 'image'|'video', url } } }); an Image/Video node's `assetId` names an entry here.",
571
- subpaths: SUBPATHS
790
+ subpaths: SUBPATHS,
791
+ surface: buildSurface()
572
792
  };
573
793
  }
574
794
  //#endregion
575
- export { describe, registerExamples };
795
+ export { describe, registerExamples, usageArity };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glissade/scene",
3
- "version": "0.46.0",
3
+ "version": "0.47.0-pre.1",
4
4
  "description": "glissade scene graph: nodes, transforms, DisplayList emission. Renderer-agnostic; zero DOM/Node dependencies.",
5
5
  "license": "Apache-2.0",
6
6
  "engines": {
@@ -77,7 +77,7 @@
77
77
  ],
78
78
  "dependencies": {
79
79
  "yoga-layout": "^3.2.1",
80
- "@glissade/core": "0.46.0"
80
+ "@glissade/core": "0.47.0-pre.1"
81
81
  },
82
82
  "repository": {
83
83
  "type": "git",