@motionscript/ui 0.1.0-alpha.0 → 0.1.0-alpha.3

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.
Files changed (46) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/browser/chunks/chunk-SFBJ6J3M.js +2 -0
  3. package/dist/browser/chunks/chunk-SFBJ6J3M.js.map +7 -0
  4. package/dist/browser/index.js +1 -1
  5. package/dist/browser/index.js.map +3 -3
  6. package/dist/browser/kit.js +1 -1
  7. package/dist/browser/manifest.json +2 -2
  8. package/dist/button/button.d.ts +6 -4
  9. package/dist/button/button.d.ts.map +1 -1
  10. package/dist/button/button.js +10 -10
  11. package/dist/button/button.js.map +1 -1
  12. package/dist/cursor/cursor.d.ts +1 -1
  13. package/dist/cursor/cursor.d.ts.map +1 -1
  14. package/dist/cursor/cursor.js +1 -1
  15. package/dist/cursor/cursor.js.map +1 -1
  16. package/dist/kit/control-icons.d.ts +1 -1
  17. package/dist/kit/control-icons.d.ts.map +1 -1
  18. package/dist/kit/control-icons.js +1 -1
  19. package/dist/kit/control-icons.js.map +1 -1
  20. package/dist/kit/control-node.d.ts +1 -1
  21. package/dist/kit/control-node.d.ts.map +1 -1
  22. package/dist/kit/control-node.js +1 -1
  23. package/dist/kit/control-node.js.map +1 -1
  24. package/dist/kit/cursor-outline.d.ts +1 -1
  25. package/dist/kit/cursor-outline.d.ts.map +1 -1
  26. package/dist/kit/cursor-outline.js +1 -1
  27. package/dist/kit/cursor-outline.js.map +1 -1
  28. package/dist/nodes.d.ts +1 -1
  29. package/dist/switch/switch.d.ts +1 -1
  30. package/dist/switch/switch.d.ts.map +1 -1
  31. package/dist/switch/switch.js +2 -2
  32. package/dist/switch/switch.js.map +1 -1
  33. package/dist/window/window.d.ts +1 -1
  34. package/dist/window/window.d.ts.map +1 -1
  35. package/dist/window/window.js +1 -1
  36. package/dist/window/window.js.map +1 -1
  37. package/package.json +4 -3
  38. package/src/button/button.ts +15 -12
  39. package/src/cursor/cursor.ts +1 -1
  40. package/src/kit/control-icons.ts +1 -1
  41. package/src/kit/control-node.ts +1 -1
  42. package/src/kit/cursor-outline.ts +1 -1
  43. package/src/switch/switch.ts +2 -2
  44. package/src/window/window.ts +1 -1
  45. package/dist/browser/chunks/chunk-W7G2N4A4.js +0 -2
  46. package/dist/browser/chunks/chunk-W7G2N4A4.js.map +0 -7
