@flatkit/player 0.1.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 +21 -0
- package/dist/chunk-BXKJAHHO.js +1681 -0
- package/dist/chunk-BXKJAHHO.js.map +1 -0
- package/dist/debug.d.ts +28 -0
- package/dist/debug.js +193 -0
- package/dist/debug.js.map +1 -0
- package/dist/index.d.ts +57 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -0
- package/dist/player-Bxx8wsSa.d.ts +252 -0
- package/package.json +51 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/headless.ts"],"sourcesContent":["// -----------------------------------------------------------------------------\n// headless.ts -- plays a Doc WITHOUT a real canvas and replays a gesture SCRIPT.\n//\n// Automatable verification of interactions (CI, LLM loop): we instantiate the\n// `FlatPlayer` on a fake canvas (client coords = scene coords, scale 1), fire\n// synthetic PointerEvents, and collect the emitted `send`s plus the final state\n// of the variables. Pure Node: stubs the missing DOM globals.\n// -----------------------------------------------------------------------------\nimport { FlatPlayer } from './player'\nimport { itemBoundsByName, dropZoneBounds } from '@flatkit/engine/groups'\nimport { isGroup } from '@flatkit/engine/layers'\nimport type { Doc, Item } from '@flatkit/types'\nexport type { Gesture } from './player' // defined on the player side (reused by `--record`)\nimport type { Gesture } from './player'\n\ntype Box = { minX: number; minY: number; maxX: number; maxY: number }\n/** Cap on the moves a `scratch` synthesizes (anti-DoS: a huge bbox / tiny brush must not blow up). */\nconst MAX_SWEEP = 2000\n\n/** First named item matching `name` (walks groups). Used to find the reveal interactor's brush. */\nfunction findItemByName(items: Item[], name: string): Item | null {\n for (const it of items) {\n if ('name' in it && it.name === name) return it\n if (isGroup(it)) for (const l of it.layers) { const r = findItemByName(l.items, name); if (r) return r }\n }\n return null\n}\n/** Brush radius (= grid) of the `reveal` interactor on a named target; default 24 if none. */\nfunction revealBrushFor(doc: Doc, name: string): number {\n let id: string | null = null\n for (const l of doc.layers) { const it = findItemByName(l.items, name); if (it) { id = it.id; break } }\n const inter = id ? doc.interactors?.find((x) => x.targetId === id) : undefined\n return inter?.grid && inter.grid > 0 ? inter.grid : 24\n}\n/** Boustrophedon sweep over `b` at ~`brush` spacing (cell centers), bounded to MAX_SWEEP points. */\nfunction sweepPoints(b: Box, brush: number): { x: number; y: number }[] {\n const w = b.maxX - b.minX, h = b.maxY - b.minY\n let step = Math.max(1, brush)\n let cols = Math.max(1, Math.ceil(w / step)), rows = Math.max(1, Math.ceil(h / step))\n if (cols * rows > MAX_SWEEP) { // too fine -> coarsen to stay bounded (coverage may be < 1; documented)\n const f = Math.sqrt((cols * rows) / MAX_SWEEP)\n step *= f; cols = Math.max(1, Math.ceil(w / step)); rows = Math.max(1, Math.ceil(h / step))\n }\n const pts: { x: number; y: number }[] = []\n for (let r = 0; r < rows; r++) {\n const y = Math.min(b.maxY, b.minY + (r + 0.5) * step)\n const cs = Array.from({ length: cols }, (_v, c) => c)\n if (r % 2) cs.reverse() // zig-zag: continuous stroke, no jump back to the left edge\n for (const c of cs) pts.push({ x: Math.min(b.maxX, b.minX + (c + 0.5) * step), y })\n }\n return pts\n}\n\nexport type PlayResult = {\n sends: { name: string; value?: number | string }[]\n vars: Record<string, number | number[]>\n steps?: TraceStep[] // present if `trace`: one record per gesture (inspection / debug-player)\n expectFailures?: string[] // mismatches reported by the `expect` gestures (empty/absent = all verified) -> exit != 0 in CLI\n}\n\n/** Trace of ONE gesture: its description, the `send`s emitted during it, and the variable diff. */\nexport type TraceStep = {\n gesture: string\n sends: { name: string; value?: number | string }[]\n changed: Record<string, [number | number[] | undefined, number | number[]]> // var -> [before, after]\n}\n\ntype Handlers = Record<string, (e: { clientX: number; clientY: number; pointerId: number }) => void>\n\nconst fakeCtx = (): CanvasRenderingContext2D =>\n new Proxy({}, {\n get: (_t, p) => (p === 'measureText' ? () => ({ width: 0 }) : p === 'getTransform' ? () => ({ a: 1, b: 0, c: 0, d: 1, e: 0, f: 0 }) : () => {}),\n set: () => true,\n }) as unknown as CanvasRenderingContext2D\n\nconst fakeCanvas = (handlers: Handlers, w: number, h: number): HTMLCanvasElement => ({\n getContext: () => fakeCtx(),\n getBoundingClientRect: () => ({ width: w, height: h, left: 0, top: 0, right: w, bottom: h }),\n addEventListener: (type: string, fn: Handlers[string]) => { handlers[type] = fn },\n removeEventListener: (type: string) => { delete handlers[type] },\n setPointerCapture: () => {},\n releasePointerCapture: () => {},\n style: {},\n} as unknown as HTMLCanvasElement)\n\n/** Stubs the missing DOM globals (pure Node); returns a restore function. */\nfunction ensureDomGlobals(): () => void {\n const g = globalThis as Record<string, unknown>\n const undo: (() => void)[] = []\n const set = (k: string, v: unknown) => { if (g[k] === undefined) { g[k] = v; undo.push(() => { delete g[k] }) } }\n set('window', { addEventListener: () => {}, removeEventListener: () => {}, devicePixelRatio: 1 })\n set('requestAnimationFrame', () => 0)\n set('cancelAnimationFrame', () => {})\n set('addEventListener', () => {})\n set('removeEventListener', () => {})\n return () => undo.forEach((f) => f())\n}\n\n/** Describes a gesture for the trace. */\nconst describeGesture = (g: Gesture): string =>\n g.type === 'drag' ? `drag ${g.source}->${g.target}` : g.type === 'tap' ? `tap ${g.target}`\n : g.type === 'connect' ? `connect ${g.source}->${g.target}` : g.type === 'scratch' ? `scratch ${g.target}`\n : g.type === 'set' ? `set ${g.name}=${g.value}` : g.type === 'wait' ? `wait ${g.frames}` : g.type === 'expect' ? 'expect' : `${g.type} (${g.x},${g.y})`\n\n/** Plays `doc`, replays `gestures`, returns the collected `send`s plus the final state of the variables.\n * `trace`: adds `steps` (sends + variable diff PER gesture) -- for inspection / the debug-player. */\nexport function playHeadless(doc: Doc, gestures: Gesture[], opts: { trace?: boolean } = {}): PlayResult {\n const restore = ensureDomGlobals()\n const handlers: Handlers = {}\n const sends: PlayResult['sends'] = []\n const pl = new FlatPlayer(fakeCanvas(handlers, doc.width, doc.height), doc, { input: true, padding: 0, render: false, onEvent: (e) => sends.push(e) })\n const ev = (x: number, y: number, id = 1) => ({ clientX: x, clientY: y, pointerId: id })\n const fire = (type: string, p: { x: number; y: number }, id = 1) => { const h = handlers[`pointer${type}`]; if (h) h(ev(p.x, p.y, id)) }\n // GRAB: the RESOLVED position of the object (expressions included -> we touch the object exactly where it is).\n const grabPoint = (name: string): { x: number; y: number } => {\n const c = pl.objectCenter(name)\n if (c) return c\n const b = itemBoundsByName(doc, name)\n if (!b) throw new Error(`gesture: object \"${name}\" not found in the scene`)\n return { x: (b.minX + b.maxX) / 2, y: (b.minY + b.maxY) / 2 }\n }\n // DROP: center of the drop zone (static bbox / hitbox) -- that is what the drop is tested against.\n const dropPoint = (name: string): { x: number; y: number } => {\n const b = dropZoneBounds(doc, name)\n if (!b) throw new Error(`gesture: zone \"${name}\" not found in the scene`)\n return { x: (b.minX + b.maxX) / 2, y: (b.minY + b.maxY) / 2 }\n }\n // `expect`: self-verified assertions. `sendCursor` = window of sends SINCE the last `expect`.\n let sendCursor = 0\n const expectFailures: string[] = []\n const applyGesture = (g: Gesture): void => {\n if (g.type === 'set') { pl.setVar(g.name, g.value); return }\n if (g.type === 'wait') { pl.stepSim(g.frames); return }\n if (g.type === 'drag') { const id = g.id ?? 1, t = dropPoint(g.target); fire('down', grabPoint(g.source), id); fire('move', t, id); fire('up', t, id); return }\n if (g.type === 'tap') { const id = g.id ?? 1, c = grabPoint(g.target); fire('down', c, id); fire('up', c, id); return }\n if (g.type === 'connect') { const id = g.id ?? 1, t = grabPoint(g.target); fire('down', grabPoint(g.source), id); fire('move', t, id); fire('up', t, id); return } // pull a link wire source -> target\n if (g.type === 'scratch') { // sweep the reveal target's bbox so its coverage reaches ~1\n const id = g.id ?? 1\n const b = itemBoundsByName(doc, g.target)\n if (!b) throw new Error(`gesture: object \"${g.target}\" not found in the scene`)\n const pts = sweepPoints(b, revealBrushFor(doc, g.target))\n fire('down', pts[0], id)\n for (let i = 1; i < pts.length; i++) fire('move', pts[i], id)\n fire('up', pts[pts.length - 1], id)\n return\n }\n if (g.type === 'expect') {\n const got = sends.slice(sendCursor).map((s) => s.name) // sequence of send names emitted since the last expect\n sendCursor = sends.length\n if (g.sends && JSON.stringify(got) !== JSON.stringify(g.sends)) expectFailures.push(`expect: expected sends [${g.sends.join(', ')}], received [${got.join(', ')}]`)\n if (g.vars) for (const [k, v] of Object.entries(g.vars)) { const cur = pl.getVar(k); if (JSON.stringify(cur) !== JSON.stringify(v)) expectFailures.push(`expect: ${k} expected ${JSON.stringify(v)}, got ${JSON.stringify(cur)}`) }\n return\n }\n fire(g.type, { x: g.x, y: g.y }, g.id) // low-level (down/move/up/cancel)\n }\n try {\n const steps: TraceStep[] = []\n for (const g of gestures) {\n if (!opts.trace) { applyGesture(g); continue }\n const before = pl.allVars(), sIdx = sends.length\n applyGesture(g)\n const after = pl.allVars()\n const changed: TraceStep['changed'] = {}\n for (const k of new Set([...Object.keys(before), ...Object.keys(after)]))\n if (JSON.stringify(before[k]) !== JSON.stringify(after[k])) changed[k] = [before[k], after[k]]\n steps.push({ gesture: describeGesture(g), sends: sends.slice(sIdx), changed })\n }\n return { sends, vars: pl.allVars(), ...(opts.trace ? { steps } : {}), ...(expectFailures.length ? { expectFailures } : {}) }\n } finally {\n pl.destroy()\n restore()\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
export { F as FlatPlayer, G as Gesture, P as PlayerOptions, s as sameOriginAssetResolver } from './player-Bxx8wsSa.js';
|
|
2
|
+
import { Region, Doc, Item, Layer } from '@flatkit/types';
|
|
3
|
+
export { Cel, Doc, Easing, Item, Keyframe, Layer, Path, Pose, Region, Seg, Subpath, Timeline, TimelineTrack } from '@flatkit/types';
|
|
4
|
+
import { ExprContext } from '@flatkit/engine/expr';
|
|
5
|
+
import { Transform } from '@flatkit/engine/transform';
|
|
6
|
+
export { evaluateTimeline, resolveInstanceFrame } from '@flatkit/engine/timeline';
|
|
7
|
+
export { resolveLayerAt } from '@flatkit/engine/cel';
|
|
8
|
+
export { clonePath, pathBBox, pathToBezier, pathToPolygons, polygonsToPath, transformPath, translatePath } from '@flatkit/engine/path';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Render context for a scope: fps (for `time` expressions) + expression context.
|
|
12
|
+
* `freezeNested` (EDITOR): we only animate the current scope; nested symbols are frozen
|
|
13
|
+
* at their frame 0 (their position follows the scope's tween, but their internal timeline does not play).
|
|
14
|
+
* The player leaves `freezeNested` absent -> full, composed animation.
|
|
15
|
+
*/
|
|
16
|
+
type RenderCtx = {
|
|
17
|
+
fps: number;
|
|
18
|
+
expr?: ExprContext;
|
|
19
|
+
freezeNested?: boolean;
|
|
20
|
+
image?: (assetId: string) => CanvasImageSource | null;
|
|
21
|
+
itemState?: (id: string) => {
|
|
22
|
+
hovered: number;
|
|
23
|
+
grabbed: number;
|
|
24
|
+
pressed: number;
|
|
25
|
+
} | undefined;
|
|
26
|
+
preview?: {
|
|
27
|
+
ids: Set<string>;
|
|
28
|
+
m: Transform;
|
|
29
|
+
};
|
|
30
|
+
filterCache?: Map<string, FilterCacheEntry>;
|
|
31
|
+
imageEpoch?: number;
|
|
32
|
+
};
|
|
33
|
+
/** Entry of the filtered composite cache: FINAL bitmap (content+tint+filter) in screen px at (ox,oy).
|
|
34
|
+
* `canvas` absent = we have only RECORDED the signature (1 observation frame before baking) -- used
|
|
35
|
+
* to NOT bake an object that moves every frame (unstable signature => we would always stay in miss). */
|
|
36
|
+
type FilterCacheEntry = {
|
|
37
|
+
canvas?: HTMLCanvasElement;
|
|
38
|
+
sig: string;
|
|
39
|
+
ox: number;
|
|
40
|
+
oy: number;
|
|
41
|
+
ow: number;
|
|
42
|
+
oh: number;
|
|
43
|
+
};
|
|
44
|
+
declare function applyTransform(ctx: CanvasRenderingContext2D, t: Transform): void;
|
|
45
|
+
/**
|
|
46
|
+
* Bezier path of a region (outline + holes), shiftable. Hybrid model: the
|
|
47
|
+
* subpaths without handles are smoothed (Catmull-Rom, matter look), those with handles
|
|
48
|
+
* render their literal cubic (see engine/path.ts).
|
|
49
|
+
*/
|
|
50
|
+
declare function regionPath(region: Region, dx?: number, dy?: number): Path2D;
|
|
51
|
+
/** Draws a list of ALREADY RESOLVED items (poses applied) at a frame. */
|
|
52
|
+
declare function renderItems(ctx: CanvasRenderingContext2D, doc: Doc, items: Item[], frame: number, hidden: Set<string> | null, seen: Set<string>, rctx: RenderCtx, parent?: Transform, depth?: number): void;
|
|
53
|
+
/** Draws a stack of layers at a frame (each layer resolves its content via the cels). */
|
|
54
|
+
declare function renderLayers(ctx: CanvasRenderingContext2D, doc: Doc, layers: Layer[], frame: number, hidden: Set<string> | null, seen: Set<string>, rctx: RenderCtx, parent?: Transform, // WORLD transform of the scope (for toLocal/toGlobal conversions in binding)
|
|
55
|
+
depth?: number): void;
|
|
56
|
+
|
|
57
|
+
export { applyTransform, regionPath, renderItems, renderLayers };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import {
|
|
2
|
+
FlatPlayer,
|
|
3
|
+
applyTransform,
|
|
4
|
+
regionPath,
|
|
5
|
+
renderItems,
|
|
6
|
+
renderLayers,
|
|
7
|
+
sameOriginAssetResolver
|
|
8
|
+
} from "./chunk-BXKJAHHO.js";
|
|
9
|
+
|
|
10
|
+
// src/index.ts
|
|
11
|
+
import { evaluateTimeline, resolveInstanceFrame } from "@flatkit/engine/timeline";
|
|
12
|
+
import { resolveLayerAt } from "@flatkit/engine/cel";
|
|
13
|
+
import { polygonsToPath, pathToPolygons, pathToBezier, transformPath, translatePath, pathBBox, clonePath } from "@flatkit/engine/path";
|
|
14
|
+
export {
|
|
15
|
+
FlatPlayer,
|
|
16
|
+
applyTransform,
|
|
17
|
+
clonePath,
|
|
18
|
+
evaluateTimeline,
|
|
19
|
+
pathBBox,
|
|
20
|
+
pathToBezier,
|
|
21
|
+
pathToPolygons,
|
|
22
|
+
polygonsToPath,
|
|
23
|
+
regionPath,
|
|
24
|
+
renderItems,
|
|
25
|
+
renderLayers,
|
|
26
|
+
resolveInstanceFrame,
|
|
27
|
+
resolveLayerAt,
|
|
28
|
+
sameOriginAssetResolver,
|
|
29
|
+
transformPath,
|
|
30
|
+
translatePath
|
|
31
|
+
};
|
|
32
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["// -----------------------------------------------------------------------------\n// runtime/index.ts -- public surface of the FlatInk runtime (player + drawing core).\n// Importable on its own, without anything from the editor. The played format = the FlatInk `Doc` JSON.\n// -----------------------------------------------------------------------------\nexport { FlatPlayer, sameOriginAssetResolver, type PlayerOptions } from './player'\n// `Gesture` stays here (FlatPlayer.stopRecording returns Gesture[]). The headless replay tools\n// (playHeadless, trace) live under `@flatkit/player/debug` — not needed for plain playback.\nexport type { Gesture } from './player'\nexport { renderLayers, renderItems, regionPath, applyTransform } from './drawScene'\nexport { evaluateTimeline, resolveInstanceFrame } from '@flatkit/engine/timeline'\nexport { resolveLayerAt } from '@flatkit/engine/cel'\nexport { polygonsToPath, pathToPolygons, pathToBezier, transformPath, translatePath, pathBBox, clonePath } from '@flatkit/engine/path'\nexport type { Doc, Timeline, TimelineTrack, Keyframe, Easing, Item, Layer, Region, Cel, Pose, Path, Subpath, Seg } from '@flatkit/types'\n"],"mappings":";;;;;;;;;;AASA,SAAS,kBAAkB,4BAA4B;AACvD,SAAS,sBAAsB;AAC/B,SAAS,gBAAgB,gBAAgB,cAAc,eAAe,eAAe,UAAU,iBAAiB;","names":[]}
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import { Doc, Asset, Point } from '@flatkit/types';
|
|
2
|
+
|
|
3
|
+
/** A replayable gesture (`--play` / `--record` format). Coords in SCENE units. `id` = pointerId (default 1).
|
|
4
|
+
* Prefer SEMANTIC gestures (`drag`/`tap` by object NAME): robust, readable, and it is the engine that
|
|
5
|
+
* resolves the coords (cf. [[flatink-semantic-gestures]]). The low-level gestures remain for special cases. */
|
|
6
|
+
type Gesture = {
|
|
7
|
+
type: 'drag';
|
|
8
|
+
source: string;
|
|
9
|
+
target: string;
|
|
10
|
+
id?: number;
|
|
11
|
+
} | {
|
|
12
|
+
type: 'tap';
|
|
13
|
+
target: string;
|
|
14
|
+
id?: number;
|
|
15
|
+
} | {
|
|
16
|
+
type: 'scratch';
|
|
17
|
+
target: string;
|
|
18
|
+
id?: number;
|
|
19
|
+
} | {
|
|
20
|
+
type: 'connect';
|
|
21
|
+
source: string;
|
|
22
|
+
target: string;
|
|
23
|
+
id?: number;
|
|
24
|
+
} | {
|
|
25
|
+
type: 'down' | 'move' | 'up' | 'cancel';
|
|
26
|
+
x: number;
|
|
27
|
+
y: number;
|
|
28
|
+
id?: number;
|
|
29
|
+
} | {
|
|
30
|
+
type: 'set';
|
|
31
|
+
name: string;
|
|
32
|
+
value: number;
|
|
33
|
+
} | {
|
|
34
|
+
type: 'wait';
|
|
35
|
+
frames: number;
|
|
36
|
+
} | {
|
|
37
|
+
type: 'expect';
|
|
38
|
+
sends?: string[];
|
|
39
|
+
vars?: Record<string, number | number[]>;
|
|
40
|
+
};
|
|
41
|
+
type PlayerOptions = {
|
|
42
|
+
autoplay?: boolean;
|
|
43
|
+
loop?: boolean;
|
|
44
|
+
padding?: number;
|
|
45
|
+
audio?: boolean;
|
|
46
|
+
input?: boolean;
|
|
47
|
+
render?: boolean;
|
|
48
|
+
image?: (assetId: string) => CanvasImageSource | null;
|
|
49
|
+
resolveAsset?: (asset: Asset) => string | null;
|
|
50
|
+
onEvent?: (event: {
|
|
51
|
+
name: string;
|
|
52
|
+
value?: number | string;
|
|
53
|
+
}) => void;
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Resolver for EXTERNAL (non-embedded) assets. Pass it as `PlayerOptions.resolveAsset` to serve media from
|
|
57
|
+
* a host-controlled folder instead of embedding everything as `data:`. It treats `asset.data` as a RELATIVE
|
|
58
|
+
* key, resolves it against the host-trusted `baseUrl`, and returns the URL only if it stays SAME-ORIGIN as
|
|
59
|
+
* baseUrl. An embedded `data:` URI is passed through; any absolute URL / scheme / protocol-relative `//host`
|
|
60
|
+
* in `asset.data` (a document trying to pick its own origin) yields null. The HOST owns the origin; the
|
|
61
|
+
* untrusted document only supplies a key — so the no-arbitrary-fetch contract still holds.
|
|
62
|
+
*/
|
|
63
|
+
declare function sameOriginAssetResolver(baseUrl: string): (asset: Asset) => string | null;
|
|
64
|
+
declare class FlatPlayer {
|
|
65
|
+
private readonly canvas;
|
|
66
|
+
private readonly ctx;
|
|
67
|
+
private doc;
|
|
68
|
+
private readonly loop;
|
|
69
|
+
private readonly pad;
|
|
70
|
+
private dpr;
|
|
71
|
+
private cssW;
|
|
72
|
+
private cssH;
|
|
73
|
+
private view;
|
|
74
|
+
private frame;
|
|
75
|
+
private playing;
|
|
76
|
+
private raf;
|
|
77
|
+
private last;
|
|
78
|
+
private simAcc;
|
|
79
|
+
private prevSimVars;
|
|
80
|
+
private simAlpha;
|
|
81
|
+
private simActive;
|
|
82
|
+
private audioOn;
|
|
83
|
+
private readonly onEvent?;
|
|
84
|
+
private renderOn;
|
|
85
|
+
private readonly imageProvider?;
|
|
86
|
+
private readonly resolveAsset;
|
|
87
|
+
private recording;
|
|
88
|
+
private recordFrame;
|
|
89
|
+
private readonly filterCache;
|
|
90
|
+
private imageEpoch;
|
|
91
|
+
private activeSources;
|
|
92
|
+
private vars;
|
|
93
|
+
private procs;
|
|
94
|
+
private valueFuncs;
|
|
95
|
+
private funcDepth;
|
|
96
|
+
private readonly mouse;
|
|
97
|
+
private readonly heldKeys;
|
|
98
|
+
private readonly keyProxy;
|
|
99
|
+
private hovered;
|
|
100
|
+
private hoverIds;
|
|
101
|
+
private selfChannels;
|
|
102
|
+
private selfParent;
|
|
103
|
+
private namedCache;
|
|
104
|
+
private namedFrame;
|
|
105
|
+
private grabbed;
|
|
106
|
+
private grabStart;
|
|
107
|
+
private dragActive;
|
|
108
|
+
private readonly revealStates;
|
|
109
|
+
private longPressTimer;
|
|
110
|
+
private lastFrameInt;
|
|
111
|
+
private readonly onResize;
|
|
112
|
+
/** Invalidates the named-objects cache (input changed outside of a frame advance). */
|
|
113
|
+
private bustNamed;
|
|
114
|
+
private readonly onKeyDown;
|
|
115
|
+
private readonly onKeyUp;
|
|
116
|
+
private readonly onPointerLeave;
|
|
117
|
+
private worldPoint;
|
|
118
|
+
/**
|
|
119
|
+
* Target of an event at a point: we walk ALL the hit chains (top to bottom) and, within each,
|
|
120
|
+
* from deepest to root. The first item carrying a handler for `event` wins. This way a click
|
|
121
|
+
* "falls through" a non-interactive item placed on top down to the clickable one below, instead
|
|
122
|
+
* of being swallowed by it.
|
|
123
|
+
*/
|
|
124
|
+
private pickTarget;
|
|
125
|
+
private interactorFor;
|
|
126
|
+
/** Is the drag active? `enabled` absent = always; otherwise true iff the expression is != 0. */
|
|
127
|
+
private interactorEnabled;
|
|
128
|
+
/** Topmost grabbable item carrying an ACTIVE (drag) interactor, at a point. */
|
|
129
|
+
private pickInteractor;
|
|
130
|
+
/** Applies the current drag: position = pointer + grab offset, then snap, then confine; writes varX/varY.
|
|
131
|
+
* Snap/confine are in WORLD space (where the visual grid and the zone bbox live); the result is brought back into
|
|
132
|
+
* the object's PARENT space (`parentInv` cached at grab time -- no scene walk per movement). */
|
|
133
|
+
/** Writes a gesture output: simple variable `name`, or array element `name[idx]` (idx is EVALUATED).
|
|
134
|
+
* The indexed form is the natural output under `each` (e.g. `drag hx[i], hy[i]` -> `hx[0]`... after unfolding). */
|
|
135
|
+
private writeOut;
|
|
136
|
+
private applyDrag;
|
|
137
|
+
/** Reveal state for a target: the grid of cells (side = brush) over its WORLD bbox, with the ticked cells
|
|
138
|
+
* PERSISTED across grabs (`revealStates`) so coverage accumulates monotonically over several strokes. */
|
|
139
|
+
private revealGridFor;
|
|
140
|
+
/** On release of a `link`: 1st target (named child of the group) containing the pointer -> index 1..n (0 = none).
|
|
141
|
+
* If linked, the wire end (endX/endY) sticks to the target center; otherwise it stays at the pointer (the author handles
|
|
142
|
+
* the "return" via target == 0). Several links coexist: one `link` interactor per source object. */
|
|
143
|
+
private resolveLink;
|
|
144
|
+
/** On release: `when dropped on Zone` whose tested point falls within the zone bbox.
|
|
145
|
+
* Tested point = the object's CENTER by default, or the POINTER if `at pointer`. Zone = the group's
|
|
146
|
+
* explicit `hitbox` if present, otherwise the (static) bbox of its content. */
|
|
147
|
+
private fireDrops;
|
|
148
|
+
private fireEvent;
|
|
149
|
+
private readonly onPointerMove;
|
|
150
|
+
private readonly onPointerDown;
|
|
151
|
+
private readonly onPointerUp;
|
|
152
|
+
private readonly onPointerCancel;
|
|
153
|
+
private cancelLongPress;
|
|
154
|
+
private clearGrab;
|
|
155
|
+
/** Surface exposed to the action interpreter (frame-actions, future onClick). */
|
|
156
|
+
private readonly host;
|
|
157
|
+
constructor(canvas: HTMLCanvasElement, doc: Doc, opts?: PlayerOptions);
|
|
158
|
+
/**
|
|
159
|
+
* Timelines of "active" symbols (referenced by >=1 instance), deduplicated,
|
|
160
|
+
* with a representative local frame. NB (v1): single playhead -> the symbol
|
|
161
|
+
* actions share the global state; gotoFrame/play acts on the root.
|
|
162
|
+
*/
|
|
163
|
+
private activeSymbolTimelines;
|
|
164
|
+
/** Actions on load (onLoad): root + active symbols. */
|
|
165
|
+
private fireLoad;
|
|
166
|
+
/** (Re)compiles the available functions: imported packages (`use ...`) + doc functions (`fn ...`,
|
|
167
|
+
* which TAKE PRECEDENCE on a name clash). -> procedures + value functions. */
|
|
168
|
+
private buildFunctions;
|
|
169
|
+
/** Calls a procedure `fn name(p) { ... }`: binds the params (save/restore), bounds the recursion. */
|
|
170
|
+
private callProc;
|
|
171
|
+
/** Runtime context for expressions: variables (flattened), mouse, keys, random, value functions,
|
|
172
|
+
* + scene objects by name (`Hero.x`, cf. sceneRefs). */
|
|
173
|
+
private exprCtx;
|
|
174
|
+
private evalNumber;
|
|
175
|
+
/**
|
|
176
|
+
* Emits a `send` event toward the host. Silent no-op if no `onEvent` is provided
|
|
177
|
+
* (e.g. editor preview). Defense-in-depth validation (the parser already guarantees the name):
|
|
178
|
+
* conforming name, finite number (NaN -> 0, DSL convention), text <= MAX_SEND_TEXT (truncated).
|
|
179
|
+
* If the host callback throws, we catch and log -- the player does not break.
|
|
180
|
+
*/
|
|
181
|
+
private emit;
|
|
182
|
+
/** Live content of a Text item resolved by id OR name (for `text("...")`). `''` + warning if absent. */
|
|
183
|
+
private textContent;
|
|
184
|
+
/**
|
|
185
|
+
* Looks up a Text item in the scene (layers + groups) and the library symbols.
|
|
186
|
+
* Resolves by `id` first (stable id set via `text "..." as "<id>"`), then by `name` as a fallback --
|
|
187
|
+
* like the rest of the text format references by name (`object "x"`, `instance "Sym" as "y"`).
|
|
188
|
+
*/
|
|
189
|
+
private findText;
|
|
190
|
+
/** Plays an audio clip (asset) as a one-shot (`sound "id"` DSL). No-op if audio is off / asset absent. */
|
|
191
|
+
private playSound;
|
|
192
|
+
get fps(): number;
|
|
193
|
+
get duration(): number;
|
|
194
|
+
get currentFrame(): number;
|
|
195
|
+
get isPlaying(): boolean;
|
|
196
|
+
/**
|
|
197
|
+
* Reads a state variable (Layer B) from the host: score, difficulty... `undefined` if absent.
|
|
198
|
+
* Returns a COPY of the arrays (the host cannot mutate the internal state by reference).
|
|
199
|
+
*/
|
|
200
|
+
getVar(name: string): number | number[] | undefined;
|
|
201
|
+
/** Snapshot (copied) of all the state variables -- for debugging / the headless harness. */
|
|
202
|
+
allVars(): Record<string, number | number[]>;
|
|
203
|
+
/** Starts recording (clears the previous one). Play the activity by hand, then `stopRecording()`. */
|
|
204
|
+
startRecording(): void;
|
|
205
|
+
/** Stops recording and returns the gesture script (replayable by `--play` / `playHeadless`). */
|
|
206
|
+
stopRecording(): Gesture[];
|
|
207
|
+
get isRecording(): boolean;
|
|
208
|
+
/** Center (RESOLVED origin, expressions included) of a named object, in world coords -- for the
|
|
209
|
+
* semantic gestures `drag`/`tap` by name. `null` if the object does not exist. */
|
|
210
|
+
objectCenter(name: string): Point | null;
|
|
211
|
+
/** Captures a gesture (no-op outside recording). Inserts a `wait` = frames elapsed since the last gesture. */
|
|
212
|
+
private record;
|
|
213
|
+
/**
|
|
214
|
+
* Writes a state variable (Layer B) from the host, then redraws -> bidirectional
|
|
215
|
+
* driving channel (the host sets the difficulty, injects a value, etc.). Clones the arrays.
|
|
216
|
+
*/
|
|
217
|
+
setVar(name: string, value: number | number[]): void;
|
|
218
|
+
/** Replaces the played document (resets the framing + the variables, keeps the frame). */
|
|
219
|
+
load(doc: Doc): void;
|
|
220
|
+
private measure;
|
|
221
|
+
/** Draws the current frame (pure, without advancing time). */
|
|
222
|
+
render(): void;
|
|
223
|
+
/** Interaction state of an item for `self.hovered`/`self.grabbed`/`self.pressed` in its channel exprs.
|
|
224
|
+
* Returns undefined when the item is neither hovered nor grabbed (the cheap, common path → flags 0). */
|
|
225
|
+
private itemStateFor;
|
|
226
|
+
private imageFor;
|
|
227
|
+
seek(frame: number): void;
|
|
228
|
+
/**
|
|
229
|
+
* Advances the simulation by `steps` FIXED steps (60 Hz) without RAF: runs `onEnterFrame`
|
|
230
|
+
* (root + active symbols) and advances the playhead as if real time elapsed.
|
|
231
|
+
* Used by the headless mode (`--play`, `wait` gesture) to let a physics simulation
|
|
232
|
+
* unfold between two gestures -- in Node, requestAnimationFrame does not exist.
|
|
233
|
+
*/
|
|
234
|
+
stepSim(steps: number): void;
|
|
235
|
+
get audioEnabled(): boolean;
|
|
236
|
+
/** Enables/disables audio (cuts immediately if off; (re)starts if on and playing). */
|
|
237
|
+
setAudio(on: boolean): void;
|
|
238
|
+
private stopAudio;
|
|
239
|
+
private decodeAudio;
|
|
240
|
+
/** (Re)schedules the audio clips for a playback starting from `fromFrame`. */
|
|
241
|
+
private startAudio;
|
|
242
|
+
/** Triggers the frame-actions when the playhead enters a new whole frame. */
|
|
243
|
+
private fireFrameActions;
|
|
244
|
+
play(): void;
|
|
245
|
+
pause(): void;
|
|
246
|
+
toggle(): void;
|
|
247
|
+
stop(): void;
|
|
248
|
+
/** Releases the listeners. To be called when the player is no longer used. */
|
|
249
|
+
destroy(): void;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
export { FlatPlayer as F, type Gesture as G, type PlayerOptions as P, sameOriginAssetResolver as s };
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@flatkit/player",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "The lightweight FlatInk player: load a .flatpack and play it in a <canvas>. No editor, no heavy deps.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Zwyk Studio",
|
|
7
|
+
"homepage": "http://flatink.zwyk-studio.com/",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/zwykstudio/flatkit.git",
|
|
11
|
+
"directory": "packages/player"
|
|
12
|
+
},
|
|
13
|
+
"bugs": "https://github.com/zwykstudio/flatkit/issues",
|
|
14
|
+
"keywords": [
|
|
15
|
+
"flatink",
|
|
16
|
+
"flatpack",
|
|
17
|
+
"animation",
|
|
18
|
+
"canvas",
|
|
19
|
+
"player",
|
|
20
|
+
"interactive"
|
|
21
|
+
],
|
|
22
|
+
"type": "module",
|
|
23
|
+
"sideEffects": false,
|
|
24
|
+
"main": "./dist/index.js",
|
|
25
|
+
"types": "./dist/index.d.ts",
|
|
26
|
+
"exports": {
|
|
27
|
+
".": {
|
|
28
|
+
"types": "./dist/index.d.ts",
|
|
29
|
+
"import": "./dist/index.js"
|
|
30
|
+
},
|
|
31
|
+
"./debug": {
|
|
32
|
+
"types": "./dist/debug.d.ts",
|
|
33
|
+
"import": "./dist/debug.js"
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"files": [
|
|
37
|
+
"dist"
|
|
38
|
+
],
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@flatkit/engine": "0.1.0",
|
|
41
|
+
"@flatkit/types": "0.1.0"
|
|
42
|
+
},
|
|
43
|
+
"publishConfig": {
|
|
44
|
+
"access": "public"
|
|
45
|
+
},
|
|
46
|
+
"scripts": {
|
|
47
|
+
"build": "tsup",
|
|
48
|
+
"typecheck": "tsc -p tsconfig.json"
|
|
49
|
+
},
|
|
50
|
+
"module": "./dist/index.js"
|
|
51
|
+
}
|