@@ -1 +1 @@
1
- {"version":3,"file":"cursor-outline.js","sourceRoot":"","sources":["../../src/kit/cursor-outline.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The artwork behind the Cursor node: two pointers, drawn the way an operating\n * system draws them.\n *\n * ## Two contours, not one shape and a stroke\n *\n * A real cursor is a **white body inside a black keyline** — that is what makes\n * it legible over a dark window and a light one both, and it is not decoration\n * anybody chose. So each glyph here is two closed contours: the outer\n * silhouette (body *plus* keyline) and the body inside it. The node paints the\n * outer one in the keyline colour and the inner one over it in the body colour,\n * and the keyline is whatever gap that leaves.\n *\n * That is deliberately **not** a fill with a stroke round it, and the reason is\n * the resize handle. A stroke's weight is a pixel count, and this glyph is\n * stretched onto whatever box the node has — so a weight that looked right at\n * 32px would be a hairline at 400 and a blob at 16. Baking the keyline into the\n * geometry makes it a *fraction of the drawing*, which is what it is on screen,\n * and it scales with everything else for free.\n *\n * ## The author box\n *\n * Both glyphs are normalized into one **32 × 32 box, y-down, origin top-left**\n * on the way in ({@link prepare}), fitted uniformly and anchored at the\n * top-left corner. Three things follow, all of them the point:\n *\n * - The two share a box, so changing the type dropdown swaps the drawing\n * without moving or resizing the node.\n * - The fit is *uniform*, so neither is distorted to fill a box it doesn't have\n * the proportions of. A glyph narrower than the box leaves the slack on its\n * right, which is empty space inside the selection rectangle and nothing more.\n * - The anchor is the top-left, which is where a pointer's **hotspot** is. A\n * cursor placed at (x, y) points at (x, y), the way the real one does.\n *\n * Normalizing at load rather than by hand is what lets the sources below stay\n * *verbatim* — they are the artwork as drawn, in their own viewBoxes, and\n * nobody has to re-derive a coordinate to move one into this module.\n */\n\nimport { pathOps, type VectorPath, type Vector2 } from \"@motionscript/core\"\n\n/**\n * The pointers, in the order the dropdown offers them.\n *\n * Two, and named for the CSS keywords rather than for what they look like:\n * `default` is the arrow and `pointer` is the hand you get over a link. That\n * vocabulary is the one anybody reaching for this node already has, and it is\n * the one the list grows in — `text`, `grab`, `crosshair` and the rest are each\n * a pair of contours away.\n */\nexport const CURSOR_TYPES = [\"default\", \"pointer\"] as const\n\nexport type CursorType = (typeof CURSOR_TYPES)[number]\n\n/**\n * The looks a cursor can be drawn in.\n *\n * One today, and the axis exists anyway because a second is a different\n * *drawing* rather than a setting: the macOS arrow is black with a white\n * keyline and has a silhouette of its own, so it arrives as another pair of\n * contours in {@link SOURCES} plus a row in {@link CURSOR_LOOKS} — not as a\n * colour control on the node. Keeping the axis is what makes that an addition\n * instead of a migration.\n *\n * While there is only one, the studio renders no dropdown for it: a control\n * with a single answer is a click that asks nothing. See the schema entry in\n * `model/appearance/schema.ts`, which says where to put it back.\n */\nexport const CURSOR_STYLES = [\"windows\"] as const\n\nexport type CursorStyle = (typeof CURSOR_STYLES)[number]\n\n/** The glyph a new Cursor node opens on: the arrow everybody pictures. */\nexport const DEFAULT_CURSOR_TYPE: CursorType = \"default\"\n\n/** …drawn the way the machine most people are looking at draws it. */\nexport const DEFAULT_CURSOR_STYLE: CursorStyle = \"windows\"\n\n/** The side of the square box both glyphs are normalized into. */\nexport const CURSOR_UNITS = 32\n\n/**\n * The side of the box a cursor node is **born at**, in scene units.\n *\n * A real pointer's own size: both Windows and macOS ship their cursors as 32×32\n * logical pixels, so a node this size in a 1920×1080 composition is the size the\n * thing actually is on a 1080p screen. That matters more than it sounds — a\n * cursor drawn four times life size doesn't read as a big cursor, it reads as a\n * scene shot at a different resolution from the interface under it.\n *\n * It is deliberately the *same number* as {@link CURSOR_UNITS} rather than a\n * multiple of it, and the coincidence is the point: the author box was chosen at\n * 32 because that is what a cursor is. See `model/natural-size.ts`, which is\n * what puts a node back to this after it has been dragged.\n */\nexport const CURSOR_SIZE = 32\n\n/** What a style paints its two contours with. */\nexport interface CursorLook {\n /** The body inside the keyline. */\n body: string\n /** The outline round it, which is the outer contour showing through. */\n keyline: string\n}\n\n/**\n * The colours each look is drawn in.\n *\n * Not defaults an author can change: a cursor's colours are what make it that\n * cursor, and a white-on-black Windows arrow repainted pink is not a stylized\n * cursor but a mistake. Hence the node exposes no Fills or Strokes section at\n * all — see `CURSOR_NODE_KEY`.\n */\nexport const CURSOR_LOOKS: Record<CursorStyle, CursorLook> = {\n windows: { body: \"#ffffff\", keyline: \"#000000\" },\n}\n\n/**\n * The look a style names, falling back to the default for one this build\n * doesn't know — a row written by a newer client, which should draw a cursor\n * rather than nothing.\n */\nexport function cursorLook(style: CursorStyle): CursorLook {\n return CURSOR_LOOKS[style] ?? CURSOR_LOOKS[DEFAULT_CURSOR_STYLE]\n}\n\n/** A cursor's two contours: the outer silhouette, and the body inside it. */\nexport interface CursorArtwork {\n /** Body *and* keyline — the whole shape, painted in the keyline colour. */\n keyline: VectorPath\n /** The body, painted over it. What is left showing is the keyline. */\n body: VectorPath\n}\n\n/**\n * The artwork, verbatim, in whatever viewBox it was drawn in.\n *\n * Each entry is one SVG `<path>` split at its second `M`: these are drawn as a\n * single two-subpath path with an even-odd fill, which paints the keyline and\n * leaves the body transparent. Splitting them is what lets the body be painted\n * too, and it is the only edit made to either.\n *\n * Keyed by style first, because a second style is a second drawing rather than\n * a recolouring of this one.\n */\nconst SOURCES: Record<\n CursorStyle,\n Record<CursorType, { keyline: string; body: string }>\n> = {\n windows: {\n // The arrow, drawn in a 50 x 50 box. The run of near-identical curves round\n // (14.8, 5) is the trace of its tip and is left exactly as it came: it is a\n // few dozen bytes, and \"tidying\" a traced outline is how a shape stops\n // matching the thing it was traced from.\n default: {\n keyline:\n \"M 14.78125 5 C 14.75 5.007813 14.71875 5.019531 14.6875 5.03125 C 14.644531 5.050781 14.601563 5.070313 14.5625 5.09375 C 14.550781 5.09375 14.542969 5.09375 14.53125 5.09375 C 14.511719 5.101563 14.488281 5.113281 14.46875 5.125 C 14.457031 5.136719 14.449219 5.144531 14.4375 5.15625 C 14.425781 5.167969 14.417969 5.175781 14.40625 5.1875 C 14.375 5.207031 14.34375 5.226563 14.3125 5.25 C 14.289063 5.269531 14.269531 5.289063 14.25 5.3125 C 14.238281 5.332031 14.226563 5.355469 14.21875 5.375 C 14.183594 5.414063 14.152344 5.457031 14.125 5.5 C 14.113281 5.511719 14.105469 5.519531 14.09375 5.53125 C 14.09375 5.542969 14.09375 5.550781 14.09375 5.5625 C 14.082031 5.582031 14.070313 5.605469 14.0625 5.625 C 14.050781 5.636719 14.042969 5.644531 14.03125 5.65625 C 14.03125 5.675781 14.03125 5.699219 14.03125 5.71875 C 14.019531 5.757813 14.007813 5.800781 14 5.84375 C 14 5.875 14 5.90625 14 5.9375 C 14 5.949219 14 5.957031 14 5.96875 C 14 5.980469 14 5.988281 14 6 C 13.996094 6.050781 13.996094 6.105469 14 6.15625 L 14 39 C 14.003906 39.398438 14.242188 39.757813 14.609375 39.914063 C 14.972656 40.070313 15.398438 39.992188 15.6875 39.71875 L 22.9375 32.90625 L 28.78125 46.40625 C 28.890625 46.652344 29.09375 46.847656 29.347656 46.941406 C 29.601563 47.035156 29.882813 47.023438 30.125 46.90625 L 34.5 44.90625 C 34.996094 44.679688 35.21875 44.09375 35 43.59375 L 28.90625 30.28125 L 39.09375 29.40625 C 39.496094 29.378906 39.84375 29.113281 39.976563 28.730469 C 40.105469 28.347656 39.992188 27.921875 39.6875 27.65625 L 15.84375 5.4375 C 15.796875 5.378906 15.746094 5.328125 15.6875 5.28125 C 15.648438 5.234375 15.609375 5.195313 15.5625 5.15625 C 15.550781 5.15625 15.542969 5.15625 15.53125 5.15625 C 15.511719 5.132813 15.492188 5.113281 15.46875 5.09375 C 15.457031 5.09375 15.449219 5.09375 15.4375 5.09375 C 15.386719 5.070313 15.335938 5.046875 15.28125 5.03125 C 15.269531 5.03125 15.261719 5.03125 15.25 5.03125 C 15.230469 5.019531 15.207031 5.007813 15.1875 5 C 15.175781 5 15.167969 5 15.15625 5 C 15.136719 5 15.113281 5 15.09375 5 C 15.082031 5 15.074219 5 15.0625 5 C 15.042969 5 15.019531 5 15 5 C 14.988281 5 14.980469 5 14.96875 5 C 14.9375 5 14.90625 5 14.875 5 C 14.84375 5 14.8125 5 14.78125 5 Z\",\n body: \"M 16 8.28125 L 36.6875 27.59375 L 27.3125 28.40625 C 26.992188 28.4375 26.707031 28.621094 26.546875 28.902344 C 26.382813 29.179688 26.367188 29.519531 26.5 29.8125 L 32.78125 43.5 L 30.21875 44.65625 L 24.21875 30.8125 C 24.089844 30.515625 23.828125 30.296875 23.511719 30.230469 C 23.195313 30.160156 22.863281 30.25 22.625 30.46875 L 16 36.6875 Z\",\n },\n // The pointing hand, drawn in a 32 x 32 box. The notches along the top of\n // the body contour are the gaps between the folded fingers — they are part\n // of the *body*, which is why the keyline shows through them.\n pointer: {\n keyline:\n \"M 13 2 C 11.355469 2 10 3.355469 10 5 L 10 16.8125 L 9.34375 16.125 L 9.09375 15.90625 C 7.941406 14.753906 6.058594 14.753906 4.90625 15.90625 C 3.753906 17.058594 3.753906 18.941406 4.90625 20.09375 L 4.90625 20.125 L 13.09375 28.21875 L 13.15625 28.25 L 13.1875 28.3125 C 14.535156 29.324219 16.253906 30 18.1875 30 L 19.90625 30 C 24.441406 30 28.09375 26.347656 28.09375 21.8125 L 28.09375 14 C 28.09375 12.355469 26.738281 11 25.09375 11 C 24.667969 11 24.273438 11.117188 23.90625 11.28125 C 23.578125 9.980469 22.394531 9 21 9 C 20.234375 9 19.53125 9.300781 19 9.78125 C 18.46875 9.300781 17.765625 9 17 9 C 16.648438 9 16.316406 9.074219 16 9.1875 L 16 5 C 16 3.355469 14.644531 2 13 2 Z\",\n body: \"M 13 4 C 13.554688 4 14 4.445313 14 5 L 14 16 L 16 16 L 16 12 C 16 11.445313 16.445313 11 17 11 C 17.554688 11 18 11.445313 18 12 L 18 16 L 20 16 L 20 12 C 20 11.445313 20.445313 11 21 11 C 21.554688 11 22 11.445313 22 12 L 22 16 L 24.09375 16 L 24.09375 14 C 24.09375 13.445313 24.539063 13 25.09375 13 C 25.648438 13 26.09375 13.445313 26.09375 14 L 26.09375 21.8125 C 26.09375 25.277344 23.371094 28 19.90625 28 L 18.1875 28 C 16.722656 28 15.457031 27.476563 14.40625 26.6875 L 6.3125 18.6875 C 5.867188 18.242188 5.867188 17.757813 6.3125 17.3125 C 6.757813 16.867188 7.242188 16.867188 7.6875 17.3125 L 12 21.625 L 12 5 C 12 4.445313 12.445313 4 13 4 Z\",\n },\n },\n}\n\n/**\n * Moves one glyph out of the viewBox it was drawn in and into the author box:\n * scaled uniformly to fit, anchored at the top-left corner.\n *\n * The two contours are measured **together** and mapped by the same transform,\n * which is the whole of what makes them still fit each other afterwards.\n */\nfunction prepare(source: { keyline: string; body: string }): CursorArtwork {\n const keyline = pathOps.anchors(source.keyline)\n const body = pathOps.anchors(source.body)\n // The outer contour contains the inner one by construction, so its bounds are\n // the glyph's — measured across both anyway, because a glyph pasted in with\n // its two halves the wrong way round would otherwise be silently cropped.\n const bounds = pathOps.anchorBounds([...keyline, ...body])\n if (!bounds) return { keyline, body }\n const width = bounds.maxX - bounds.minX\n const height = bounds.maxY - bounds.minY\n const scale = CURSOR_UNITS / Math.max(width, height, 1e-9)\n const move = (p: Vector2) => ({\n x: (p.x - bounds.minX) * scale,\n y: (p.y - bounds.minY) * scale,\n })\n return {\n keyline: pathOps.map(keyline, move),\n body: pathOps.map(body, move),\n }\n}\n\n/**\n * Every glyph, parsed and moved into the author box once, at module load.\n *\n * Once rather than per draw, unlike the parametric shapes next door: these are\n * fixed drawings with nothing to recompute, so parsing a few hundred curve\n * commands on every frame would buy nothing at all.\n */\nconst ARTWORK: Record<\n CursorStyle,\n Record<CursorType, CursorArtwork>\n> = Object.fromEntries(\n Object.entries(SOURCES).map(([style, byType]) => [\n style,\n Object.fromEntries(\n Object.entries(byType).map(([type, source]) => [type, prepare(source)])\n ),\n ])\n) as Record<CursorStyle, Record<CursorType, CursorArtwork>>\n\n/** The glyph in the author box, or the arrow for a type this build doesn't know. */\nfunction artworkFor(type: CursorType, style: CursorStyle): CursorArtwork {\n const byType = ARTWORK[style] ?? ARTWORK[DEFAULT_CURSOR_STYLE]\n return byType[type] ?? byType[DEFAULT_CURSOR_TYPE]\n}\n\n/**\n * The glyph mapped onto a node's box: centred on the origin, **fitted** into\n * `width` × `height`, still y-down.\n *\n * The same contract `shapeOutlinePixels` has, so the node class that draws this\n * is the same shape of thing as the ones that draw a hexagon — see\n * `nodes/cursor`.\n *\n * A cursor is **fitted** rather than stretched, which is the opposite of the\n * bargain every other node in this app makes and is the one case that earns it.\n * A rectangle dragged tall is a tall rectangle; a pointer dragged tall is not a\n * tall pointer, it is a drawing that has gone wrong — the shape is the whole of\n * what makes an arrow read as *the* arrow.\n *\n * In practice the two mappings agree, because the node's box is aspect-locked\n * square (see `model/natural-size.ts`) and a uniform fit into a square box is a\n * stretch. What this buys is what happens when the box arrives at some other\n * shape anyway — a scene authored before the lock existed, a paste, an agent, a\n * newer client — where the honest answer is a correctly-shaped cursor with slack\n * around it rather than a squashed one. The same failure posture the builder\n * takes everywhere else: draw something right rather than something wrong.\n */\nexport function cursorArtworkPixels(\n type: CursorType,\n style: CursorStyle,\n width: number,\n height: number\n): CursorArtwork {\n if (!(width > 0) || !(height > 0)) return { keyline: [], body: [] }\n // One scale for both axes — that is the fit — taken from the tighter of them,\n // and the leftover slack split either side so the glyph sits in the middle of\n // whatever box it was given.\n const k = Math.min(width, height) / CURSOR_UNITS\n const span = CURSOR_UNITS * k\n const onto = (p: Vector2) => ({\n x: p.x * k - span / 2,\n y: p.y * k - span / 2,\n })\n const artwork = artworkFor(type, style)\n return {\n keyline: pathOps.map(artwork.keyline, onto),\n body: pathOps.map(artwork.body, onto),\n }\n}\n\n/**\n * The glyph's two contours as SVG `d` strings in the 32-unit box.\n *\n * What the studio's own chrome draws with: the Components panel's card shows\n * the *actual* cursor rather than a hand-drawn approximation of it, so artwork\n * corrected here is corrected everywhere at once.\n */\nexport function cursorArtworkData(\n type: CursorType,\n style: CursorStyle\n): { keyline: string; body: string } {\n const artwork = artworkFor(type, style)\n return {\n keyline: pathOps.fromAnchors(artwork.keyline),\n body: pathOps.fromAnchors(artwork.body),\n }\n}\n\n/** Whether a stored value names a cursor this build can draw. */\nexport function isCursorType(value: unknown): value is CursorType {\n return (\n typeof value === \"string\" &&\n (CURSOR_TYPES as readonly string[]).includes(value)\n )\n}\n\n/** Whether a stored value names a look this build can draw. */\nexport function isCursorStyle(value: unknown): value is CursorStyle {\n return (\n typeof value === \"string\" &&\n (CURSOR_STYLES as readonly string[]).includes(value)\n )\n}\n"]}
1
+ {"version":3,"file":"cursor-outline.js","sourceRoot":"","sources":["../../src/kit/cursor-outline.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The artwork behind the Cursor node: two pointers, drawn the way an operating\n * system draws them.\n *\n * ## Two contours, not one shape and a stroke\n *\n * A real cursor is a **white body inside a black keyline** — that is what makes\n * it legible over a dark window and a light one both, and it is not decoration\n * anybody chose. So each glyph here is two closed contours: the outer\n * silhouette (body *plus* keyline) and the body inside it. The node paints the\n * outer one in the keyline colour and the inner one over it in the body colour,\n * and the keyline is whatever gap that leaves.\n *\n * That is deliberately **not** a fill with a stroke round it, and the reason is\n * the resize handle. A stroke's weight is a pixel count, and this glyph is\n * stretched onto whatever box the node has — so a weight that looked right at\n * 32px would be a hairline at 400 and a blob at 16. Baking the keyline into the\n * geometry makes it a *fraction of the drawing*, which is what it is on screen,\n * and it scales with everything else for free.\n *\n * ## The author box\n *\n * Both glyphs are normalized into one **32 × 32 box, y-down, origin top-left**\n * on the way in ({@link prepare}), fitted uniformly and anchored at the\n * top-left corner. Three things follow, all of them the point:\n *\n * - The two share a box, so changing the type dropdown swaps the drawing\n * without moving or resizing the node.\n * - The fit is *uniform*, so neither is distorted to fill a box it doesn't have\n * the proportions of. A glyph narrower than the box leaves the slack on its\n * right, which is empty space inside the selection rectangle and nothing more.\n * - The anchor is the top-left, which is where a pointer's **hotspot** is. A\n * cursor placed at (x, y) points at (x, y), the way the real one does.\n *\n * Normalizing at load rather than by hand is what lets the sources below stay\n * *verbatim* — they are the artwork as drawn, in their own viewBoxes, and\n * nobody has to re-derive a coordinate to move one into this module.\n */\n\nimport { pathOps, type VectorPath, type Vector2 } from \"@motionscript/sdk\"\n\n/**\n * The pointers, in the order the dropdown offers them.\n *\n * Two, and named for the CSS keywords rather than for what they look like:\n * `default` is the arrow and `pointer` is the hand you get over a link. That\n * vocabulary is the one anybody reaching for this node already has, and it is\n * the one the list grows in — `text`, `grab`, `crosshair` and the rest are each\n * a pair of contours away.\n */\nexport const CURSOR_TYPES = [\"default\", \"pointer\"] as const\n\nexport type CursorType = (typeof CURSOR_TYPES)[number]\n\n/**\n * The looks a cursor can be drawn in.\n *\n * One today, and the axis exists anyway because a second is a different\n * *drawing* rather than a setting: the macOS arrow is black with a white\n * keyline and has a silhouette of its own, so it arrives as another pair of\n * contours in {@link SOURCES} plus a row in {@link CURSOR_LOOKS} — not as a\n * colour control on the node. Keeping the axis is what makes that an addition\n * instead of a migration.\n *\n * While there is only one, the studio renders no dropdown for it: a control\n * with a single answer is a click that asks nothing. See the schema entry in\n * `model/appearance/schema.ts`, which says where to put it back.\n */\nexport const CURSOR_STYLES = [\"windows\"] as const\n\nexport type CursorStyle = (typeof CURSOR_STYLES)[number]\n\n/** The glyph a new Cursor node opens on: the arrow everybody pictures. */\nexport const DEFAULT_CURSOR_TYPE: CursorType = \"default\"\n\n/** …drawn the way the machine most people are looking at draws it. */\nexport const DEFAULT_CURSOR_STYLE: CursorStyle = \"windows\"\n\n/** The side of the square box both glyphs are normalized into. */\nexport const CURSOR_UNITS = 32\n\n/**\n * The side of the box a cursor node is **born at**, in scene units.\n *\n * A real pointer's own size: both Windows and macOS ship their cursors as 32×32\n * logical pixels, so a node this size in a 1920×1080 composition is the size the\n * thing actually is on a 1080p screen. That matters more than it sounds — a\n * cursor drawn four times life size doesn't read as a big cursor, it reads as a\n * scene shot at a different resolution from the interface under it.\n *\n * It is deliberately the *same number* as {@link CURSOR_UNITS} rather than a\n * multiple of it, and the coincidence is the point: the author box was chosen at\n * 32 because that is what a cursor is. See `model/natural-size.ts`, which is\n * what puts a node back to this after it has been dragged.\n */\nexport const CURSOR_SIZE = 32\n\n/** What a style paints its two contours with. */\nexport interface CursorLook {\n /** The body inside the keyline. */\n body: string\n /** The outline round it, which is the outer contour showing through. */\n keyline: string\n}\n\n/**\n * The colours each look is drawn in.\n *\n * Not defaults an author can change: a cursor's colours are what make it that\n * cursor, and a white-on-black Windows arrow repainted pink is not a stylized\n * cursor but a mistake. Hence the node exposes no Fills or Strokes section at\n * all — see `CURSOR_NODE_KEY`.\n */\nexport const CURSOR_LOOKS: Record<CursorStyle, CursorLook> = {\n windows: { body: \"#ffffff\", keyline: \"#000000\" },\n}\n\n/**\n * The look a style names, falling back to the default for one this build\n * doesn't know — a row written by a newer client, which should draw a cursor\n * rather than nothing.\n */\nexport function cursorLook(style: CursorStyle): CursorLook {\n return CURSOR_LOOKS[style] ?? CURSOR_LOOKS[DEFAULT_CURSOR_STYLE]\n}\n\n/** A cursor's two contours: the outer silhouette, and the body inside it. */\nexport interface CursorArtwork {\n /** Body *and* keyline — the whole shape, painted in the keyline colour. */\n keyline: VectorPath\n /** The body, painted over it. What is left showing is the keyline. */\n body: VectorPath\n}\n\n/**\n * The artwork, verbatim, in whatever viewBox it was drawn in.\n *\n * Each entry is one SVG `<path>` split at its second `M`: these are drawn as a\n * single two-subpath path with an even-odd fill, which paints the keyline and\n * leaves the body transparent. Splitting them is what lets the body be painted\n * too, and it is the only edit made to either.\n *\n * Keyed by style first, because a second style is a second drawing rather than\n * a recolouring of this one.\n */\nconst SOURCES: Record<\n CursorStyle,\n Record<CursorType, { keyline: string; body: string }>\n> = {\n windows: {\n // The arrow, drawn in a 50 x 50 box. The run of near-identical curves round\n // (14.8, 5) is the trace of its tip and is left exactly as it came: it is a\n // few dozen bytes, and \"tidying\" a traced outline is how a shape stops\n // matching the thing it was traced from.\n default: {\n keyline:\n \"M 14.78125 5 C 14.75 5.007813 14.71875 5.019531 14.6875 5.03125 C 14.644531 5.050781 14.601563 5.070313 14.5625 5.09375 C 14.550781 5.09375 14.542969 5.09375 14.53125 5.09375 C 14.511719 5.101563 14.488281 5.113281 14.46875 5.125 C 14.457031 5.136719 14.449219 5.144531 14.4375 5.15625 C 14.425781 5.167969 14.417969 5.175781 14.40625 5.1875 C 14.375 5.207031 14.34375 5.226563 14.3125 5.25 C 14.289063 5.269531 14.269531 5.289063 14.25 5.3125 C 14.238281 5.332031 14.226563 5.355469 14.21875 5.375 C 14.183594 5.414063 14.152344 5.457031 14.125 5.5 C 14.113281 5.511719 14.105469 5.519531 14.09375 5.53125 C 14.09375 5.542969 14.09375 5.550781 14.09375 5.5625 C 14.082031 5.582031 14.070313 5.605469 14.0625 5.625 C 14.050781 5.636719 14.042969 5.644531 14.03125 5.65625 C 14.03125 5.675781 14.03125 5.699219 14.03125 5.71875 C 14.019531 5.757813 14.007813 5.800781 14 5.84375 C 14 5.875 14 5.90625 14 5.9375 C 14 5.949219 14 5.957031 14 5.96875 C 14 5.980469 14 5.988281 14 6 C 13.996094 6.050781 13.996094 6.105469 14 6.15625 L 14 39 C 14.003906 39.398438 14.242188 39.757813 14.609375 39.914063 C 14.972656 40.070313 15.398438 39.992188 15.6875 39.71875 L 22.9375 32.90625 L 28.78125 46.40625 C 28.890625 46.652344 29.09375 46.847656 29.347656 46.941406 C 29.601563 47.035156 29.882813 47.023438 30.125 46.90625 L 34.5 44.90625 C 34.996094 44.679688 35.21875 44.09375 35 43.59375 L 28.90625 30.28125 L 39.09375 29.40625 C 39.496094 29.378906 39.84375 29.113281 39.976563 28.730469 C 40.105469 28.347656 39.992188 27.921875 39.6875 27.65625 L 15.84375 5.4375 C 15.796875 5.378906 15.746094 5.328125 15.6875 5.28125 C 15.648438 5.234375 15.609375 5.195313 15.5625 5.15625 C 15.550781 5.15625 15.542969 5.15625 15.53125 5.15625 C 15.511719 5.132813 15.492188 5.113281 15.46875 5.09375 C 15.457031 5.09375 15.449219 5.09375 15.4375 5.09375 C 15.386719 5.070313 15.335938 5.046875 15.28125 5.03125 C 15.269531 5.03125 15.261719 5.03125 15.25 5.03125 C 15.230469 5.019531 15.207031 5.007813 15.1875 5 C 15.175781 5 15.167969 5 15.15625 5 C 15.136719 5 15.113281 5 15.09375 5 C 15.082031 5 15.074219 5 15.0625 5 C 15.042969 5 15.019531 5 15 5 C 14.988281 5 14.980469 5 14.96875 5 C 14.9375 5 14.90625 5 14.875 5 C 14.84375 5 14.8125 5 14.78125 5 Z\",\n body: \"M 16 8.28125 L 36.6875 27.59375 L 27.3125 28.40625 C 26.992188 28.4375 26.707031 28.621094 26.546875 28.902344 C 26.382813 29.179688 26.367188 29.519531 26.5 29.8125 L 32.78125 43.5 L 30.21875 44.65625 L 24.21875 30.8125 C 24.089844 30.515625 23.828125 30.296875 23.511719 30.230469 C 23.195313 30.160156 22.863281 30.25 22.625 30.46875 L 16 36.6875 Z\",\n },\n // The pointing hand, drawn in a 32 x 32 box. The notches along the top of\n // the body contour are the gaps between the folded fingers — they are part\n // of the *body*, which is why the keyline shows through them.\n pointer: {\n keyline:\n \"M 13 2 C 11.355469 2 10 3.355469 10 5 L 10 16.8125 L 9.34375 16.125 L 9.09375 15.90625 C 7.941406 14.753906 6.058594 14.753906 4.90625 15.90625 C 3.753906 17.058594 3.753906 18.941406 4.90625 20.09375 L 4.90625 20.125 L 13.09375 28.21875 L 13.15625 28.25 L 13.1875 28.3125 C 14.535156 29.324219 16.253906 30 18.1875 30 L 19.90625 30 C 24.441406 30 28.09375 26.347656 28.09375 21.8125 L 28.09375 14 C 28.09375 12.355469 26.738281 11 25.09375 11 C 24.667969 11 24.273438 11.117188 23.90625 11.28125 C 23.578125 9.980469 22.394531 9 21 9 C 20.234375 9 19.53125 9.300781 19 9.78125 C 18.46875 9.300781 17.765625 9 17 9 C 16.648438 9 16.316406 9.074219 16 9.1875 L 16 5 C 16 3.355469 14.644531 2 13 2 Z\",\n body: \"M 13 4 C 13.554688 4 14 4.445313 14 5 L 14 16 L 16 16 L 16 12 C 16 11.445313 16.445313 11 17 11 C 17.554688 11 18 11.445313 18 12 L 18 16 L 20 16 L 20 12 C 20 11.445313 20.445313 11 21 11 C 21.554688 11 22 11.445313 22 12 L 22 16 L 24.09375 16 L 24.09375 14 C 24.09375 13.445313 24.539063 13 25.09375 13 C 25.648438 13 26.09375 13.445313 26.09375 14 L 26.09375 21.8125 C 26.09375 25.277344 23.371094 28 19.90625 28 L 18.1875 28 C 16.722656 28 15.457031 27.476563 14.40625 26.6875 L 6.3125 18.6875 C 5.867188 18.242188 5.867188 17.757813 6.3125 17.3125 C 6.757813 16.867188 7.242188 16.867188 7.6875 17.3125 L 12 21.625 L 12 5 C 12 4.445313 12.445313 4 13 4 Z\",\n },\n },\n}\n\n/**\n * Moves one glyph out of the viewBox it was drawn in and into the author box:\n * scaled uniformly to fit, anchored at the top-left corner.\n *\n * The two contours are measured **together** and mapped by the same transform,\n * which is the whole of what makes them still fit each other afterwards.\n */\nfunction prepare(source: { keyline: string; body: string }): CursorArtwork {\n const keyline = pathOps.anchors(source.keyline)\n const body = pathOps.anchors(source.body)\n // The outer contour contains the inner one by construction, so its bounds are\n // the glyph's — measured across both anyway, because a glyph pasted in with\n // its two halves the wrong way round would otherwise be silently cropped.\n const bounds = pathOps.anchorBounds([...keyline, ...body])\n if (!bounds) return { keyline, body }\n const width = bounds.maxX - bounds.minX\n const height = bounds.maxY - bounds.minY\n const scale = CURSOR_UNITS / Math.max(width, height, 1e-9)\n const move = (p: Vector2) => ({\n x: (p.x - bounds.minX) * scale,\n y: (p.y - bounds.minY) * scale,\n })\n return {\n keyline: pathOps.map(keyline, move),\n body: pathOps.map(body, move),\n }\n}\n\n/**\n * Every glyph, parsed and moved into the author box once, at module load.\n *\n * Once rather than per draw, unlike the parametric shapes next door: these are\n * fixed drawings with nothing to recompute, so parsing a few hundred curve\n * commands on every frame would buy nothing at all.\n */\nconst ARTWORK: Record<\n CursorStyle,\n Record<CursorType, CursorArtwork>\n> = Object.fromEntries(\n Object.entries(SOURCES).map(([style, byType]) => [\n style,\n Object.fromEntries(\n Object.entries(byType).map(([type, source]) => [type, prepare(source)])\n ),\n ])\n) as Record<CursorStyle, Record<CursorType, CursorArtwork>>\n\n/** The glyph in the author box, or the arrow for a type this build doesn't know. */\nfunction artworkFor(type: CursorType, style: CursorStyle): CursorArtwork {\n const byType = ARTWORK[style] ?? ARTWORK[DEFAULT_CURSOR_STYLE]\n return byType[type] ?? byType[DEFAULT_CURSOR_TYPE]\n}\n\n/**\n * The glyph mapped onto a node's box: centred on the origin, **fitted** into\n * `width` × `height`, still y-down.\n *\n * The same contract `shapeOutlinePixels` has, so the node class that draws this\n * is the same shape of thing as the ones that draw a hexagon — see\n * `nodes/cursor`.\n *\n * A cursor is **fitted** rather than stretched, which is the opposite of the\n * bargain every other node in this app makes and is the one case that earns it.\n * A rectangle dragged tall is a tall rectangle; a pointer dragged tall is not a\n * tall pointer, it is a drawing that has gone wrong — the shape is the whole of\n * what makes an arrow read as *the* arrow.\n *\n * In practice the two mappings agree, because the node's box is aspect-locked\n * square (see `model/natural-size.ts`) and a uniform fit into a square box is a\n * stretch. What this buys is what happens when the box arrives at some other\n * shape anyway — a scene authored before the lock existed, a paste, an agent, a\n * newer client — where the honest answer is a correctly-shaped cursor with slack\n * around it rather than a squashed one. The same failure posture the builder\n * takes everywhere else: draw something right rather than something wrong.\n */\nexport function cursorArtworkPixels(\n type: CursorType,\n style: CursorStyle,\n width: number,\n height: number\n): CursorArtwork {\n if (!(width > 0) || !(height > 0)) return { keyline: [], body: [] }\n // One scale for both axes — that is the fit — taken from the tighter of them,\n // and the leftover slack split either side so the glyph sits in the middle of\n // whatever box it was given.\n const k = Math.min(width, height) / CURSOR_UNITS\n const span = CURSOR_UNITS * k\n const onto = (p: Vector2) => ({\n x: p.x * k - span / 2,\n y: p.y * k - span / 2,\n })\n const artwork = artworkFor(type, style)\n return {\n keyline: pathOps.map(artwork.keyline, onto),\n body: pathOps.map(artwork.body, onto),\n }\n}\n\n/**\n * The glyph's two contours as SVG `d` strings in the 32-unit box.\n *\n * What the studio's own chrome draws with: the Components panel's card shows\n * the *actual* cursor rather than a hand-drawn approximation of it, so artwork\n * corrected here is corrected everywhere at once.\n */\nexport function cursorArtworkData(\n type: CursorType,\n style: CursorStyle\n): { keyline: string; body: string } {\n const artwork = artworkFor(type, style)\n return {\n keyline: pathOps.fromAnchors(artwork.keyline),\n body: pathOps.fromAnchors(artwork.body),\n }\n}\n\n/** Whether a stored value names a cursor this build can draw. */\nexport function isCursorType(value: unknown): value is CursorType {\n return (\n typeof value === \"string\" &&\n (CURSOR_TYPES as readonly string[]).includes(value)\n )\n}\n\n/** Whether a stored value names a look this build can draw. */\nexport function isCursorStyle(value: unknown): value is CursorStyle {\n return (\n typeof value === \"string\" &&\n (CURSOR_STYLES as readonly string[]).includes(value)\n )\n}\n"]}
package/dist/nodes.d.ts CHANGED
@@ -17,5 +17,5 @@ import { Cursor } from "./cursor/index.js";
17
17
  * `import "./switch/index.js"` for its side effect is exactly what gets shaken out, where an
18
18
  * array of bindings is a data dependency that cannot be.
19
19
  */
20
- export declare const NODES: (typeof Switch | typeof Button | typeof Window | typeof Cursor)[];
20
+ export declare const NODES: (typeof Button | typeof Switch | typeof Window | typeof Cursor)[];
21
21
  //# sourceMappingURL=nodes.d.ts.map
@@ -1,4 +1,4 @@
1
- import { type Command, type CommandArgs, type Node, type NodeConfig, type RenderContext2D } from "@motionscript/core";
1
+ import { type Command, type CommandArgs, type Node, type NodeConfig, type RenderContext2D } from "@motionscript/sdk";
2
2
  import { type ControlIcon } from "../kit/control-icons.js";
3
3
  import { type ControlStyle } from "../kit/control-style.js";
4
4
  import { ControlNode, type ControlNodeProps } from "../kit/control-node.js";
@@ -1 +1 @@
1
- {"version":3,"file":"switch.d.ts","sourceRoot":"","sources":["../../src/switch/switch.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,OAAO,EACZ,KAAK,WAAW,EAGhB,KAAK,IAAI,EACT,KAAK,UAAU,EACf,KAAK,eAAe,EACrB,MAAM,oBAAoB,CAAA;AAE3B,OAAO,EAIL,KAAK,WAAW,EACjB,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAKL,KAAK,YAAY,EAClB,MAAM,sBAAsB,CAAA;AAE7B,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AAExE,mFAAmF;AACnF,MAAM,WAAW,WAAY,SAAQ,gBAAgB;IACnD,mEAAmE;IACnE,KAAK,EAAE,YAAY,CAAA;IACnB;;;;;;;;OAQG;IACH,QAAQ,EAAE,MAAM,CAAA;IAChB,wDAAwD;IACxD,MAAM,EAAE,MAAM,CAAA;IACd,wCAAwC;IACxC,MAAM,EAAE,WAAW,CAAA;IACnB,qBAAqB;IACrB,OAAO,EAAE,WAAW,CAAA;IACpB;;;;;OAKG;IACH,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;IACX,6EAA6E;IAC7E,MAAM,EAAE,MAAM,CAAA;IACd,gFAAgF;IAChF,cAAc,EAAE,MAAM,CAAA;CACvB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,6DAA6D;AAC7D,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,IAAI,GAAG,KAAK,CAAA;AAEjD,qBAea,MAAO,SAAQ,WAAW,CAAC,WAAW,CAAC;IAE1C,KAAK,EAAE,YAAY,CAAA;IACmC,QAAQ,EAAE,MAAM,CAAA;IACrB,MAAM,EAAE,MAAM,CAAA;IAE/D,MAAM,EAAE,WAAW,CAAA;IAEnB,OAAO,EAAE,WAAW,CAAA;IAC6B,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;IACN,MAAM,EAAE,MAAM,CAAA;IAEpE,cAAc,EAAE,MAAM,CAAA;gBAElB,KAAK,EAAE,UAAU,CAAC,MAAM,EAAE,WAAW,CAAC;IAIlD,mFAAmF;cAChE,YAAY,CAAC,MAAM,EAAE,IAAI,GAAG,OAAO;IAItD;;;;;OAKG;IAEH,MAAM,CAAC,IAAI,EAAE,WAAW,CAAC;QAAE,WAAW,CAAC,EAAE,WAAW,CAAA;KAAE,CAAC,GAAG;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,WAAW,CAAC;IAStG;;;;;;;OAOG;IACH,OAAO,CAAC,OAAO;cAmCI,UAAU,CAAC,GAAG,EAAE,eAAe,GAAG,IAAI;IAkDzD;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,QAAQ;CAsCjB"}
1
+ {"version":3,"file":"switch.d.ts","sourceRoot":"","sources":["../../src/switch/switch.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,OAAO,EACZ,KAAK,WAAW,EAGhB,KAAK,IAAI,EACT,KAAK,UAAU,EACf,KAAK,eAAe,EACrB,MAAM,mBAAmB,CAAA;AAE1B,OAAO,EAIL,KAAK,WAAW,EACjB,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAKL,KAAK,YAAY,EAClB,MAAM,sBAAsB,CAAA;AAE7B,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AAExE,mFAAmF;AACnF,MAAM,WAAW,WAAY,SAAQ,gBAAgB;IACnD,mEAAmE;IACnE,KAAK,EAAE,YAAY,CAAA;IACnB;;;;;;;;OAQG;IACH,QAAQ,EAAE,MAAM,CAAA;IAChB,wDAAwD;IACxD,MAAM,EAAE,MAAM,CAAA;IACd,wCAAwC;IACxC,MAAM,EAAE,WAAW,CAAA;IACnB,qBAAqB;IACrB,OAAO,EAAE,WAAW,CAAA;IACpB;;;;;OAKG;IACH,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;IACX,6EAA6E;IAC7E,MAAM,EAAE,MAAM,CAAA;IACd,gFAAgF;IAChF,cAAc,EAAE,MAAM,CAAA;CACvB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,6DAA6D;AAC7D,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,IAAI,GAAG,KAAK,CAAA;AAEjD,qBAea,MAAO,SAAQ,WAAW,CAAC,WAAW,CAAC;IAE1C,KAAK,EAAE,YAAY,CAAA;IACmC,QAAQ,EAAE,MAAM,CAAA;IACrB,MAAM,EAAE,MAAM,CAAA;IAE/D,MAAM,EAAE,WAAW,CAAA;IAEnB,OAAO,EAAE,WAAW,CAAA;IAC6B,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;IACN,MAAM,EAAE,MAAM,CAAA;IAEpE,cAAc,EAAE,MAAM,CAAA;gBAElB,KAAK,EAAE,UAAU,CAAC,MAAM,EAAE,WAAW,CAAC;IAIlD,mFAAmF;cAChE,YAAY,CAAC,MAAM,EAAE,IAAI,GAAG,OAAO;IAItD;;;;;OAKG;IAEH,MAAM,CAAC,IAAI,EAAE,WAAW,CAAC;QAAE,WAAW,CAAC,EAAE,WAAW,CAAA;KAAE,CAAC,GAAG;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,WAAW,CAAC;IAStG;;;;;;;OAOG;IACH,OAAO,CAAC,OAAO;cAmCI,UAAU,CAAC,GAAG,EAAE,eAAe,GAAG,IAAI;IAkDzD;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,QAAQ;CAsCjB"}
@@ -4,10 +4,10 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
4
4
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
- import { command, easeInOut, node, Graphics2D, property, } from "@motionscript/core";
7
+ import { command, easeInOut, node, Graphics2D, property, } from "@motionscript/sdk";
8
8
  import { CONTROL_ICONS, controlIconPixels, DEFAULT_CONTROL_ICON, } from "../kit/control-icons.js";
9
9
  import { CONTROL_STYLES, DEFAULT_CONTROL_STYLE, mixHex, switchLook, } from "../kit/control-style.js";
10
- import { pathOps } from "@motionscript/core";
10
+ import { pathOps } from "@motionscript/sdk";
11
11
  import { ControlNode } from "../kit/control-node.js";
12
12
  let Switch = class Switch extends ControlNode {
13
13
  constructor(props) {
@@ -1 +1 @@
1
- {"version":3,"file":"switch.js","sourceRoot":"","sources":["../../src/switch/switch.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n command,\n easeInOut,\n node,\n type Command,\n type CommandArgs,\n Graphics2D,\n property,\n type Node,\n type NodeConfig,\n type RenderContext2D,\n} from \"@motionscript/core\"\n\nimport {\n CONTROL_ICONS,\n controlIconPixels,\n DEFAULT_CONTROL_ICON,\n type ControlIcon,\n} from \"../kit/control-icons\"\nimport {\n CONTROL_STYLES,\n DEFAULT_CONTROL_STYLE,\n mixHex,\n switchLook,\n type ControlStyle,\n} from \"../kit/control-style\"\nimport { pathOps } from \"@motionscript/core\"\nimport { ControlNode, type ControlNodeProps } from \"../kit/control-node\"\n\n/** A switch's own props, over the box and the sound schedule every control has. */\nexport interface SwitchProps extends ControlNodeProps {\n /** Which design language to draw in — see {@link ControlStyle}. */\n style: ControlStyle\n /**\n * Where the knob is, `0` (off) to `1` (on).\n *\n * The **whole** of the node's animated state, and an ordinary tweenable number\n * rather than a boolean, which is the point: a switch's flip is a slide, and\n * \"half a boolean\" is not a frame anyone could draw. The document's Toggle\n * commands are lowered to tweens of this by the builder, each toward the\n * concrete state its chain resolves to (see `nodes/ui-kit/commands.ts`).\n */\n progress: number\n /** The colour the track turns when the switch is on. */\n accent: string\n /** The mark inside the knob when on. */\n iconOn: ControlIcon\n /** …and when off. */\n iconOff: ControlIcon\n /**\n * The track when off, the knob, and the mark's ink — honoured **only** in the\n * `custom` style, where they are what \"custom\" means. In the three named looks\n * these are ignored in favour of the platform's own, because a Material switch\n * with someone's grey in it is not a Material switch. See `model/control-style`.\n */\n track: string\n knob: string\n ink: string\n /** Corner radius as a fraction of half the track's height. `custom` only. */\n radius: number\n /** Seconds a {@link Switch.toggle} runs for when its row states no duration. */\n toggleDuration: number\n}\n\n/**\n * A **switch**, as a node.\n *\n * The control every product demo turns on at some point, and — like the cursor\n * one shelf over — a thing that was previously either a screen recording or four\n * rectangles animated by hand. Four rectangles is the interesting failure: it\n * works until you want the knob to arrive a beat later, at which point you are\n * keeping three tweens in sync by eye.\n *\n * ## One control, not thirty\n *\n * Its whole surface is a style, an accent, two marks and a resting state.\n * Everything else — the knob's diameter, its inset, whether it grows on the way\n * across, whether the track carries an outline — comes out of the style, because\n * those are facts about iOS and Material rather than decisions anybody making a\n * video wants to take. `model/control-style` has that argument at length, and\n * the `custom` style is the escape hatch for the case none of the three covers.\n *\n * ## Why it paints itself\n *\n * A `node` in the registry rather than a `shape`, on the cursor's reasoning with\n * one addition. A switch is *five* painted parts — track, outline, knob, and a\n * mark on each side of the fade — and a Fills section could only ever reach one\n * of them, so it would be a control whose effect an author would have to\n * discover by experiment. What it takes instead is the accent, which is the one\n * paint decision a switch actually has.\n *\n * ## Drawing, in four passes\n *\n * Track, knob, then the two marks. Four `draw` calls rather than one chained\n * `Graphics2D` because three of them carry a group opacity or a shadow of their\n * own, and `Graphics2D.opacity` composites the *whole* list — chaining them\n * would fade the track along with the mark it was meant to be cross-fading.\n */\n\n/** What {@link Switch.toggle} should leave the switch in. */\nexport type ToggleState = \"toggle\" | \"on\" | \"off\"\n\n@node({\n key: \"switch\",\n parentKey: \"node\",\n forkable: true,\n layout: {\n children: \"freeform\",\n defaultWidthMode: \"fixed\",\n defaultHeightMode: \"fixed\",\n acceptsChildren: false,\n },\n seed: {\n width: 204,\n height: 124,\n },\n})\nexport class Switch extends ControlNode<SwitchProps> {\n @property({ default: DEFAULT_CONTROL_STYLE, kind: \"enum\", options: CONTROL_STYLES })\n declare style: ControlStyle\n @property({ default: 0, min: 0, max: 1, step: 0.01 }) declare progress: number\n @property({ default: \"#34c759\", kind: \"color\" }) declare accent: string\n @property({ default: DEFAULT_CONTROL_ICON, kind: \"enum\", options: CONTROL_ICONS })\n declare iconOn: ControlIcon\n @property({ default: DEFAULT_CONTROL_ICON, kind: \"enum\", options: CONTROL_ICONS })\n declare iconOff: ControlIcon\n @property({ default: \"#e9e9eb\", kind: \"color\" }) declare track: string\n @property({ default: \"#ffffff\", kind: \"color\" }) declare knob: string\n @property({ default: \"#8e8e93\", kind: \"color\" }) declare ink: string\n @property({ default: 1, min: 0, max: 1, step: 0.01 }) declare radius: number\n @property({ default: 0.28, min: 0, step: 0.05, unit: \"s\" })\n declare toggleDuration: number\n\n constructor(props: NodeConfig<Switch, SwitchProps>) {\n super(props)\n }\n\n /** A switch is a control, not a container — its five painted parts are its own. */\n protected override acceptsChild(_child: Node): boolean {\n return false\n }\n\n /**\n * Throw the switch. `\"on\"`/`\"off\"` are absolute; `\"toggle\"` reads the knob's\n * current position and goes the other way — read when the **command is\n * built**, matching the timeline's own order, so two `toggle`s at the same\n * `at` agree rather than alternating.\n */\n @command({ args: [{ key: \"toggleState\", kind: \"enum\", default: \"toggle\", options: [\"toggle\", \"on\", \"off\"] }] })\n toggle(args: CommandArgs<{ toggleState?: ToggleState }> & { duration?: number }): Command<SwitchProps> {\n const toggleState = args.data?.toggleState ?? \"toggle\"\n const duration = args.duration && args.duration > 0 ? args.duration : this.toggleDuration\n const easing = args.easing ?? easeInOut()\n const to =\n toggleState === \"on\" ? 1 : toggleState === \"off\" ? 0 : this.progress > 0.5 ? 0 : 1\n return this.to({ data: { progress: to } as Partial<SwitchProps>, duration, easing })\n }\n\n /**\n * Every measurement the drawing needs, in pixels of the node's own box.\n *\n * Resolved in one place rather than at each use so the knob, its travel and\n * the mark inside it cannot disagree about where the knob is — three\n * near-identical expressions is how a mark ends up a pixel behind the thing it\n * is drawn on.\n */\n private metrics() {\n const bounds = this.layoutBounds\n const width = bounds?.width ?? 0\n const height = bounds?.height ?? 0\n const look = switchLook(this.style)\n const custom = this.style === \"custom\"\n const p = Math.min(1, Math.max(0, this.progress))\n\n const trackHeight = height * look.track\n // The margin is taken from the *largest* the knob ever gets, so a knob that\n // grows (Material's does) grows in place rather than dragging its own travel\n // with it — which would make the same switch stop at a different place\n // depending on how far through the flip it was.\n const widest = trackHeight * Math.max(look.knobOff, look.knobOn)\n const margin = (trackHeight - widest) / 2\n const knobSize =\n trackHeight * (look.knobOff + (look.knobOn - look.knobOff) * p)\n const travel = width / 2 - margin - widest / 2\n\n return {\n width,\n height,\n look,\n p,\n trackHeight,\n trackRadius: (trackHeight / 2) * (custom ? this.radius : look.radius),\n outline: trackHeight * look.outline,\n knobSize,\n knobX: -travel + travel * 2 * p,\n offTrack: custom ? this.track : look.offTrack,\n offKnob: custom ? this.knob : look.offKnob,\n offIcon: custom ? this.ink : look.offIcon,\n }\n }\n\n protected override renderSelf(ctx: RenderContext2D): void {\n const m = this.metrics()\n if (m.width <= 0 || m.trackHeight <= 0) return\n\n // The track, and its outline where the look has one. Both interpolate\n // toward the accent, which is what makes Material's outline disappear as it\n // turns on without needing a second rule for the weight.\n const track = new Graphics2D().rect({\n x: 0,\n y: 0,\n width: m.width,\n height: m.trackHeight,\n cornerRadius: m.trackRadius,\n })\n track.fill(mixHex(m.offTrack, this.accent, m.p))\n if (m.outline > 0) {\n track.stroke({\n weight: m.outline,\n fill: mixHex(m.look.offOutline, this.accent, m.p),\n align: \"inside\",\n })\n }\n ctx.draw(track)\n\n // The knob. Its shadow is the look's rather than a paint stack's, for the\n // same reason its diameter is: an iOS knob has a soft shadow and a Material\n // one does not, and that is part of what tells them apart.\n const knob = new Graphics2D().ellipse({\n x: m.knobX,\n y: 0,\n width: m.knobSize,\n height: m.knobSize,\n })\n if (m.look.shadow > 0) {\n knob.shadow({\n blur: m.trackHeight * m.look.shadow,\n offset: { x: 0, y: -m.trackHeight * m.look.shadow * 0.25 },\n fill: \"rgba(0, 0, 0, 0.22)\",\n })\n }\n knob.fill(mixHex(m.offKnob, m.look.onKnob, m.p))\n ctx.draw(knob)\n\n // The two marks, cross-fading. Drawn even at zero opacity — skipping them\n // would be a branch that saves nothing and puts a pop at each end of the\n // fade the moment a renderer rounds the alpha differently.\n this.drawIcon(ctx, this.iconOff, m.knobX, m.knobSize, m.offIcon, 1 - m.p)\n this.drawIcon(ctx, this.iconOn, m.knobX, m.knobSize, this.accent, m.p)\n }\n\n /**\n * One mark, centred in the knob.\n *\n * Its ink is the *other* side's colour by construction — the off mark takes\n * the look's own grey against a light knob, and the on mark takes the accent,\n * which the knob has turned white behind by the time it is visible. That is\n * why neither is a field: the pairing is what makes the mark legible, and an\n * author free to set it is an author free to make it invisible.\n *\n * Stroked and filled contours are two draws because they are two paints; a\n * glyph carries one or the other and never both, so the second is a no-op for\n * every mark in the catalogue today (see `model/control-icons`).\n */\n private drawIcon(\n ctx: RenderContext2D,\n icon: ControlIcon,\n x: number,\n knobSize: number,\n color: string,\n opacity: number\n ): void {\n if (icon === \"none\" || opacity <= 0 || knobSize <= 0) return\n // Just over half the knob, which is where every platform sets a glyph\n // inside a circular target: larger reads as a badge, smaller as a speck.\n const art = controlIconPixels(icon, knobSize * 0.56)\n const shift = (p: { x: number; y: number }) => ({ x: p.x + x, y: p.y })\n\n if (art.fills.length > 0) {\n ctx.draw(\n new Graphics2D()\n .path({ data: pathOps.anchorCommands(art.fills, shift) })\n .fill(color)\n .opacity(opacity)\n )\n }\n if (art.strokes.length > 0) {\n ctx.draw(\n new Graphics2D()\n .path({ data: pathOps.anchorCommands(art.strokes, shift) })\n .stroke({\n weight: art.weight,\n fill: color,\n cap: \"round\",\n join: \"round\",\n align: \"center\",\n })\n .opacity(opacity)\n )\n }\n }\n\n}\n"]}
1
+ {"version":3,"file":"switch.js","sourceRoot":"","sources":["../../src/switch/switch.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n command,\n easeInOut,\n node,\n type Command,\n type CommandArgs,\n Graphics2D,\n property,\n type Node,\n type NodeConfig,\n type RenderContext2D,\n} from \"@motionscript/sdk\"\n\nimport {\n CONTROL_ICONS,\n controlIconPixels,\n DEFAULT_CONTROL_ICON,\n type ControlIcon,\n} from \"../kit/control-icons\"\nimport {\n CONTROL_STYLES,\n DEFAULT_CONTROL_STYLE,\n mixHex,\n switchLook,\n type ControlStyle,\n} from \"../kit/control-style\"\nimport { pathOps } from \"@motionscript/sdk\"\nimport { ControlNode, type ControlNodeProps } from \"../kit/control-node\"\n\n/** A switch's own props, over the box and the sound schedule every control has. */\nexport interface SwitchProps extends ControlNodeProps {\n /** Which design language to draw in — see {@link ControlStyle}. */\n style: ControlStyle\n /**\n * Where the knob is, `0` (off) to `1` (on).\n *\n * The **whole** of the node's animated state, and an ordinary tweenable number\n * rather than a boolean, which is the point: a switch's flip is a slide, and\n * \"half a boolean\" is not a frame anyone could draw. The document's Toggle\n * commands are lowered to tweens of this by the builder, each toward the\n * concrete state its chain resolves to (see `nodes/ui-kit/commands.ts`).\n */\n progress: number\n /** The colour the track turns when the switch is on. */\n accent: string\n /** The mark inside the knob when on. */\n iconOn: ControlIcon\n /** …and when off. */\n iconOff: ControlIcon\n /**\n * The track when off, the knob, and the mark's ink — honoured **only** in the\n * `custom` style, where they are what \"custom\" means. In the three named looks\n * these are ignored in favour of the platform's own, because a Material switch\n * with someone's grey in it is not a Material switch. See `model/control-style`.\n */\n track: string\n knob: string\n ink: string\n /** Corner radius as a fraction of half the track's height. `custom` only. */\n radius: number\n /** Seconds a {@link Switch.toggle} runs for when its row states no duration. */\n toggleDuration: number\n}\n\n/**\n * A **switch**, as a node.\n *\n * The control every product demo turns on at some point, and — like the cursor\n * one shelf over — a thing that was previously either a screen recording or four\n * rectangles animated by hand. Four rectangles is the interesting failure: it\n * works until you want the knob to arrive a beat later, at which point you are\n * keeping three tweens in sync by eye.\n *\n * ## One control, not thirty\n *\n * Its whole surface is a style, an accent, two marks and a resting state.\n * Everything else — the knob's diameter, its inset, whether it grows on the way\n * across, whether the track carries an outline — comes out of the style, because\n * those are facts about iOS and Material rather than decisions anybody making a\n * video wants to take. `model/control-style` has that argument at length, and\n * the `custom` style is the escape hatch for the case none of the three covers.\n *\n * ## Why it paints itself\n *\n * A `node` in the registry rather than a `shape`, on the cursor's reasoning with\n * one addition. A switch is *five* painted parts — track, outline, knob, and a\n * mark on each side of the fade — and a Fills section could only ever reach one\n * of them, so it would be a control whose effect an author would have to\n * discover by experiment. What it takes instead is the accent, which is the one\n * paint decision a switch actually has.\n *\n * ## Drawing, in four passes\n *\n * Track, knob, then the two marks. Four `draw` calls rather than one chained\n * `Graphics2D` because three of them carry a group opacity or a shadow of their\n * own, and `Graphics2D.opacity` composites the *whole* list — chaining them\n * would fade the track along with the mark it was meant to be cross-fading.\n */\n\n/** What {@link Switch.toggle} should leave the switch in. */\nexport type ToggleState = \"toggle\" | \"on\" | \"off\"\n\n@node({\n key: \"switch\",\n parentKey: \"node\",\n forkable: true,\n layout: {\n children: \"freeform\",\n defaultWidthMode: \"fixed\",\n defaultHeightMode: \"fixed\",\n acceptsChildren: false,\n },\n seed: {\n width: 204,\n height: 124,\n },\n})\nexport class Switch extends ControlNode<SwitchProps> {\n @property({ default: DEFAULT_CONTROL_STYLE, kind: \"enum\", options: CONTROL_STYLES })\n declare style: ControlStyle\n @property({ default: 0, min: 0, max: 1, step: 0.01 }) declare progress: number\n @property({ default: \"#34c759\", kind: \"color\" }) declare accent: string\n @property({ default: DEFAULT_CONTROL_ICON, kind: \"enum\", options: CONTROL_ICONS })\n declare iconOn: ControlIcon\n @property({ default: DEFAULT_CONTROL_ICON, kind: \"enum\", options: CONTROL_ICONS })\n declare iconOff: ControlIcon\n @property({ default: \"#e9e9eb\", kind: \"color\" }) declare track: string\n @property({ default: \"#ffffff\", kind: \"color\" }) declare knob: string\n @property({ default: \"#8e8e93\", kind: \"color\" }) declare ink: string\n @property({ default: 1, min: 0, max: 1, step: 0.01 }) declare radius: number\n @property({ default: 0.28, min: 0, step: 0.05, unit: \"s\" })\n declare toggleDuration: number\n\n constructor(props: NodeConfig<Switch, SwitchProps>) {\n super(props)\n }\n\n /** A switch is a control, not a container — its five painted parts are its own. */\n protected override acceptsChild(_child: Node): boolean {\n return false\n }\n\n /**\n * Throw the switch. `\"on\"`/`\"off\"` are absolute; `\"toggle\"` reads the knob's\n * current position and goes the other way — read when the **command is\n * built**, matching the timeline's own order, so two `toggle`s at the same\n * `at` agree rather than alternating.\n */\n @command({ args: [{ key: \"toggleState\", kind: \"enum\", default: \"toggle\", options: [\"toggle\", \"on\", \"off\"] }] })\n toggle(args: CommandArgs<{ toggleState?: ToggleState }> & { duration?: number }): Command<SwitchProps> {\n const toggleState = args.data?.toggleState ?? \"toggle\"\n const duration = args.duration && args.duration > 0 ? args.duration : this.toggleDuration\n const easing = args.easing ?? easeInOut()\n const to =\n toggleState === \"on\" ? 1 : toggleState === \"off\" ? 0 : this.progress > 0.5 ? 0 : 1\n return this.to({ data: { progress: to } as Partial<SwitchProps>, duration, easing })\n }\n\n /**\n * Every measurement the drawing needs, in pixels of the node's own box.\n *\n * Resolved in one place rather than at each use so the knob, its travel and\n * the mark inside it cannot disagree about where the knob is — three\n * near-identical expressions is how a mark ends up a pixel behind the thing it\n * is drawn on.\n */\n private metrics() {\n const bounds = this.layoutBounds\n const width = bounds?.width ?? 0\n const height = bounds?.height ?? 0\n const look = switchLook(this.style)\n const custom = this.style === \"custom\"\n const p = Math.min(1, Math.max(0, this.progress))\n\n const trackHeight = height * look.track\n // The margin is taken from the *largest* the knob ever gets, so a knob that\n // grows (Material's does) grows in place rather than dragging its own travel\n // with it — which would make the same switch stop at a different place\n // depending on how far through the flip it was.\n const widest = trackHeight * Math.max(look.knobOff, look.knobOn)\n const margin = (trackHeight - widest) / 2\n const knobSize =\n trackHeight * (look.knobOff + (look.knobOn - look.knobOff) * p)\n const travel = width / 2 - margin - widest / 2\n\n return {\n width,\n height,\n look,\n p,\n trackHeight,\n trackRadius: (trackHeight / 2) * (custom ? this.radius : look.radius),\n outline: trackHeight * look.outline,\n knobSize,\n knobX: -travel + travel * 2 * p,\n offTrack: custom ? this.track : look.offTrack,\n offKnob: custom ? this.knob : look.offKnob,\n offIcon: custom ? this.ink : look.offIcon,\n }\n }\n\n protected override renderSelf(ctx: RenderContext2D): void {\n const m = this.metrics()\n if (m.width <= 0 || m.trackHeight <= 0) return\n\n // The track, and its outline where the look has one. Both interpolate\n // toward the accent, which is what makes Material's outline disappear as it\n // turns on without needing a second rule for the weight.\n const track = new Graphics2D().rect({\n x: 0,\n y: 0,\n width: m.width,\n height: m.trackHeight,\n cornerRadius: m.trackRadius,\n })\n track.fill(mixHex(m.offTrack, this.accent, m.p))\n if (m.outline > 0) {\n track.stroke({\n weight: m.outline,\n fill: mixHex(m.look.offOutline, this.accent, m.p),\n align: \"inside\",\n })\n }\n ctx.draw(track)\n\n // The knob. Its shadow is the look's rather than a paint stack's, for the\n // same reason its diameter is: an iOS knob has a soft shadow and a Material\n // one does not, and that is part of what tells them apart.\n const knob = new Graphics2D().ellipse({\n x: m.knobX,\n y: 0,\n width: m.knobSize,\n height: m.knobSize,\n })\n if (m.look.shadow > 0) {\n knob.shadow({\n blur: m.trackHeight * m.look.shadow,\n offset: { x: 0, y: -m.trackHeight * m.look.shadow * 0.25 },\n fill: \"rgba(0, 0, 0, 0.22)\",\n })\n }\n knob.fill(mixHex(m.offKnob, m.look.onKnob, m.p))\n ctx.draw(knob)\n\n // The two marks, cross-fading. Drawn even at zero opacity — skipping them\n // would be a branch that saves nothing and puts a pop at each end of the\n // fade the moment a renderer rounds the alpha differently.\n this.drawIcon(ctx, this.iconOff, m.knobX, m.knobSize, m.offIcon, 1 - m.p)\n this.drawIcon(ctx, this.iconOn, m.knobX, m.knobSize, this.accent, m.p)\n }\n\n /**\n * One mark, centred in the knob.\n *\n * Its ink is the *other* side's colour by construction — the off mark takes\n * the look's own grey against a light knob, and the on mark takes the accent,\n * which the knob has turned white behind by the time it is visible. That is\n * why neither is a field: the pairing is what makes the mark legible, and an\n * author free to set it is an author free to make it invisible.\n *\n * Stroked and filled contours are two draws because they are two paints; a\n * glyph carries one or the other and never both, so the second is a no-op for\n * every mark in the catalogue today (see `model/control-icons`).\n */\n private drawIcon(\n ctx: RenderContext2D,\n icon: ControlIcon,\n x: number,\n knobSize: number,\n color: string,\n opacity: number\n ): void {\n if (icon === \"none\" || opacity <= 0 || knobSize <= 0) return\n // Just over half the knob, which is where every platform sets a glyph\n // inside a circular target: larger reads as a badge, smaller as a speck.\n const art = controlIconPixels(icon, knobSize * 0.56)\n const shift = (p: { x: number; y: number }) => ({ x: p.x + x, y: p.y })\n\n if (art.fills.length > 0) {\n ctx.draw(\n new Graphics2D()\n .path({ data: pathOps.anchorCommands(art.fills, shift) })\n .fill(color)\n .opacity(opacity)\n )\n }\n if (art.strokes.length > 0) {\n ctx.draw(\n new Graphics2D()\n .path({ data: pathOps.anchorCommands(art.strokes, shift) })\n .stroke({\n weight: art.weight,\n fill: color,\n cap: \"round\",\n join: \"round\",\n align: \"center\",\n })\n .opacity(opacity)\n )\n }\n }\n\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { Graphics2D, Rect, type InsetsResolved, type RectProps, type RenderContext2D } from "@motionscript/core";
1
+ import { Graphics2D, Rect, type InsetsResolved, type RectProps, type RenderContext2D } from "@motionscript/sdk";
2
2
  import { type WindowStyle } from "./window-style.js";
3
3
  /** A window's own props, over the box and layout every `Rect` has. */
4
4
  export interface WindowProps extends RectProps {
@@ -1 +1 @@
1
- {"version":3,"file":"window.d.ts","sourceRoot":"","sources":["../../src/window/window.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,UAAU,EACV,IAAI,EAEJ,KAAK,cAAc,EACnB,KAAK,SAAS,EACd,KAAK,eAAe,EAGrB,MAAM,oBAAoB,CAAA;AAE3B,OAAO,EAKL,KAAK,WAAW,EACjB,MAAM,gBAAgB,CAAA;AAEvB,sEAAsE;AACtE,MAAM,WAAW,WAAY,SAAQ,SAAS;IAC5C,yEAAyE;IACzE,KAAK,EAAE,WAAW,CAAA;IAClB;;;;;;OAMG;IACH,IAAI,EAAE,OAAO,CAAA;IACb,oDAAoD;IACpD,KAAK,EAAE,MAAM,CAAA;IACb,kEAAkE;IAClE,UAAU,EAAE,MAAM,CAAA;IAClB,oDAAoD;IACpD,IAAI,EAAE,MAAM,CAAA;IACZ;;;;;;;;;OASG;IACH,WAAW,EAAE,MAAM,CAAA;IACnB,qEAAqE;IACrE,QAAQ,EAAE,OAAO,CAAA;CAClB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AACH,qBAea,MAAO,SAAQ,IAAI,CAAC,WAAW,CAAC;IAEnC,KAAK,EAAE,WAAW,CAAA;IACY,IAAI,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,EAAE,MAAM,CAAA;IACI,IAAI,EAAE,MAAM,CAAA;IAE7D,WAAW,EAAE,MAAM,CAAA;IACU,QAAQ,EAAE,OAAO,CAAA;IAEtD;;;;;;;;;;OAUG;IACH,OAAO,CAAC,OAAO;IAsBf;;;;;;;;;;;;;;;;;;;OAmBG;IACM,gBAAgB,IAAI,cAAc;IAe3C;;;;;;OAMG;cACgB,aAAa,IAAI,UAAU;cAW3B,UAAU,CAAC,GAAG,EAAE,eAAe,GAAG,IAAI;IAWzD,+EAA+E;IAC/E,OAAO,CAAC,SAAS;IAgCjB;;;;;;;;;;;;;;;;;OAiBG;IACH,OAAO,CAAC,YAAY;IAapB;;;;;;;;OAQG;IACH,OAAO,CAAC,SAAS;IAmCjB,gDAAgD;IAChD,OAAO,CAAC,YAAY;IAsDpB;;;;;;;;OAQG;IACH,OAAO,CAAC,cAAc;IAsBtB;;;;;;;OAOG;IACH,OAAO,CAAC,SAAS;IAgDjB,iFAAiF;IACjF,OAAO,CAAC,YAAY;IA6EpB;;;;;;;OAOG;IACH,OAAO,CAAC,SAAS;CA+ClB"}
1
+ {"version":3,"file":"window.d.ts","sourceRoot":"","sources":["../../src/window/window.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,UAAU,EACV,IAAI,EAEJ,KAAK,cAAc,EACnB,KAAK,SAAS,EACd,KAAK,eAAe,EAGrB,MAAM,mBAAmB,CAAA;AAE1B,OAAO,EAKL,KAAK,WAAW,EACjB,MAAM,gBAAgB,CAAA;AAEvB,sEAAsE;AACtE,MAAM,WAAW,WAAY,SAAQ,SAAS;IAC5C,yEAAyE;IACzE,KAAK,EAAE,WAAW,CAAA;IAClB;;;;;;OAMG;IACH,IAAI,EAAE,OAAO,CAAA;IACb,oDAAoD;IACpD,KAAK,EAAE,MAAM,CAAA;IACb,kEAAkE;IAClE,UAAU,EAAE,MAAM,CAAA;IAClB,oDAAoD;IACpD,IAAI,EAAE,MAAM,CAAA;IACZ;;;;;;;;;OASG;IACH,WAAW,EAAE,MAAM,CAAA;IACnB,qEAAqE;IACrE,QAAQ,EAAE,OAAO,CAAA;CAClB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AACH,qBAea,MAAO,SAAQ,IAAI,CAAC,WAAW,CAAC;IAEnC,KAAK,EAAE,WAAW,CAAA;IACY,IAAI,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,EAAE,MAAM,CAAA;IACI,IAAI,EAAE,MAAM,CAAA;IAE7D,WAAW,EAAE,MAAM,CAAA;IACU,QAAQ,EAAE,OAAO,CAAA;IAEtD;;;;;;;;;;OAUG;IACH,OAAO,CAAC,OAAO;IAsBf;;;;;;;;;;;;;;;;;;;OAmBG;IACM,gBAAgB,IAAI,cAAc;IAe3C;;;;;;OAMG;cACgB,aAAa,IAAI,UAAU;cAW3B,UAAU,CAAC,GAAG,EAAE,eAAe,GAAG,IAAI;IAWzD,+EAA+E;IAC/E,OAAO,CAAC,SAAS;IAgCjB;;;;;;;;;;;;;;;;;OAiBG;IACH,OAAO,CAAC,YAAY;IAapB;;;;;;;;OAQG;IACH,OAAO,CAAC,SAAS;IAmCjB,gDAAgD;IAChD,OAAO,CAAC,YAAY;IAsDpB;;;;;;;;OAQG;IACH,OAAO,CAAC,cAAc;IAsBtB;;;;;;;OAOG;IACH,OAAO,CAAC,SAAS;IAgDjB,iFAAiF;IACjF,OAAO,CAAC,YAAY;IA6EpB;;;;;;;OAOG;IACH,OAAO,CAAC,SAAS;CA+ClB"}
@@ -4,7 +4,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
4
4
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
- import { node, Graphics2D, Rect, property, } from "@motionscript/core";
7
+ import { node, Graphics2D, Rect, property, } from "@motionscript/sdk";
8
8
  import { DEFAULT_WINDOW_STYLE, windowLook, WINDOW_STYLES, } from "./window-style.js";
9
9
  /**
10
10
  * A **window**, as a node.
@@ -1 +1 @@
1
- {"version":3,"file":"window.js","sourceRoot":"","sources":["../../src/window/window.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n node,\n Graphics2D,\n Rect,\n property,\n type InsetsResolved,\n type RectProps,\n type RenderContext2D,\n type ShadowResolved,\n Vector2,\n} from \"@motionscript/core\"\n\nimport {\n DEFAULT_WINDOW_STYLE,\n windowLook,\n WINDOW_STYLES,\n type WindowLook,\n type WindowStyle,\n} from \"./window-style\"\n\n/** A window's own props, over the box and layout every `Rect` has. */\nexport interface WindowProps extends RectProps {\n /** Which operating system's chrome to draw — see {@link WindowStyle}. */\n style: WindowStyle\n /**\n * Draw the chrome's **dark** appearance.\n *\n * Inert on the two vintage styles, which shipped one appearance each and so\n * have no dark twin to switch to — see `WINDOW_DARK_STYLES`, which the panel\n * reads to hide the control rather than offer a switch that does nothing.\n */\n dark: boolean\n /** The words in the title bar. Empty draws none. */\n title: string\n /** The face they are set in. Empty falls back to the built-in. */\n fontFamily: string\n /** The client area behind the window's children. */\n body: string\n /**\n * How much bigger than life the chrome is drawn.\n *\n * `1` is the real operating system's own pixels — a 28pt macOS title bar is 28\n * units tall. The field exists because a window in a 1080p composition is\n * usually shown *larger* than life, and everything that makes chrome read as\n * chrome (the title bar's height, the traffic lights' 12px, a bevel's 2px) is\n * an absolute measurement rather than a fraction of the frame. Scaling the\n * node instead would scale its contents too.\n */\n chromeScale: number\n /** Draw the caption buttons. Off is a sheet, a palette, a dialog. */\n controls: boolean\n}\n\n/**\n * A **window**, as a node.\n *\n * The frame every software demo is shot inside, and the third thing the UI shelf\n * needed: the cursor is the person, the switch and the button are what they\n * touch, and this is the thing all of it is happening *in*.\n *\n * ## Why it is a `Rect`\n *\n * Alone among the controls here — the switch and the button both extend\n * {@link ControlNode}, which is a bare `Node2D`. A window is different in kind\n * because it has an **inside**: the whole point of one is to put a screenshot, a\n * chart or a caption in it, and that means real layout, real padding and a real\n * clip against the frame's own rounded corners. `Rect` is the one class in\n * motion-script that does all three, so the window is a Rect whose paint is\n * replaced rather than a node that draws a rectangle.\n *\n * {@link shapeGraphics} is overridden along with {@link renderSelf}, and that is\n * the half that makes the clip work: the silhouette a child is cut against has\n * to be the window's *rounded* outline, not the square box it was laid out in.\n *\n * ## Chrome is drawn in real pixels\n *\n * Everything else on this shelf states its metrics as fractions of its own box,\n * because a switch's box *is* its design. A window's is not: a title bar is 28\n * points tall on a small window and on a large one, which is exactly why a\n * window can be dragged to any size and still look like a window. So the look's\n * numbers are the operating system's own (see `model/window-style.ts`) and the\n * only thing between them and the canvas is {@link WindowProps.chromeScale}.\n *\n * That is also why this node is **not aspect-locked** where the switch is. Its\n * shape is not part of its identity — being resizable is.\n *\n * ## The chrome is padding\n *\n * A window's children belong in its **body**, not in its box: a child set to\n * fill its container should fill the client area and stop at the title bar,\n * because that is what filling a window means to everyone who has ever used one.\n * That is stated as {@link effectivePadding} — the same seam `Rect` already uses\n * to keep children clear of its stroke, extended with the frame's border and the\n * title bar's height. Saying it there rather than in the drawing is what makes it\n * true of *measurement* as well as of paint: `hug` sizes around it, `fill` sizes\n * inside it, and a child never has to know a title bar exists.\n *\n * ## No commands\n *\n * Deliberately none of its own. A switch flips and a button is pressed; a window\n * *is*, and everything anyone would animate about one — where it sits, how big\n * it is, whether it has faded in — is a property of the box that `to`, `moveTo`\n * and `scaleTo` already reach.\n */\n@node({\n key: \"window\",\n parentKey: \"node\",\n forkable: true,\n layout: {\n children: \"flow\",\n defaultWidthMode: \"fixed\",\n defaultHeightMode: \"fixed\",\n acceptsChildren: true,\n },\n seed: {\n width: 720,\n height: 480,\n },\n})\nexport class Window extends Rect<WindowProps> {\n @property({ default: DEFAULT_WINDOW_STYLE, kind: \"enum\", options: WINDOW_STYLES })\n declare style: WindowStyle\n @property({ default: false }) declare dark: boolean\n @property({ default: \"\" }) declare title: string\n @property({ default: \"\" }) declare fontFamily: string\n @property({ default: \"#ffffff\", kind: \"color\" }) declare body: string\n @property({ default: 1, min: 0.5, max: 3, step: 0.05, unit: \"×\" })\n declare chromeScale: number\n @property({ default: true }) declare controls: boolean\n\n /**\n * Every measurement the drawing needs, in the node's own pixels.\n *\n * The look's numbers times the scale, resolved once — three near-identical\n * `look.titleBar * scale` expressions is how a title bar and the thing drawn\n * inside it end up a pixel apart.\n *\n * The title bar is capped at half the window, so a window dragged shorter than\n * its own chrome degrades to a bar with a sliver under it rather than to a\n * client area with a negative height.\n */\n private metrics() {\n const bounds = this.layoutBounds\n const width = bounds?.width ?? 0\n const height = bounds?.height ?? 0\n const look = windowLook(this.style, this.dark)\n const scale = Math.max(0.01, this.chromeScale)\n\n const titleBar = Math.min(look.titleBar * scale, height / 2)\n return {\n width,\n height,\n look,\n scale,\n titleBar,\n radius: Math.min(look.radius * scale, width / 2, height / 2),\n border: look.border * scale,\n /** The top edge in the node's own y-up space. */\n top: height / 2,\n left: -width / 2,\n }\n }\n\n /**\n * The chrome, as padding — so children are laid out in the **body**.\n *\n * `Rect` already treats the part of its stroke that intrudes on the content\n * box as padding, for exactly this reason: a child must not be laid out under\n * paint the parent is going to draw over it. A window's chrome is the same\n * problem several sizes larger — a title bar is 28 points of the box that\n * belongs to the operating system, not to the author's content — so it is\n * answered in the same place, and everything downstream follows without\n * knowing why. A child at `width: \"fill\"` fills the client area; one at\n * `height: \"fill\"` stops under the title bar; a window that hugs hugs around\n * its chrome rather than inside it.\n *\n * The title bar's *uncapped* height is used, unlike everywhere in the drawing:\n * layout runs before this node has a box (that is what it is computing), and\n * the cap in {@link metrics} is a function of the box. A window shorter than\n * its own chrome therefore lays its children out in a content box of zero\n * height, which is the honest answer — there is no client area in a window\n * that is all title bar.\n */\n override effectivePadding(): InsetsResolved {\n const base = super.effectivePadding()\n const look = windowLook(this.style, this.dark)\n const scale = Math.max(0.01, this.chromeScale)\n // The frame's own border, doubled where the chrome is a two-ring bevel —\n // the same inset the title bar is drawn at, so the two cannot disagree.\n const inset = look.border * scale * (look.bevel ? 2 : 1)\n return {\n left: base.left + inset,\n right: base.right + inset,\n top: base.top + inset + look.titleBar * scale,\n bottom: base.bottom + inset,\n }\n }\n\n /**\n * The window's outline — what a nested child is clipped against.\n *\n * Overridden so the clip follows the *rounded* frame. `Rect`'s own answer is\n * the same shape with this node's `cornerRadius`, which a window does not\n * carry: its corner is the operating system's, not the author's.\n */\n protected override shapeGraphics(): Graphics2D {\n const m = this.metrics()\n return new Graphics2D().rect({\n x: 0,\n y: 0,\n width: m.width,\n height: m.height,\n cornerRadius: m.radius,\n })\n }\n\n protected override renderSelf(ctx: RenderContext2D): void {\n const m = this.metrics()\n if (m.width <= 0 || m.height <= 0) return\n\n this.drawFrame(ctx, m)\n this.drawTitleBar(ctx, m)\n if (m.look.pinstripe) this.drawPinstripes(ctx, m)\n this.drawTitle(ctx, m)\n if (this.controls) this.drawControls(ctx, m)\n }\n\n /** The client area, its outer border, and the shadow the whole thing casts. */\n private drawFrame(ctx: RenderContext2D, m: Metrics): void {\n const frame = new Graphics2D().rect({\n x: 0,\n y: 0,\n width: m.width,\n height: m.height,\n cornerRadius: m.radius,\n })\n const authored = this.shadow as ShadowResolved[]\n if (authored.length > 0) {\n frame.shadow(authored)\n } else if (m.look.shadow > 0) {\n frame.shadow(this.chromeShadow(m))\n }\n frame.fill(this.body)\n if (m.border > 0 && !m.look.bevel) {\n frame.stroke({\n weight: m.border,\n fill: m.look.borderColor,\n align: \"inside\",\n })\n }\n ctx.draw(frame)\n\n // Windows 95's frame is not a border, it is a **bevel**: two nested rings,\n // light on the top-left and dark on the bottom-right, which is what makes\n // the whole window read as a raised physical object. There is no stroke that\n // draws that — a stroke has one colour all the way round — so it is four\n // strips a side, drawn as two L-shaped pairs.\n if (m.look.bevel) this.drawBevel(ctx, m)\n }\n\n /**\n * The drop the chrome itself comes with, drawn when the author has not put a\n * stack of their own in the Shadows section.\n *\n * The one place a window's paint slots do **not** behave exactly like a\n * shape's, and the deviation is worth stating: on a `Rect` an empty Shadows\n * section means no shadow, whereas here it means *the chrome's own*. Both\n * modern chromes ship a drop — a macOS window is separated from the desktop by\n * nothing else — so an empty stack meaning \"flat\" would make every window look\n * wrong until the author discovered a section they had no reason to open, and\n * would make the two vintage chromes (which really are flat) indistinguishable\n * from a bug. Adding a shadow replaces it, wholesale, which is the behaviour\n * that lets an author light a window however they like; removing the last one\n * hands the chrome back its own.\n *\n * Its offset is a quarter of its blur, downward — negative in this y-up space\n * — which is what every OS's own drop uses.\n */\n private chromeShadow(m: Metrics): {\n blur: number\n offset: { x: number; y: number }\n fill: string\n } {\n const blur = m.look.shadow * m.scale\n return {\n blur,\n offset: { x: 0, y: -blur * 0.25 },\n fill: \"rgba(0, 0, 0, 0.28)\",\n }\n }\n\n /**\n * A raised (or, with `depth` negative, a sunken) 3D edge — Windows 95's whole\n * visual language, and the one piece of chrome here that cannot be a stroke.\n *\n * Two rings: an outer one in white / black and an inner one in light grey /\n * dark grey, each drawn as an L along the top-and-left and another along the\n * bottom-and-right. Reused for the caption chips, which are the same edge at\n * a smaller radius.\n */\n private drawBevel(\n ctx: RenderContext2D,\n m: Metrics,\n box = { x: 0, y: 0, width: m.width, height: m.height },\n raised = true\n ): void {\n const t = Math.max(1, m.scale)\n const half = { w: box.width / 2, h: box.height / 2 }\n const light = raised ? \"#ffffff\" : \"#808080\"\n const dark = raised ? \"#0a0a0a\" : \"#ffffff\"\n const innerLight = raised ? \"#dfdfdf\" : \"#808080\"\n const innerDark = raised ? \"#808080\" : \"#dfdfdf\"\n\n /** One L: a horizontal strip and a vertical one, meeting at `corner`. */\n const edge = (inset: number, colour: string, corner: \"tl\" | \"br\") => {\n const g = new Graphics2D()\n const top = corner === \"tl\"\n const y = top\n ? box.y + half.h - inset - t / 2\n : box.y - half.h + inset + t / 2\n const x = top\n ? box.x - half.w + inset + t / 2\n : box.x + half.w - inset - t / 2\n const span = { w: box.width - inset * 2, h: box.height - inset * 2 }\n g.rect({ x: box.x, y, width: span.w, height: t })\n g.rect({ x, y: box.y, width: t, height: span.h })\n ctx.draw(g.fill(colour))\n }\n\n edge(0, light, \"tl\")\n edge(0, dark, \"br\")\n edge(t, innerLight, \"tl\")\n edge(t, innerDark, \"br\")\n }\n\n /** The bar across the top, flat or gradient. */\n private drawTitleBar(ctx: RenderContext2D, m: Metrics): void {\n if (m.titleBar <= 0) return\n // Inside the bevel where there is one, so the navy bar sits *within* the\n // grey frame rather than running under it — which is what Windows 95 does\n // and what makes the frame read as surrounding the bar.\n const inset = m.look.bevel ? m.border * 2 : m.border\n const barWidth = m.width - inset * 2\n const bar = new Graphics2D().rect({\n x: 0,\n y: m.top - inset - m.titleBar / 2,\n width: barWidth,\n height: m.titleBar,\n // Only the top corners are the window's; the bottom two are square where\n // the bar meets the client area. Stated as a per-corner bag rather than\n // clipped, which would need a whole mask scope for two corners.\n cornerRadius: {\n topLeft: Math.max(0, m.radius - inset),\n topRight: Math.max(0, m.radius - inset),\n bottomLeft: 0,\n bottomRight: 0,\n },\n })\n\n if (m.look.titleBarTo !== \"\") {\n // Left to right, which is Windows 95's own direction. The endpoints are\n // in the renderer's own gradient space — −1…+1 from the box's centre,\n // y up — rather than in pixels; see `toGradientPoint` in `motion-paints`,\n // which exists because those two spaces are easy to confuse.\n bar.fill({\n type: \"linear-gradient\",\n colors: [m.look.titleBarColor, m.look.titleBarTo],\n stops: [0, 1],\n start: { x: -1, y: 0 },\n end: { x: 1, y: 0 },\n })\n } else {\n bar.fill(m.look.titleBarColor)\n }\n ctx.draw(bar)\n\n if (m.look.separator !== \"\") {\n ctx.draw(\n new Graphics2D()\n .rect({\n x: 0,\n y: m.top - inset - m.titleBar,\n width: barWidth,\n height: Math.max(1, m.scale),\n })\n .fill(m.look.separator)\n )\n }\n }\n\n /**\n * System 7's horizontal stripes — six lines across the bar, every other pixel.\n *\n * Drawn as real 1px rules at 1× rather than as a texture, because at\n * `chromeScale: 2` a texture would blur where the real thing simply had\n * thicker lines. The run stops short of the controls and of the title, which\n * is how the bar was actually drawn: the stripes are the *background*, and\n * anything sitting on the bar interrupts them.\n */\n private drawPinstripes(ctx: RenderContext2D, m: Metrics): void {\n const inset = m.border\n const weight = Math.max(1, m.scale)\n const pitch = weight * 2\n const stripes = new Graphics2D()\n const barTop = m.top - inset\n // Two pixels of clearance top and bottom, as System 7 left.\n for (\n let y = barTop - pitch * 2;\n y > barTop - m.titleBar + weight;\n y -= pitch\n ) {\n stripes.rect({\n x: 0,\n y,\n width: m.width - inset * 2,\n height: weight,\n })\n }\n ctx.draw(stripes.fill(m.look.titleColor))\n }\n\n /**\n * The title, and — on a pinstriped bar — the gap it sits in.\n *\n * The gap is the detail that makes System 7 read as System 7: the words do not\n * sit *on* the stripes, they sit in a hole punched through them. Drawn as a\n * bar-coloured rectangle behind the text, sized from the same width estimate\n * the button's label uses (see `estimateWidth` there for why an estimate).\n */\n private drawTitle(ctx: RenderContext2D, m: Metrics): void {\n if (this.title === \"\" || m.titleBar <= 0) return\n const inset = m.look.bevel ? m.border * 2 : m.border\n const size = m.look.titleSize * m.scale\n const y = m.top - inset - m.titleBar / 2\n const width = this.title.length * size * 0.55\n\n // Where the title starts. Centred on both Macs; on Windows it follows the\n // left edge, clearing the controls only when they are on that side.\n const x =\n m.look.titleAlign === \"center\"\n ? 0\n : m.left + inset + m.look.controlInset * m.scale + width / 2\n\n if (m.look.pinstripe) {\n const pad = size * 0.6\n ctx.draw(\n new Graphics2D()\n .rect({\n x,\n y,\n width: width + pad * 2,\n height: m.titleBar - m.scale * 4,\n })\n .fill(m.look.titleBarColor)\n )\n }\n\n ctx.draw(\n new Graphics2D()\n .text({\n text: this.title,\n x,\n y,\n width,\n fontSize: size,\n // Already resolved: the props mapper fills an empty family in from\n // the host (see `nodes/kit/text-defaults`), so the node never has to\n // know which typeface this application ships.\n fontFamily: this.fontFamily,\n fontWeight: m.look.titleWeight,\n textAlign: \"center\",\n wrap: false,\n })\n .fill(m.look.titleColor)\n )\n }\n\n /** The three caption buttons, in whichever of the four idioms the style uses. */\n private drawControls(ctx: RenderContext2D, m: Metrics): void {\n if (m.titleBar <= 0) return\n const inset = m.look.bevel ? m.border * 2 : m.border\n const size = m.look.controlSize * m.scale\n const height = m.look.controlHeight * m.scale\n const gap = m.look.controlGap * m.scale\n const edge = m.look.controlInset * m.scale\n const y = m.top - inset - m.titleBar / 2\n const rightward = m.look.controlsSide === \"left\"\n\n /** The centre of control `i`, counting outward from the window's near edge. */\n const centreOf = (i: number): number => {\n const first = rightward\n ? m.left + inset + edge + size / 2\n : -m.left - inset - edge - size / 2\n const step = gap || size * 1.6\n return rightward ? first + step * i : first - step * i\n }\n\n // Which button sits where, counting **outward from the corner the controls\n // are pinned to** — which is the only ordering both sides have in common.\n //\n // Close is nearest that corner in both idioms: leftmost on a Mac, rightmost\n // on Windows. What differs is the other two. A Mac runs close, minimise,\n // zoom left to right; Windows runs minimise, maximise, close — so counting\n // in from its right-hand corner gives close, maximise, minimise. The colour\n // list is always in close/minimise/maximise order, so it is the order that\n // is stated here rather than the list that is rebuilt.\n const order = rightward ? [0, 1, 2] : [0, 2, 1]\n\n for (let i = 0; i < 3; i++) {\n const slot = order[i]\n const x = centreOf(i)\n const colour = m.look.controlColors[slot]\n\n switch (m.look.controlsShape) {\n case \"lights\":\n ctx.draw(\n new Graphics2D()\n .ellipse({ x, y, width: size, height: size })\n .fill(colour)\n )\n break\n\n case \"boxes\":\n // System 7 drew a close box at the left and a zoom box at the right,\n // and nothing in between — so the middle slot is skipped rather than\n // drawn as a third square the OS never had.\n if (i === 1) break\n ctx.draw(\n new Graphics2D()\n .rect({\n x: i === 0 ? x : -centreOf(0),\n y,\n width: size,\n height: height,\n })\n .fill(m.look.titleBarColor)\n .stroke({ weight: m.scale, fill: colour, align: \"inside\" })\n )\n break\n\n case \"chips\":\n ctx.draw(\n new Graphics2D().rect({ x, y, width: size, height }).fill(\"#c0c0c0\")\n )\n this.drawBevel(ctx, m, { x, y, width: size, height }, true)\n this.drawGlyph(ctx, slot, x, y, size * 0.42, \"#000000\", m.scale)\n break\n\n case \"glyphs\":\n this.drawGlyph(ctx, slot, x, y, size, colour, m.scale)\n break\n }\n }\n }\n\n /**\n * A caption glyph: a minus, a square, or a cross.\n *\n * Drawn from strokes rather than typed as text, because these are the same\n * three marks in every chrome that has them and a font would put whatever the\n * renderer happened to shape into a 10px box. `slot` is close / minimise /\n * maximise, matching the colour list's order.\n */\n private drawGlyph(\n ctx: RenderContext2D,\n slot: number,\n x: number,\n y: number,\n size: number,\n colour: string,\n scale: number\n ): void {\n const r = size / 2\n const g = new Graphics2D()\n const weight = Math.max(1, scale)\n /** One stroked rule, drawn on its own — see the cross below for why. */\n const rule = (from: Vector2, to: Vector2) =>\n ctx.draw(\n new Graphics2D()\n .line({ points: [from, to] })\n .stroke({ weight, fill: colour, align: \"center\", cap: \"butt\" })\n )\n\n if (slot === 0) {\n // The cross, as two crossing rules — and each is its own draw.\n //\n // A `Graphics2D` unions every shape declared before a paint call and\n // paints them as one surface, which is right for two rects making an L\n // (see {@link drawBevel}) and wrong for two *lines*: the union of two open\n // strokes is not a shape the stroker can trace, and what came out was\n // nothing at all — a close button that was positioned, coloured and\n // invisible. One draw each is the whole fix; the marks do not need to\n // share a paint, since they are one colour by construction.\n rule({ x: x - r, y: y - r }, { x: x + r, y: y + r })\n rule({ x: x - r, y: y + r }, { x: x + r, y: y - r })\n return\n }\n\n if (slot === 1) {\n // The minimise rule, sitting on the baseline rather than the middle in the\n // chrome that draws it low — but centred reads correctly at every size and\n // is what both modern shells do.\n rule({ x: x - r, y }, { x: x + r, y })\n return\n }\n\n // The maximise square, hollow.\n g.rect({ x, y, width: size, height: size })\n ctx.draw(g.stroke({ weight, fill: colour, align: \"center\", cap: \"butt\" }))\n }\n}\n\n\n\n/** What {@link Window.metrics} hands round — named so the helpers can take it. */\ntype Metrics = {\n width: number\n height: number\n look: WindowLook\n scale: number\n titleBar: number\n radius: number\n border: number\n top: number\n left: number\n}\n"]}
1
+ {"version":3,"file":"window.js","sourceRoot":"","sources":["../../src/window/window.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n node,\n Graphics2D,\n Rect,\n property,\n type InsetsResolved,\n type RectProps,\n type RenderContext2D,\n type ShadowResolved,\n Vector2,\n} from \"@motionscript/sdk\"\n\nimport {\n DEFAULT_WINDOW_STYLE,\n windowLook,\n WINDOW_STYLES,\n type WindowLook,\n type WindowStyle,\n} from \"./window-style\"\n\n/** A window's own props, over the box and layout every `Rect` has. */\nexport interface WindowProps extends RectProps {\n /** Which operating system's chrome to draw — see {@link WindowStyle}. */\n style: WindowStyle\n /**\n * Draw the chrome's **dark** appearance.\n *\n * Inert on the two vintage styles, which shipped one appearance each and so\n * have no dark twin to switch to — see `WINDOW_DARK_STYLES`, which the panel\n * reads to hide the control rather than offer a switch that does nothing.\n */\n dark: boolean\n /** The words in the title bar. Empty draws none. */\n title: string\n /** The face they are set in. Empty falls back to the built-in. */\n fontFamily: string\n /** The client area behind the window's children. */\n body: string\n /**\n * How much bigger than life the chrome is drawn.\n *\n * `1` is the real operating system's own pixels — a 28pt macOS title bar is 28\n * units tall. The field exists because a window in a 1080p composition is\n * usually shown *larger* than life, and everything that makes chrome read as\n * chrome (the title bar's height, the traffic lights' 12px, a bevel's 2px) is\n * an absolute measurement rather than a fraction of the frame. Scaling the\n * node instead would scale its contents too.\n */\n chromeScale: number\n /** Draw the caption buttons. Off is a sheet, a palette, a dialog. */\n controls: boolean\n}\n\n/**\n * A **window**, as a node.\n *\n * The frame every software demo is shot inside, and the third thing the UI shelf\n * needed: the cursor is the person, the switch and the button are what they\n * touch, and this is the thing all of it is happening *in*.\n *\n * ## Why it is a `Rect`\n *\n * Alone among the controls here — the switch and the button both extend\n * {@link ControlNode}, which is a bare `Node2D`. A window is different in kind\n * because it has an **inside**: the whole point of one is to put a screenshot, a\n * chart or a caption in it, and that means real layout, real padding and a real\n * clip against the frame's own rounded corners. `Rect` is the one class in\n * motion-script that does all three, so the window is a Rect whose paint is\n * replaced rather than a node that draws a rectangle.\n *\n * {@link shapeGraphics} is overridden along with {@link renderSelf}, and that is\n * the half that makes the clip work: the silhouette a child is cut against has\n * to be the window's *rounded* outline, not the square box it was laid out in.\n *\n * ## Chrome is drawn in real pixels\n *\n * Everything else on this shelf states its metrics as fractions of its own box,\n * because a switch's box *is* its design. A window's is not: a title bar is 28\n * points tall on a small window and on a large one, which is exactly why a\n * window can be dragged to any size and still look like a window. So the look's\n * numbers are the operating system's own (see `model/window-style.ts`) and the\n * only thing between them and the canvas is {@link WindowProps.chromeScale}.\n *\n * That is also why this node is **not aspect-locked** where the switch is. Its\n * shape is not part of its identity — being resizable is.\n *\n * ## The chrome is padding\n *\n * A window's children belong in its **body**, not in its box: a child set to\n * fill its container should fill the client area and stop at the title bar,\n * because that is what filling a window means to everyone who has ever used one.\n * That is stated as {@link effectivePadding} — the same seam `Rect` already uses\n * to keep children clear of its stroke, extended with the frame's border and the\n * title bar's height. Saying it there rather than in the drawing is what makes it\n * true of *measurement* as well as of paint: `hug` sizes around it, `fill` sizes\n * inside it, and a child never has to know a title bar exists.\n *\n * ## No commands\n *\n * Deliberately none of its own. A switch flips and a button is pressed; a window\n * *is*, and everything anyone would animate about one — where it sits, how big\n * it is, whether it has faded in — is a property of the box that `to`, `moveTo`\n * and `scaleTo` already reach.\n */\n@node({\n key: \"window\",\n parentKey: \"node\",\n forkable: true,\n layout: {\n children: \"flow\",\n defaultWidthMode: \"fixed\",\n defaultHeightMode: \"fixed\",\n acceptsChildren: true,\n },\n seed: {\n width: 720,\n height: 480,\n },\n})\nexport class Window extends Rect<WindowProps> {\n @property({ default: DEFAULT_WINDOW_STYLE, kind: \"enum\", options: WINDOW_STYLES })\n declare style: WindowStyle\n @property({ default: false }) declare dark: boolean\n @property({ default: \"\" }) declare title: string\n @property({ default: \"\" }) declare fontFamily: string\n @property({ default: \"#ffffff\", kind: \"color\" }) declare body: string\n @property({ default: 1, min: 0.5, max: 3, step: 0.05, unit: \"×\" })\n declare chromeScale: number\n @property({ default: true }) declare controls: boolean\n\n /**\n * Every measurement the drawing needs, in the node's own pixels.\n *\n * The look's numbers times the scale, resolved once — three near-identical\n * `look.titleBar * scale` expressions is how a title bar and the thing drawn\n * inside it end up a pixel apart.\n *\n * The title bar is capped at half the window, so a window dragged shorter than\n * its own chrome degrades to a bar with a sliver under it rather than to a\n * client area with a negative height.\n */\n private metrics() {\n const bounds = this.layoutBounds\n const width = bounds?.width ?? 0\n const height = bounds?.height ?? 0\n const look = windowLook(this.style, this.dark)\n const scale = Math.max(0.01, this.chromeScale)\n\n const titleBar = Math.min(look.titleBar * scale, height / 2)\n return {\n width,\n height,\n look,\n scale,\n titleBar,\n radius: Math.min(look.radius * scale, width / 2, height / 2),\n border: look.border * scale,\n /** The top edge in the node's own y-up space. */\n top: height / 2,\n left: -width / 2,\n }\n }\n\n /**\n * The chrome, as padding — so children are laid out in the **body**.\n *\n * `Rect` already treats the part of its stroke that intrudes on the content\n * box as padding, for exactly this reason: a child must not be laid out under\n * paint the parent is going to draw over it. A window's chrome is the same\n * problem several sizes larger — a title bar is 28 points of the box that\n * belongs to the operating system, not to the author's content — so it is\n * answered in the same place, and everything downstream follows without\n * knowing why. A child at `width: \"fill\"` fills the client area; one at\n * `height: \"fill\"` stops under the title bar; a window that hugs hugs around\n * its chrome rather than inside it.\n *\n * The title bar's *uncapped* height is used, unlike everywhere in the drawing:\n * layout runs before this node has a box (that is what it is computing), and\n * the cap in {@link metrics} is a function of the box. A window shorter than\n * its own chrome therefore lays its children out in a content box of zero\n * height, which is the honest answer — there is no client area in a window\n * that is all title bar.\n */\n override effectivePadding(): InsetsResolved {\n const base = super.effectivePadding()\n const look = windowLook(this.style, this.dark)\n const scale = Math.max(0.01, this.chromeScale)\n // The frame's own border, doubled where the chrome is a two-ring bevel —\n // the same inset the title bar is drawn at, so the two cannot disagree.\n const inset = look.border * scale * (look.bevel ? 2 : 1)\n return {\n left: base.left + inset,\n right: base.right + inset,\n top: base.top + inset + look.titleBar * scale,\n bottom: base.bottom + inset,\n }\n }\n\n /**\n * The window's outline — what a nested child is clipped against.\n *\n * Overridden so the clip follows the *rounded* frame. `Rect`'s own answer is\n * the same shape with this node's `cornerRadius`, which a window does not\n * carry: its corner is the operating system's, not the author's.\n */\n protected override shapeGraphics(): Graphics2D {\n const m = this.metrics()\n return new Graphics2D().rect({\n x: 0,\n y: 0,\n width: m.width,\n height: m.height,\n cornerRadius: m.radius,\n })\n }\n\n protected override renderSelf(ctx: RenderContext2D): void {\n const m = this.metrics()\n if (m.width <= 0 || m.height <= 0) return\n\n this.drawFrame(ctx, m)\n this.drawTitleBar(ctx, m)\n if (m.look.pinstripe) this.drawPinstripes(ctx, m)\n this.drawTitle(ctx, m)\n if (this.controls) this.drawControls(ctx, m)\n }\n\n /** The client area, its outer border, and the shadow the whole thing casts. */\n private drawFrame(ctx: RenderContext2D, m: Metrics): void {\n const frame = new Graphics2D().rect({\n x: 0,\n y: 0,\n width: m.width,\n height: m.height,\n cornerRadius: m.radius,\n })\n const authored = this.shadow as ShadowResolved[]\n if (authored.length > 0) {\n frame.shadow(authored)\n } else if (m.look.shadow > 0) {\n frame.shadow(this.chromeShadow(m))\n }\n frame.fill(this.body)\n if (m.border > 0 && !m.look.bevel) {\n frame.stroke({\n weight: m.border,\n fill: m.look.borderColor,\n align: \"inside\",\n })\n }\n ctx.draw(frame)\n\n // Windows 95's frame is not a border, it is a **bevel**: two nested rings,\n // light on the top-left and dark on the bottom-right, which is what makes\n // the whole window read as a raised physical object. There is no stroke that\n // draws that — a stroke has one colour all the way round — so it is four\n // strips a side, drawn as two L-shaped pairs.\n if (m.look.bevel) this.drawBevel(ctx, m)\n }\n\n /**\n * The drop the chrome itself comes with, drawn when the author has not put a\n * stack of their own in the Shadows section.\n *\n * The one place a window's paint slots do **not** behave exactly like a\n * shape's, and the deviation is worth stating: on a `Rect` an empty Shadows\n * section means no shadow, whereas here it means *the chrome's own*. Both\n * modern chromes ship a drop — a macOS window is separated from the desktop by\n * nothing else — so an empty stack meaning \"flat\" would make every window look\n * wrong until the author discovered a section they had no reason to open, and\n * would make the two vintage chromes (which really are flat) indistinguishable\n * from a bug. Adding a shadow replaces it, wholesale, which is the behaviour\n * that lets an author light a window however they like; removing the last one\n * hands the chrome back its own.\n *\n * Its offset is a quarter of its blur, downward — negative in this y-up space\n * — which is what every OS's own drop uses.\n */\n private chromeShadow(m: Metrics): {\n blur: number\n offset: { x: number; y: number }\n fill: string\n } {\n const blur = m.look.shadow * m.scale\n return {\n blur,\n offset: { x: 0, y: -blur * 0.25 },\n fill: \"rgba(0, 0, 0, 0.28)\",\n }\n }\n\n /**\n * A raised (or, with `depth` negative, a sunken) 3D edge — Windows 95's whole\n * visual language, and the one piece of chrome here that cannot be a stroke.\n *\n * Two rings: an outer one in white / black and an inner one in light grey /\n * dark grey, each drawn as an L along the top-and-left and another along the\n * bottom-and-right. Reused for the caption chips, which are the same edge at\n * a smaller radius.\n */\n private drawBevel(\n ctx: RenderContext2D,\n m: Metrics,\n box = { x: 0, y: 0, width: m.width, height: m.height },\n raised = true\n ): void {\n const t = Math.max(1, m.scale)\n const half = { w: box.width / 2, h: box.height / 2 }\n const light = raised ? \"#ffffff\" : \"#808080\"\n const dark = raised ? \"#0a0a0a\" : \"#ffffff\"\n const innerLight = raised ? \"#dfdfdf\" : \"#808080\"\n const innerDark = raised ? \"#808080\" : \"#dfdfdf\"\n\n /** One L: a horizontal strip and a vertical one, meeting at `corner`. */\n const edge = (inset: number, colour: string, corner: \"tl\" | \"br\") => {\n const g = new Graphics2D()\n const top = corner === \"tl\"\n const y = top\n ? box.y + half.h - inset - t / 2\n : box.y - half.h + inset + t / 2\n const x = top\n ? box.x - half.w + inset + t / 2\n : box.x + half.w - inset - t / 2\n const span = { w: box.width - inset * 2, h: box.height - inset * 2 }\n g.rect({ x: box.x, y, width: span.w, height: t })\n g.rect({ x, y: box.y, width: t, height: span.h })\n ctx.draw(g.fill(colour))\n }\n\n edge(0, light, \"tl\")\n edge(0, dark, \"br\")\n edge(t, innerLight, \"tl\")\n edge(t, innerDark, \"br\")\n }\n\n /** The bar across the top, flat or gradient. */\n private drawTitleBar(ctx: RenderContext2D, m: Metrics): void {\n if (m.titleBar <= 0) return\n // Inside the bevel where there is one, so the navy bar sits *within* the\n // grey frame rather than running under it — which is what Windows 95 does\n // and what makes the frame read as surrounding the bar.\n const inset = m.look.bevel ? m.border * 2 : m.border\n const barWidth = m.width - inset * 2\n const bar = new Graphics2D().rect({\n x: 0,\n y: m.top - inset - m.titleBar / 2,\n width: barWidth,\n height: m.titleBar,\n // Only the top corners are the window's; the bottom two are square where\n // the bar meets the client area. Stated as a per-corner bag rather than\n // clipped, which would need a whole mask scope for two corners.\n cornerRadius: {\n topLeft: Math.max(0, m.radius - inset),\n topRight: Math.max(0, m.radius - inset),\n bottomLeft: 0,\n bottomRight: 0,\n },\n })\n\n if (m.look.titleBarTo !== \"\") {\n // Left to right, which is Windows 95's own direction. The endpoints are\n // in the renderer's own gradient space — −1…+1 from the box's centre,\n // y up — rather than in pixels; see `toGradientPoint` in `motion-paints`,\n // which exists because those two spaces are easy to confuse.\n bar.fill({\n type: \"linear-gradient\",\n colors: [m.look.titleBarColor, m.look.titleBarTo],\n stops: [0, 1],\n start: { x: -1, y: 0 },\n end: { x: 1, y: 0 },\n })\n } else {\n bar.fill(m.look.titleBarColor)\n }\n ctx.draw(bar)\n\n if (m.look.separator !== \"\") {\n ctx.draw(\n new Graphics2D()\n .rect({\n x: 0,\n y: m.top - inset - m.titleBar,\n width: barWidth,\n height: Math.max(1, m.scale),\n })\n .fill(m.look.separator)\n )\n }\n }\n\n /**\n * System 7's horizontal stripes — six lines across the bar, every other pixel.\n *\n * Drawn as real 1px rules at 1× rather than as a texture, because at\n * `chromeScale: 2` a texture would blur where the real thing simply had\n * thicker lines. The run stops short of the controls and of the title, which\n * is how the bar was actually drawn: the stripes are the *background*, and\n * anything sitting on the bar interrupts them.\n */\n private drawPinstripes(ctx: RenderContext2D, m: Metrics): void {\n const inset = m.border\n const weight = Math.max(1, m.scale)\n const pitch = weight * 2\n const stripes = new Graphics2D()\n const barTop = m.top - inset\n // Two pixels of clearance top and bottom, as System 7 left.\n for (\n let y = barTop - pitch * 2;\n y > barTop - m.titleBar + weight;\n y -= pitch\n ) {\n stripes.rect({\n x: 0,\n y,\n width: m.width - inset * 2,\n height: weight,\n })\n }\n ctx.draw(stripes.fill(m.look.titleColor))\n }\n\n /**\n * The title, and — on a pinstriped bar — the gap it sits in.\n *\n * The gap is the detail that makes System 7 read as System 7: the words do not\n * sit *on* the stripes, they sit in a hole punched through them. Drawn as a\n * bar-coloured rectangle behind the text, sized from the same width estimate\n * the button's label uses (see `estimateWidth` there for why an estimate).\n */\n private drawTitle(ctx: RenderContext2D, m: Metrics): void {\n if (this.title === \"\" || m.titleBar <= 0) return\n const inset = m.look.bevel ? m.border * 2 : m.border\n const size = m.look.titleSize * m.scale\n const y = m.top - inset - m.titleBar / 2\n const width = this.title.length * size * 0.55\n\n // Where the title starts. Centred on both Macs; on Windows it follows the\n // left edge, clearing the controls only when they are on that side.\n const x =\n m.look.titleAlign === \"center\"\n ? 0\n : m.left + inset + m.look.controlInset * m.scale + width / 2\n\n if (m.look.pinstripe) {\n const pad = size * 0.6\n ctx.draw(\n new Graphics2D()\n .rect({\n x,\n y,\n width: width + pad * 2,\n height: m.titleBar - m.scale * 4,\n })\n .fill(m.look.titleBarColor)\n )\n }\n\n ctx.draw(\n new Graphics2D()\n .text({\n text: this.title,\n x,\n y,\n width,\n fontSize: size,\n // Already resolved: the props mapper fills an empty family in from\n // the host (see `nodes/kit/text-defaults`), so the node never has to\n // know which typeface this application ships.\n fontFamily: this.fontFamily,\n fontWeight: m.look.titleWeight,\n textAlign: \"center\",\n wrap: false,\n })\n .fill(m.look.titleColor)\n )\n }\n\n /** The three caption buttons, in whichever of the four idioms the style uses. */\n private drawControls(ctx: RenderContext2D, m: Metrics): void {\n if (m.titleBar <= 0) return\n const inset = m.look.bevel ? m.border * 2 : m.border\n const size = m.look.controlSize * m.scale\n const height = m.look.controlHeight * m.scale\n const gap = m.look.controlGap * m.scale\n const edge = m.look.controlInset * m.scale\n const y = m.top - inset - m.titleBar / 2\n const rightward = m.look.controlsSide === \"left\"\n\n /** The centre of control `i`, counting outward from the window's near edge. */\n const centreOf = (i: number): number => {\n const first = rightward\n ? m.left + inset + edge + size / 2\n : -m.left - inset - edge - size / 2\n const step = gap || size * 1.6\n return rightward ? first + step * i : first - step * i\n }\n\n // Which button sits where, counting **outward from the corner the controls\n // are pinned to** — which is the only ordering both sides have in common.\n //\n // Close is nearest that corner in both idioms: leftmost on a Mac, rightmost\n // on Windows. What differs is the other two. A Mac runs close, minimise,\n // zoom left to right; Windows runs minimise, maximise, close — so counting\n // in from its right-hand corner gives close, maximise, minimise. The colour\n // list is always in close/minimise/maximise order, so it is the order that\n // is stated here rather than the list that is rebuilt.\n const order = rightward ? [0, 1, 2] : [0, 2, 1]\n\n for (let i = 0; i < 3; i++) {\n const slot = order[i]\n const x = centreOf(i)\n const colour = m.look.controlColors[slot]\n\n switch (m.look.controlsShape) {\n case \"lights\":\n ctx.draw(\n new Graphics2D()\n .ellipse({ x, y, width: size, height: size })\n .fill(colour)\n )\n break\n\n case \"boxes\":\n // System 7 drew a close box at the left and a zoom box at the right,\n // and nothing in between — so the middle slot is skipped rather than\n // drawn as a third square the OS never had.\n if (i === 1) break\n ctx.draw(\n new Graphics2D()\n .rect({\n x: i === 0 ? x : -centreOf(0),\n y,\n width: size,\n height: height,\n })\n .fill(m.look.titleBarColor)\n .stroke({ weight: m.scale, fill: colour, align: \"inside\" })\n )\n break\n\n case \"chips\":\n ctx.draw(\n new Graphics2D().rect({ x, y, width: size, height }).fill(\"#c0c0c0\")\n )\n this.drawBevel(ctx, m, { x, y, width: size, height }, true)\n this.drawGlyph(ctx, slot, x, y, size * 0.42, \"#000000\", m.scale)\n break\n\n case \"glyphs\":\n this.drawGlyph(ctx, slot, x, y, size, colour, m.scale)\n break\n }\n }\n }\n\n /**\n * A caption glyph: a minus, a square, or a cross.\n *\n * Drawn from strokes rather than typed as text, because these are the same\n * three marks in every chrome that has them and a font would put whatever the\n * renderer happened to shape into a 10px box. `slot` is close / minimise /\n * maximise, matching the colour list's order.\n */\n private drawGlyph(\n ctx: RenderContext2D,\n slot: number,\n x: number,\n y: number,\n size: number,\n colour: string,\n scale: number\n ): void {\n const r = size / 2\n const g = new Graphics2D()\n const weight = Math.max(1, scale)\n /** One stroked rule, drawn on its own — see the cross below for why. */\n const rule = (from: Vector2, to: Vector2) =>\n ctx.draw(\n new Graphics2D()\n .line({ points: [from, to] })\n .stroke({ weight, fill: colour, align: \"center\", cap: \"butt\" })\n )\n\n if (slot === 0) {\n // The cross, as two crossing rules — and each is its own draw.\n //\n // A `Graphics2D` unions every shape declared before a paint call and\n // paints them as one surface, which is right for two rects making an L\n // (see {@link drawBevel}) and wrong for two *lines*: the union of two open\n // strokes is not a shape the stroker can trace, and what came out was\n // nothing at all — a close button that was positioned, coloured and\n // invisible. One draw each is the whole fix; the marks do not need to\n // share a paint, since they are one colour by construction.\n rule({ x: x - r, y: y - r }, { x: x + r, y: y + r })\n rule({ x: x - r, y: y + r }, { x: x + r, y: y - r })\n return\n }\n\n if (slot === 1) {\n // The minimise rule, sitting on the baseline rather than the middle in the\n // chrome that draws it low — but centred reads correctly at every size and\n // is what both modern shells do.\n rule({ x: x - r, y }, { x: x + r, y })\n return\n }\n\n // The maximise square, hollow.\n g.rect({ x, y, width: size, height: size })\n ctx.draw(g.stroke({ weight, fill: colour, align: \"center\", cap: \"butt\" }))\n }\n}\n\n\n\n/** What {@link Window.metrics} hands round — named so the helpers can take it. */\ntype Metrics = {\n width: number\n height: number\n look: WindowLook\n scale: number\n titleBar: number\n radius: number\n border: number\n top: number\n left: number\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@motionscript/ui",
3
- "version": "0.1.0-alpha.0",
3
+ "version": "0.1.0-alpha.3",
4
4
  "type": "module",
5
5
  "description": "Animated interface controls for Motion Script: a switch, a button, a window chrome and a cursor, measured off the real things.",
6
6
  "repository": {
@@ -47,7 +47,7 @@
47
47
  ],
48
48
  "license": "Apache-2.0",
49
49
  "peerDependencies": {
50
- "@motionscript/core": "^0.1.0-alpha.0"
50
+ "@motionscript/sdk": "^0.1.0-alpha.3"
51
51
  },
52
52
  "devDependencies": {
53
53
  "@types/node": "^25.6.2",
@@ -58,7 +58,8 @@
58
58
  "typescript": "^6.0.3",
59
59
  "typescript-eslint": "^8.48.0",
60
60
  "vitest": "^4.1.5",
61
- "@motionscript/core": "0.1.0-alpha.0"
61
+ "@motionscript/core": "0.1.0-alpha.3",
62
+ "@motionscript/sdk": "0.1.0-alpha.3"
62
63
  },
63
64
  "scripts": {
64
65
  "build": "tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json --resolve-full-paths && node ../../../scripts/build-browser.mjs",
@@ -1,7 +1,7 @@
1
1
  import {
2
+ clamp,
2
3
  command,
3
4
  driveCommand,
4
- easeInOut,
5
5
  node,
6
6
  type Command,
7
7
  type CommandArgs,
@@ -10,7 +10,7 @@ import {
10
10
  type Node,
11
11
  type NodeConfig,
12
12
  type RenderContext2D,
13
- } from "@motionscript/core"
13
+ } from "@motionscript/sdk"
14
14
 
15
15
  import {
16
16
  CONTROL_ICONS,
@@ -26,7 +26,7 @@ import {
26
26
  readableInk,
27
27
  type ControlStyle,
28
28
  } from "../kit/control-style"
29
- import { pathOps } from "@motionscript/core"
29
+ import { pathOps } from "@motionscript/sdk"
30
30
  import { pressDepth } from "../kit/press"
31
31
  import { ControlNode, type ControlNodeProps } from "../kit/control-node"
32
32
 
@@ -50,7 +50,7 @@ export interface ButtonProps extends ControlNodeProps {
50
50
  * and a press is two. {@link pressDepth} turns the fractional part into the
51
51
  * down-and-up envelope, which is zero at both whole numbers — so a finished
52
52
  * press leaves the button at rest by arithmetic rather than by a reset the
53
- * builder would have to remember to write. See `nodes/ui-kit/commands.ts`.
53
+ * builder would have to remember to write. See {@link Button.pulse}.
54
54
  */
55
55
  press: number
56
56
  /**
@@ -131,8 +131,10 @@ export class Button extends ControlNode<ButtonProps> {
131
131
  }
132
132
 
133
133
  /**
134
- * Press and release the button — a pulse on `press`, not a state change, so
135
- * a document that only ever presses never leaves the button stuck down.
134
+ * Press and release the button: `press` climbs from the whole number it
135
+ * starts at to the next, and {@link pressDepth} draws that as one press. The
136
+ * phase only climbs, as `Cursor.click` writes it, so the row never undoes
137
+ * the count an earlier press left.
136
138
  *
137
139
  * Named `pulse` and published as `press` to avoid shadowing the `press` prop
138
140
  * this drives. Same split `Code.erase` makes to avoid shadowing `Node.remove`.
@@ -140,12 +142,13 @@ export class Button extends ControlNode<ButtonProps> {
140
142
  @command({ key: "press" })
141
143
  pulse(args: CommandArgs<Record<string, never>> & { duration?: number }): Command<ButtonProps> {
142
144
  const duration = args.duration && args.duration > 0 ? args.duration : this.pressDuration
143
- const easing = args.easing ?? easeInOut()
144
- const DOWN = 0.35
145
- return driveCommand(duration, (t) => {
146
- const phase = t < DOWN ? easing(t / DOWN) : 1 - easing((t - DOWN) / (1 - DOWN))
147
- this.set({ press: phase } as Partial<ButtonProps>)
148
- }) as Command<ButtonProps>
145
+ const base = Math.floor(this.press)
146
+ return driveCommand(
147
+ duration,
148
+ // Clamped so an overshooting easing cannot carry the phase into a second press.
149
+ (phase) => this.set({ press: base + clamp(phase, 0, 1) } as Partial<ButtonProps>),
150
+ args.easing
151
+ ) as Command<ButtonProps>
149
152
  }
150
153
 
151
154
  /** Every measurement the drawing needs, resolved once — see {@link Switch.metrics}. */
@@ -17,7 +17,7 @@ import {
17
17
  type PathCommand,
18
18
  type RenderContext2D,
19
19
  type VectorPath,
20
- } from "@motionscript/core"
20
+ } from "@motionscript/sdk"
21
21
 
22
22
  import {
23
23
  cursorArtworkPixels,
@@ -39,7 +39,7 @@
39
39
  * hairline on a large switch and a blob on a small one.
40
40
  */
41
41
 
42
- import { pathOps, type PathSubpath, type VectorPath, type Vector2 } from "@motionscript/core"
42
+ import { pathOps, type PathSubpath, type VectorPath, type Vector2 } from "@motionscript/sdk"
43
43
 
44
44
  /**
45
45
  * The marks a control can wear, in the order the dropdown offers them.
@@ -27,7 +27,7 @@ import {
27
27
  property,
28
28
  type AudioScope,
29
29
  type Node2DProps,
30
- } from "@motionscript/core"
30
+ } from "@motionscript/sdk"
31
31
 
32
32
  /**
33
33
  * One sound a node's chain fires: a moment, a file, and the window of it played.
@@ -37,7 +37,7 @@
37
37
  * nobody has to re-derive a coordinate to move one into this module.
38
38
  */
39
39
 
40
- import { pathOps, type VectorPath, type Vector2 } from "@motionscript/core"
40
+ import { pathOps, type VectorPath, type Vector2 } from "@motionscript/sdk"
41
41
 
42
42
  /**
43
43
  * The pointers, in the order the dropdown offers them.