@woven-canvas/plugin-tapes 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/commands/tape.ts","../src/components/index.ts","../src/components/Tape.ts","../src/constants.ts","../src/singletons/index.ts","../src/singletons/TapeDrawState.ts","../src/types.ts","../src/TapesPlugin.ts","../src/systems/index.ts","../src/systems/captureTapeDrawSystem.ts","../src/systems/updateTapeDrawSystem.ts"],"sourcesContent":["export * from './commands'\nexport * from './components'\nexport * from './constants'\nexport * from './singletons'\nexport { createTapesPlugin, TapesPlugin } from './TapesPlugin'\nexport * from './types'\n","import { defineCommand, type EntityId } from '@woven-canvas/core'\nimport type { Vec2 } from '@woven-canvas/math'\n\n/**\n * Add a new tape block at the given world position.\n */\nexport const AddTape = defineCommand<{\n entityId: EntityId\n position: Vec2\n}>('tape-add')\n\n/**\n * Update tape geometry during drawing.\n * Stretches tape from start to end position.\n */\nexport const DrawTape = defineCommand<{\n entityId: EntityId\n start: Vec2\n end: Vec2\n}>('tape-draw')\n\n/**\n * Remove a tape entity (on cancel).\n */\nexport const RemoveTape = defineCommand<{\n entityId: EntityId\n}>('tape-remove')\n\n/**\n * Complete drawing a tape.\n * Finalizes the tape and selects it.\n */\nexport const CompleteTape = defineCommand<{\n entityId: EntityId\n}>('tape-complete')\n\n/**\n * Place a default-sized tape at the given position (on simple click).\n */\nexport const PlaceTape = defineCommand<{\n entityId: EntityId\n position: Vec2\n}>('tape-place')\n","export { Tape } from './Tape'\n","import { defineCanvasComponent, field } from '@woven-canvas/core'\n\n/**\n * Tape component - stores tape-specific metadata for washi tape blocks.\n *\n * Tape is a ribbon-like element positioned by its two endpoints.\n * The block's width represents the tape length and height represents thickness.\n * Rotation is derived from the angle between endpoints.\n *\n * The tape image is stored via the Image and Asset components (same as image blocks).\n * For default tapes, the Asset identifier is set to the known URL directly —\n * AssetManager will return it as-is without going through the upload pipeline.\n * The image tiles horizontally along the tape length.\n */\nexport const Tape = defineCanvasComponent(\n { name: 'tape', sync: 'document' },\n {\n /** Tape thickness in world units (the height of the tape ribbon) */\n thickness: field.float64().default(30),\n },\n)\n","/** Plugin name identifier */\nexport const TAPES_PLUGIN_NAME = 'tapes'\n\n/** Default tape thickness in world units */\nexport const DEFAULT_TAPE_THICKNESS = 30\n\n/** Default tape length in world units (for click-to-place) */\nexport const DEFAULT_TAPE_LENGTH = 200\n\n/** Minimum distance (in screen pixels) before transitioning from Pointing to Drawing */\nexport const POINTING_THRESHOLD = 4\n\n/** Default tape image URL */\nexport const DEFAULT_TAPE_IMAGE =\n 'https://storage.googleapis.com/download/storage/v1/b/zine-maker-public/o/tapes%2F7e3b7dde-927d-4b09-aeb4-d49eac36d4ea.png?generation=1715183194653465&alt=media'\n","export { TapeDrawState } from './TapeDrawState'\n","import { defineEditorState, field } from '@woven-canvas/core'\nimport { TapeDrawStateEnum } from '../types'\n\n/**\n * Tape draw state singleton - stores the current state of the tape draw state machine.\n *\n * Tracks the drawing tool state and active tape entity while drawing new tape.\n */\nexport const TapeDrawState = defineEditorState('tapeDrawState', {\n /** Current state machine state */\n state: field.string().max(16).default(TapeDrawStateEnum.Idle),\n\n /** Reference to the active tape entity (while drawing) */\n activeTape: field.ref(),\n\n /** Pointing start position in client coordinates [x, y] */\n pointingStartClient: field.tuple(field.int32(), 2).default([0, 0]),\n\n /** Pointing start position in world coordinates [x, y] */\n pointingStartWorld: field.tuple(field.float64(), 2).default([0, 0]),\n})\n","/**\n * State values for the tape draw state machine.\n */\nexport const TapeDrawStateEnum = {\n /** Idle - waiting for user to start drawing */\n Idle: 'idle',\n /** Pointing - pointer down, waiting for drag threshold */\n Pointing: 'pointing',\n /** Drawing - tape created, stretching with pointer */\n Drawing: 'drawing',\n} as const\n\nexport type TapeDrawStateValue = (typeof TapeDrawStateEnum)[keyof typeof TapeDrawStateEnum]\n","import {\n Asset,\n CanvasComponentDef,\n CanvasSingletonDef,\n type EditorPlugin,\n type EditorPluginFactory,\n type EditorSystem,\n Image,\n ResizeMode,\n} from '@woven-canvas/core'\n\nimport * as components from './components'\nimport { TAPES_PLUGIN_NAME } from './constants'\nimport * as singletons from './singletons'\nimport * as systems from './systems'\n\n// Helper to filter EditorSystem instances from a namespace\nconst filterSystems = (ns: object): EditorSystem[] =>\n Object.values(ns).filter(\n (v): v is EditorSystem => typeof v === 'object' && v !== null && '_system' in v && 'phase' in v,\n )\n\n/**\n * Create a Tapes plugin.\n *\n * @returns Configured EditorPlugin\n */\nexport function createTapesPlugin(): EditorPlugin {\n return {\n name: TAPES_PLUGIN_NAME,\n\n dependencies: ['selection'],\n\n components: Object.values(components).filter((v) => v instanceof CanvasComponentDef),\n\n singletons: Object.values(singletons).filter((v) => v instanceof CanvasSingletonDef),\n\n blockDefs: [\n {\n tag: 'tape',\n components: [components.Tape, Image, Asset],\n resizeMode: ResizeMode.Scale,\n connectors: {\n enabled: false,\n },\n },\n ],\n\n systems: filterSystems(systems),\n }\n}\n\n/**\n * Tapes Plugin\n *\n * Provides washi tape drawing functionality for infinite canvas:\n * - Click and drag to draw tape across the canvas\n * - Tape stretches from start to end point with rotation\n * - Uses tiling tape texture images via Asset system\n * - RotateScale handles for repositioning tape endpoints\n *\n * @example\n * ```typescript\n * import { Editor } from '@woven-canvas/core';\n * import { TapesPlugin } from '@woven-canvas/plugin-tapes';\n *\n * const editor = new Editor(el, {\n * plugins: [TapesPlugin],\n * });\n * ```\n */\nexport const TapesPlugin: EditorPluginFactory = () => createTapesPlugin()\n","export { captureTapeDrawSystem } from './captureTapeDrawSystem'\nexport { updateTapeDrawSystem } from './updateTapeDrawSystem'\n","import {\n Controls,\n Cursor,\n createEntity,\n defineEditorSystem,\n type EntityId,\n getPointerInput,\n type InferStateContext,\n type PointerInput,\n} from '@woven-canvas/core'\nimport { Vec2 } from '@woven-canvas/math'\nimport { DeselectAll } from '@woven-canvas/plugin-selection'\nimport { assign, setup } from 'xstate'\nimport { AddTape, CompleteTape, DrawTape, PlaceTape, RemoveTape } from '../commands'\nimport { POINTING_THRESHOLD } from '../constants'\nimport { TapeDrawState } from '../singletons'\nimport { TapeDrawStateEnum } from '../types'\n\n/**\n * Tape draw state machine context - derived from TapeDrawState schema.\n */\ntype TapeDrawContext = InferStateContext<typeof TapeDrawState>\n\n/**\n * Tape draw state machine - handles pointer events for drawing new tape.\n *\n * Flow:\n * - Idle → pointerDown → Pointing (record start position)\n * - Pointing → pointerMove (past threshold) → Drawing (create tape entity)\n * - Drawing → pointerMove → update tape geometry\n * - Drawing → pointerUp → Idle (complete tape)\n * - Any → cancel → Idle (remove tape if exists)\n */\nconst tapeDrawMachine = setup({\n types: {\n context: {} as TapeDrawContext,\n events: {} as PointerInput,\n },\n guards: {\n isThresholdReached: ({ context, event }) => {\n const dist = Vec2.distance(context.pointingStartClient as [number, number], event.screenPosition)\n return dist >= POINTING_THRESHOLD\n },\n },\n actions: {\n setPointingStart: assign({\n pointingStartClient: ({ event }): [number, number] => [event.screenPosition[0], event.screenPosition[1]],\n pointingStartWorld: ({ event }): [number, number] => [event.worldPosition[0], event.worldPosition[1]],\n }),\n\n resetContext: assign({\n pointingStartClient: (): [number, number] => [0, 0],\n pointingStartWorld: (): [number, number] => [0, 0],\n activeTape: () => null,\n }),\n\n addTape: assign({\n activeTape: ({ context, event }): EntityId => {\n const startWorld = context.pointingStartWorld as [number, number]\n const entityId = createEntity(event.ctx)\n AddTape.spawn(event.ctx, {\n entityId,\n position: startWorld,\n })\n return entityId\n },\n }),\n\n drawTape: ({ context, event }) => {\n if (!context.activeTape) return\n const startWorld = context.pointingStartWorld as [number, number]\n DrawTape.spawn(event.ctx, {\n entityId: context.activeTape,\n start: startWorld,\n end: event.worldPosition,\n })\n },\n\n completeTape: ({ context, event }) => {\n if (!context.activeTape) return\n CompleteTape.spawn(event.ctx, { entityId: context.activeTape })\n },\n\n removeTape: assign({\n activeTape: ({ context, event }): EntityId | null => {\n if (!context.activeTape) return null\n RemoveTape.spawn(event.ctx, { entityId: context.activeTape })\n return null\n },\n }),\n\n placeTape: ({ context, event }) => {\n const startWorld = context.pointingStartWorld as [number, number]\n const entityId = createEntity(event.ctx)\n PlaceTape.spawn(event.ctx, {\n entityId,\n position: startWorld,\n })\n },\n\n exitTapeControl: ({ event }) => {\n const controls = Controls.write(event.ctx)\n controls.leftMouseTool = 'select'\n\n const cursor = Cursor.write(event.ctx)\n cursor.cursorKind = 'select'\n },\n\n deselectAll: ({ event }) => {\n DeselectAll.spawn(event.ctx)\n },\n },\n}).createMachine({\n id: 'tapeDraw',\n initial: TapeDrawStateEnum.Idle,\n context: {\n activeTape: null,\n pointingStartClient: [0, 0] as [number, number],\n pointingStartWorld: [0, 0] as [number, number],\n },\n states: {\n [TapeDrawStateEnum.Idle]: {\n entry: 'resetContext',\n on: {\n pointerDown: [\n {\n actions: 'deselectAll',\n target: TapeDrawStateEnum.Pointing,\n },\n ],\n },\n },\n [TapeDrawStateEnum.Pointing]: {\n entry: 'setPointingStart',\n on: {\n pointerMove: {\n guard: 'isThresholdReached',\n target: TapeDrawStateEnum.Drawing,\n },\n pointerUp: {\n actions: ['placeTape', 'exitTapeControl'],\n target: TapeDrawStateEnum.Idle,\n },\n cancel: {\n target: TapeDrawStateEnum.Idle,\n },\n },\n },\n [TapeDrawStateEnum.Drawing]: {\n entry: 'addTape',\n exit: 'exitTapeControl',\n on: {\n pointerMove: {\n actions: 'drawTape',\n },\n pointerUp: {\n actions: 'completeTape',\n target: TapeDrawStateEnum.Idle,\n },\n cancel: {\n actions: 'removeTape',\n target: TapeDrawStateEnum.Idle,\n },\n },\n },\n },\n})\n\n/**\n * Capture tape draw system - runs the tape draw state machine.\n *\n * Runs in the capture phase to handle pointer events for the tape draw tool.\n * Generates commands that are processed by the update system.\n */\nexport const captureTapeDrawSystem = defineEditorSystem({ phase: 'capture', priority: 100 }, (ctx) => {\n // Get pointer buttons mapped to tape tool\n const buttons = Controls.getButtons(ctx, 'tape')\n\n // Skip if tape tool is not active\n if (buttons.length === 0) return\n\n // Get pointer events\n const events = getPointerInput(ctx, buttons)\n\n if (events.length === 0) return\n\n TapeDrawState.run(ctx, tapeDrawMachine, events)\n})\n","import {\n Asset,\n addComponent,\n Block,\n type Context,\n defineEditorSystem,\n type EntityId,\n Grid,\n Image,\n on,\n RankBounds,\n removeEntity,\n Synced,\n UploadState,\n} from '@woven-canvas/core'\nimport type { Vec2 } from '@woven-canvas/math'\nimport { selectBlock } from '@woven-canvas/plugin-selection'\nimport { AddTape, CompleteTape, DrawTape, PlaceTape, RemoveTape } from '../commands'\nimport { Tape } from '../components'\nimport { DEFAULT_TAPE_IMAGE, DEFAULT_TAPE_LENGTH, DEFAULT_TAPE_THICKNESS } from '../constants'\n\n/**\n * Update tape draw system - handles tape commands.\n *\n * Processes:\n * - AddTape: Create new tape entity at start position\n * - DrawTape: Update tape geometry as user drags\n * - RemoveTape: Delete tape entity\n * - CompleteTape: Finalize and select tape\n */\nexport const updateTapeDrawSystem = defineEditorSystem({ phase: 'update' }, (ctx: Context) => {\n on(ctx, AddTape, (ctx, { entityId, position }) => {\n addTape(ctx, entityId, position)\n })\n\n on(ctx, DrawTape, (ctx, { entityId, start, end }) => {\n drawTape(ctx, entityId, start, end)\n })\n\n on(ctx, RemoveTape, (ctx, { entityId }) => {\n removeEntity(ctx, entityId)\n })\n\n on(ctx, CompleteTape, (ctx, { entityId }) => {\n completeTape(ctx, entityId)\n })\n\n on(ctx, PlaceTape, (ctx, { entityId, position }) => {\n placeTape(ctx, entityId, position)\n })\n})\n\n/**\n * Create a new tape entity at the given position.\n */\nfunction addTape(ctx: Context, entityId: EntityId, position: Vec2): void {\n // Snap start position to grid\n const snappedPos: Vec2 = [position[0], position[1]]\n Grid.snapPosition(ctx, snappedPos)\n\n // Create block with minimal initial size (will be updated by drawTape)\n addComponent(ctx, entityId, Block, {\n tag: 'tape',\n rank: RankBounds.genNext(ctx),\n position: [snappedPos[0], snappedPos[1] - DEFAULT_TAPE_THICKNESS / 2],\n size: [1, DEFAULT_TAPE_THICKNESS],\n })\n\n addComponent(ctx, entityId, Synced, {\n id: crypto.randomUUID(),\n })\n\n addComponent(ctx, entityId, Tape)\n\n addComponent(ctx, entityId, Image, {})\n\n addComponent(ctx, entityId, Asset, {\n identifier: DEFAULT_TAPE_IMAGE,\n uploadState: UploadState.Complete,\n })\n}\n\n/**\n * Update tape geometry based on start and end positions.\n *\n * The tape stretches from the start point to the current cursor position.\n * Position is the midpoint, width is the distance, height is the thickness,\n * and rotation is derived from the angle between the two points.\n */\nfunction drawTape(ctx: Context, entityId: EntityId, start: Vec2, end: Vec2): void {\n // Snap both endpoints to grid\n const s: Vec2 = [start[0], start[1]]\n const e: Vec2 = [end[0], end[1]]\n Grid.snapPosition(ctx, s)\n Grid.snapPosition(ctx, e)\n\n const dx = e[0] - s[0]\n const dy = e[1] - s[1]\n const length = Math.sqrt(dx * dx + dy * dy)\n const angle = Math.atan2(dy, dx)\n\n // Midpoint between start and end\n const midX = (s[0] + e[0]) / 2\n const midY = (s[1] + e[1]) / 2\n\n const block = Block.write(ctx, entityId)\n const tape = Tape.read(ctx, entityId)\n const thickness = tape.thickness\n\n // Position is top-left corner of the unrotated bounding box centered on midpoint\n block.position = [midX - length / 2, midY - thickness / 2]\n block.size = [Math.max(length, 1), thickness]\n block.rotateZ = angle\n}\n\n/**\n * Place a default-sized tape at the given position (simple click).\n */\nfunction placeTape(ctx: Context, entityId: EntityId, position: Vec2): void {\n const snappedPos: Vec2 = [position[0], position[1]]\n Grid.snapPosition(ctx, snappedPos)\n\n addComponent(ctx, entityId, Block, {\n tag: 'tape',\n rank: RankBounds.genNext(ctx),\n position: [snappedPos[0] - DEFAULT_TAPE_LENGTH / 2, snappedPos[1] - DEFAULT_TAPE_THICKNESS / 2],\n size: [DEFAULT_TAPE_LENGTH, DEFAULT_TAPE_THICKNESS],\n })\n\n addComponent(ctx, entityId, Synced, {\n id: crypto.randomUUID(),\n })\n\n addComponent(ctx, entityId, Tape)\n\n addComponent(ctx, entityId, Image, {})\n\n addComponent(ctx, entityId, Asset, {\n identifier: DEFAULT_TAPE_IMAGE,\n uploadState: UploadState.Complete,\n })\n\n selectBlock(ctx, entityId)\n}\n\n/**\n * Complete tape drawing - select it.\n */\nfunction completeTape(ctx: Context, entityId: EntityId): void {\n // Check the tape has meaningful size\n const block = Block.read(ctx, entityId)\n if (block.size[0] <= 1) {\n // Too small - remove it\n removeEntity(ctx, entityId)\n return\n }\n\n selectBlock(ctx, entityId)\n}\n"],"mappings":"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","names":["import_core","import_core","import_core","import_core","import_core","import_plugin_selection","ctx"]}
@@ -0,0 +1,16 @@
1
+ export { createTapesPlugin_alias_1 as createTapesPlugin } from './_tsup-dts-rollup.cjs';
2
+ export { TapesPlugin_alias_1 as TapesPlugin } from './_tsup-dts-rollup.cjs';
3
+ export { AddTape } from './_tsup-dts-rollup.cjs';
4
+ export { CompleteTape } from './_tsup-dts-rollup.cjs';
5
+ export { DrawTape } from './_tsup-dts-rollup.cjs';
6
+ export { PlaceTape } from './_tsup-dts-rollup.cjs';
7
+ export { RemoveTape } from './_tsup-dts-rollup.cjs';
8
+ export { Tape } from './_tsup-dts-rollup.cjs';
9
+ export { TAPES_PLUGIN_NAME_alias_1 as TAPES_PLUGIN_NAME } from './_tsup-dts-rollup.cjs';
10
+ export { DEFAULT_TAPE_THICKNESS_alias_1 as DEFAULT_TAPE_THICKNESS } from './_tsup-dts-rollup.cjs';
11
+ export { DEFAULT_TAPE_LENGTH_alias_1 as DEFAULT_TAPE_LENGTH } from './_tsup-dts-rollup.cjs';
12
+ export { POINTING_THRESHOLD_alias_1 as POINTING_THRESHOLD } from './_tsup-dts-rollup.cjs';
13
+ export { DEFAULT_TAPE_IMAGE_alias_1 as DEFAULT_TAPE_IMAGE } from './_tsup-dts-rollup.cjs';
14
+ export { TapeDrawState } from './_tsup-dts-rollup.cjs';
15
+ export { TapeDrawStateEnum } from './_tsup-dts-rollup.cjs';
16
+ export { TapeDrawStateValue } from './_tsup-dts-rollup.cjs';
@@ -0,0 +1,16 @@
1
+ export { createTapesPlugin_alias_1 as createTapesPlugin } from './_tsup-dts-rollup.js';
2
+ export { TapesPlugin_alias_1 as TapesPlugin } from './_tsup-dts-rollup.js';
3
+ export { AddTape } from './_tsup-dts-rollup.js';
4
+ export { CompleteTape } from './_tsup-dts-rollup.js';
5
+ export { DrawTape } from './_tsup-dts-rollup.js';
6
+ export { PlaceTape } from './_tsup-dts-rollup.js';
7
+ export { RemoveTape } from './_tsup-dts-rollup.js';
8
+ export { Tape } from './_tsup-dts-rollup.js';
9
+ export { TAPES_PLUGIN_NAME_alias_1 as TAPES_PLUGIN_NAME } from './_tsup-dts-rollup.js';
10
+ export { DEFAULT_TAPE_THICKNESS_alias_1 as DEFAULT_TAPE_THICKNESS } from './_tsup-dts-rollup.js';
11
+ export { DEFAULT_TAPE_LENGTH_alias_1 as DEFAULT_TAPE_LENGTH } from './_tsup-dts-rollup.js';
12
+ export { POINTING_THRESHOLD_alias_1 as POINTING_THRESHOLD } from './_tsup-dts-rollup.js';
13
+ export { DEFAULT_TAPE_IMAGE_alias_1 as DEFAULT_TAPE_IMAGE } from './_tsup-dts-rollup.js';
14
+ export { TapeDrawState } from './_tsup-dts-rollup.js';
15
+ export { TapeDrawStateEnum } from './_tsup-dts-rollup.js';
16
+ export { TapeDrawStateValue } from './_tsup-dts-rollup.js';
package/build/index.js ADDED
@@ -0,0 +1,368 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __export = (target, all) => {
3
+ for (var name in all)
4
+ __defProp(target, name, { get: all[name], enumerable: true });
5
+ };
6
+
7
+ // src/commands/tape.ts
8
+ import { defineCommand } from "@woven-canvas/core";
9
+ var AddTape = defineCommand("tape-add");
10
+ var DrawTape = defineCommand("tape-draw");
11
+ var RemoveTape = defineCommand("tape-remove");
12
+ var CompleteTape = defineCommand("tape-complete");
13
+ var PlaceTape = defineCommand("tape-place");
14
+
15
+ // src/components/index.ts
16
+ var components_exports = {};
17
+ __export(components_exports, {
18
+ Tape: () => Tape
19
+ });
20
+
21
+ // src/components/Tape.ts
22
+ import { defineCanvasComponent, field } from "@woven-canvas/core";
23
+ var Tape = defineCanvasComponent(
24
+ { name: "tape", sync: "document" },
25
+ {
26
+ /** Tape thickness in world units (the height of the tape ribbon) */
27
+ thickness: field.float64().default(30)
28
+ }
29
+ );
30
+
31
+ // src/constants.ts
32
+ var TAPES_PLUGIN_NAME = "tapes";
33
+ var DEFAULT_TAPE_THICKNESS = 30;
34
+ var DEFAULT_TAPE_LENGTH = 200;
35
+ var POINTING_THRESHOLD = 4;
36
+ var DEFAULT_TAPE_IMAGE = "https://storage.googleapis.com/download/storage/v1/b/zine-maker-public/o/tapes%2F7e3b7dde-927d-4b09-aeb4-d49eac36d4ea.png?generation=1715183194653465&alt=media";
37
+
38
+ // src/singletons/index.ts
39
+ var singletons_exports = {};
40
+ __export(singletons_exports, {
41
+ TapeDrawState: () => TapeDrawState
42
+ });
43
+
44
+ // src/singletons/TapeDrawState.ts
45
+ import { defineEditorState, field as field2 } from "@woven-canvas/core";
46
+
47
+ // src/types.ts
48
+ var TapeDrawStateEnum = {
49
+ /** Idle - waiting for user to start drawing */
50
+ Idle: "idle",
51
+ /** Pointing - pointer down, waiting for drag threshold */
52
+ Pointing: "pointing",
53
+ /** Drawing - tape created, stretching with pointer */
54
+ Drawing: "drawing"
55
+ };
56
+
57
+ // src/singletons/TapeDrawState.ts
58
+ var TapeDrawState = defineEditorState("tapeDrawState", {
59
+ /** Current state machine state */
60
+ state: field2.string().max(16).default(TapeDrawStateEnum.Idle),
61
+ /** Reference to the active tape entity (while drawing) */
62
+ activeTape: field2.ref(),
63
+ /** Pointing start position in client coordinates [x, y] */
64
+ pointingStartClient: field2.tuple(field2.int32(), 2).default([0, 0]),
65
+ /** Pointing start position in world coordinates [x, y] */
66
+ pointingStartWorld: field2.tuple(field2.float64(), 2).default([0, 0])
67
+ });
68
+
69
+ // src/TapesPlugin.ts
70
+ import {
71
+ Asset as Asset2,
72
+ CanvasComponentDef,
73
+ CanvasSingletonDef,
74
+ Image as Image2,
75
+ ResizeMode
76
+ } from "@woven-canvas/core";
77
+
78
+ // src/systems/index.ts
79
+ var systems_exports = {};
80
+ __export(systems_exports, {
81
+ captureTapeDrawSystem: () => captureTapeDrawSystem,
82
+ updateTapeDrawSystem: () => updateTapeDrawSystem
83
+ });
84
+
85
+ // src/systems/captureTapeDrawSystem.ts
86
+ import {
87
+ Controls,
88
+ Cursor,
89
+ createEntity,
90
+ defineEditorSystem,
91
+ getPointerInput
92
+ } from "@woven-canvas/core";
93
+ import { Vec2 } from "@woven-canvas/math";
94
+ import { DeselectAll } from "@woven-canvas/plugin-selection";
95
+ import { assign, setup } from "xstate";
96
+ var tapeDrawMachine = setup({
97
+ types: {
98
+ context: {},
99
+ events: {}
100
+ },
101
+ guards: {
102
+ isThresholdReached: ({ context, event }) => {
103
+ const dist = Vec2.distance(context.pointingStartClient, event.screenPosition);
104
+ return dist >= POINTING_THRESHOLD;
105
+ }
106
+ },
107
+ actions: {
108
+ setPointingStart: assign({
109
+ pointingStartClient: ({ event }) => [event.screenPosition[0], event.screenPosition[1]],
110
+ pointingStartWorld: ({ event }) => [event.worldPosition[0], event.worldPosition[1]]
111
+ }),
112
+ resetContext: assign({
113
+ pointingStartClient: () => [0, 0],
114
+ pointingStartWorld: () => [0, 0],
115
+ activeTape: () => null
116
+ }),
117
+ addTape: assign({
118
+ activeTape: ({ context, event }) => {
119
+ const startWorld = context.pointingStartWorld;
120
+ const entityId = createEntity(event.ctx);
121
+ AddTape.spawn(event.ctx, {
122
+ entityId,
123
+ position: startWorld
124
+ });
125
+ return entityId;
126
+ }
127
+ }),
128
+ drawTape: ({ context, event }) => {
129
+ if (!context.activeTape) return;
130
+ const startWorld = context.pointingStartWorld;
131
+ DrawTape.spawn(event.ctx, {
132
+ entityId: context.activeTape,
133
+ start: startWorld,
134
+ end: event.worldPosition
135
+ });
136
+ },
137
+ completeTape: ({ context, event }) => {
138
+ if (!context.activeTape) return;
139
+ CompleteTape.spawn(event.ctx, { entityId: context.activeTape });
140
+ },
141
+ removeTape: assign({
142
+ activeTape: ({ context, event }) => {
143
+ if (!context.activeTape) return null;
144
+ RemoveTape.spawn(event.ctx, { entityId: context.activeTape });
145
+ return null;
146
+ }
147
+ }),
148
+ placeTape: ({ context, event }) => {
149
+ const startWorld = context.pointingStartWorld;
150
+ const entityId = createEntity(event.ctx);
151
+ PlaceTape.spawn(event.ctx, {
152
+ entityId,
153
+ position: startWorld
154
+ });
155
+ },
156
+ exitTapeControl: ({ event }) => {
157
+ const controls = Controls.write(event.ctx);
158
+ controls.leftMouseTool = "select";
159
+ const cursor = Cursor.write(event.ctx);
160
+ cursor.cursorKind = "select";
161
+ },
162
+ deselectAll: ({ event }) => {
163
+ DeselectAll.spawn(event.ctx);
164
+ }
165
+ }
166
+ }).createMachine({
167
+ id: "tapeDraw",
168
+ initial: TapeDrawStateEnum.Idle,
169
+ context: {
170
+ activeTape: null,
171
+ pointingStartClient: [0, 0],
172
+ pointingStartWorld: [0, 0]
173
+ },
174
+ states: {
175
+ [TapeDrawStateEnum.Idle]: {
176
+ entry: "resetContext",
177
+ on: {
178
+ pointerDown: [
179
+ {
180
+ actions: "deselectAll",
181
+ target: TapeDrawStateEnum.Pointing
182
+ }
183
+ ]
184
+ }
185
+ },
186
+ [TapeDrawStateEnum.Pointing]: {
187
+ entry: "setPointingStart",
188
+ on: {
189
+ pointerMove: {
190
+ guard: "isThresholdReached",
191
+ target: TapeDrawStateEnum.Drawing
192
+ },
193
+ pointerUp: {
194
+ actions: ["placeTape", "exitTapeControl"],
195
+ target: TapeDrawStateEnum.Idle
196
+ },
197
+ cancel: {
198
+ target: TapeDrawStateEnum.Idle
199
+ }
200
+ }
201
+ },
202
+ [TapeDrawStateEnum.Drawing]: {
203
+ entry: "addTape",
204
+ exit: "exitTapeControl",
205
+ on: {
206
+ pointerMove: {
207
+ actions: "drawTape"
208
+ },
209
+ pointerUp: {
210
+ actions: "completeTape",
211
+ target: TapeDrawStateEnum.Idle
212
+ },
213
+ cancel: {
214
+ actions: "removeTape",
215
+ target: TapeDrawStateEnum.Idle
216
+ }
217
+ }
218
+ }
219
+ }
220
+ });
221
+ var captureTapeDrawSystem = defineEditorSystem({ phase: "capture", priority: 100 }, (ctx) => {
222
+ const buttons = Controls.getButtons(ctx, "tape");
223
+ if (buttons.length === 0) return;
224
+ const events = getPointerInput(ctx, buttons);
225
+ if (events.length === 0) return;
226
+ TapeDrawState.run(ctx, tapeDrawMachine, events);
227
+ });
228
+
229
+ // src/systems/updateTapeDrawSystem.ts
230
+ import {
231
+ Asset,
232
+ addComponent,
233
+ Block,
234
+ defineEditorSystem as defineEditorSystem2,
235
+ Grid,
236
+ Image,
237
+ on,
238
+ RankBounds,
239
+ removeEntity,
240
+ Synced,
241
+ UploadState
242
+ } from "@woven-canvas/core";
243
+ import { selectBlock } from "@woven-canvas/plugin-selection";
244
+ var updateTapeDrawSystem = defineEditorSystem2({ phase: "update" }, (ctx) => {
245
+ on(ctx, AddTape, (ctx2, { entityId, position }) => {
246
+ addTape(ctx2, entityId, position);
247
+ });
248
+ on(ctx, DrawTape, (ctx2, { entityId, start, end }) => {
249
+ drawTape(ctx2, entityId, start, end);
250
+ });
251
+ on(ctx, RemoveTape, (ctx2, { entityId }) => {
252
+ removeEntity(ctx2, entityId);
253
+ });
254
+ on(ctx, CompleteTape, (ctx2, { entityId }) => {
255
+ completeTape(ctx2, entityId);
256
+ });
257
+ on(ctx, PlaceTape, (ctx2, { entityId, position }) => {
258
+ placeTape(ctx2, entityId, position);
259
+ });
260
+ });
261
+ function addTape(ctx, entityId, position) {
262
+ const snappedPos = [position[0], position[1]];
263
+ Grid.snapPosition(ctx, snappedPos);
264
+ addComponent(ctx, entityId, Block, {
265
+ tag: "tape",
266
+ rank: RankBounds.genNext(ctx),
267
+ position: [snappedPos[0], snappedPos[1] - DEFAULT_TAPE_THICKNESS / 2],
268
+ size: [1, DEFAULT_TAPE_THICKNESS]
269
+ });
270
+ addComponent(ctx, entityId, Synced, {
271
+ id: crypto.randomUUID()
272
+ });
273
+ addComponent(ctx, entityId, Tape);
274
+ addComponent(ctx, entityId, Image, {});
275
+ addComponent(ctx, entityId, Asset, {
276
+ identifier: DEFAULT_TAPE_IMAGE,
277
+ uploadState: UploadState.Complete
278
+ });
279
+ }
280
+ function drawTape(ctx, entityId, start, end) {
281
+ const s = [start[0], start[1]];
282
+ const e = [end[0], end[1]];
283
+ Grid.snapPosition(ctx, s);
284
+ Grid.snapPosition(ctx, e);
285
+ const dx = e[0] - s[0];
286
+ const dy = e[1] - s[1];
287
+ const length = Math.sqrt(dx * dx + dy * dy);
288
+ const angle = Math.atan2(dy, dx);
289
+ const midX = (s[0] + e[0]) / 2;
290
+ const midY = (s[1] + e[1]) / 2;
291
+ const block = Block.write(ctx, entityId);
292
+ const tape = Tape.read(ctx, entityId);
293
+ const thickness = tape.thickness;
294
+ block.position = [midX - length / 2, midY - thickness / 2];
295
+ block.size = [Math.max(length, 1), thickness];
296
+ block.rotateZ = angle;
297
+ }
298
+ function placeTape(ctx, entityId, position) {
299
+ const snappedPos = [position[0], position[1]];
300
+ Grid.snapPosition(ctx, snappedPos);
301
+ addComponent(ctx, entityId, Block, {
302
+ tag: "tape",
303
+ rank: RankBounds.genNext(ctx),
304
+ position: [snappedPos[0] - DEFAULT_TAPE_LENGTH / 2, snappedPos[1] - DEFAULT_TAPE_THICKNESS / 2],
305
+ size: [DEFAULT_TAPE_LENGTH, DEFAULT_TAPE_THICKNESS]
306
+ });
307
+ addComponent(ctx, entityId, Synced, {
308
+ id: crypto.randomUUID()
309
+ });
310
+ addComponent(ctx, entityId, Tape);
311
+ addComponent(ctx, entityId, Image, {});
312
+ addComponent(ctx, entityId, Asset, {
313
+ identifier: DEFAULT_TAPE_IMAGE,
314
+ uploadState: UploadState.Complete
315
+ });
316
+ selectBlock(ctx, entityId);
317
+ }
318
+ function completeTape(ctx, entityId) {
319
+ const block = Block.read(ctx, entityId);
320
+ if (block.size[0] <= 1) {
321
+ removeEntity(ctx, entityId);
322
+ return;
323
+ }
324
+ selectBlock(ctx, entityId);
325
+ }
326
+
327
+ // src/TapesPlugin.ts
328
+ var filterSystems = (ns) => Object.values(ns).filter(
329
+ (v) => typeof v === "object" && v !== null && "_system" in v && "phase" in v
330
+ );
331
+ function createTapesPlugin() {
332
+ return {
333
+ name: TAPES_PLUGIN_NAME,
334
+ dependencies: ["selection"],
335
+ components: Object.values(components_exports).filter((v) => v instanceof CanvasComponentDef),
336
+ singletons: Object.values(singletons_exports).filter((v) => v instanceof CanvasSingletonDef),
337
+ blockDefs: [
338
+ {
339
+ tag: "tape",
340
+ components: [Tape, Image2, Asset2],
341
+ resizeMode: ResizeMode.Scale,
342
+ connectors: {
343
+ enabled: false
344
+ }
345
+ }
346
+ ],
347
+ systems: filterSystems(systems_exports)
348
+ };
349
+ }
350
+ var TapesPlugin = () => createTapesPlugin();
351
+ export {
352
+ AddTape,
353
+ CompleteTape,
354
+ DEFAULT_TAPE_IMAGE,
355
+ DEFAULT_TAPE_LENGTH,
356
+ DEFAULT_TAPE_THICKNESS,
357
+ DrawTape,
358
+ POINTING_THRESHOLD,
359
+ PlaceTape,
360
+ RemoveTape,
361
+ TAPES_PLUGIN_NAME,
362
+ Tape,
363
+ TapeDrawState,
364
+ TapeDrawStateEnum,
365
+ TapesPlugin,
366
+ createTapesPlugin
367
+ };
368
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/tape.ts","../src/components/index.ts","../src/components/Tape.ts","../src/constants.ts","../src/singletons/index.ts","../src/singletons/TapeDrawState.ts","../src/types.ts","../src/TapesPlugin.ts","../src/systems/index.ts","../src/systems/captureTapeDrawSystem.ts","../src/systems/updateTapeDrawSystem.ts"],"sourcesContent":["import { defineCommand, type EntityId } from '@woven-canvas/core'\nimport type { Vec2 } from '@woven-canvas/math'\n\n/**\n * Add a new tape block at the given world position.\n */\nexport const AddTape = defineCommand<{\n entityId: EntityId\n position: Vec2\n}>('tape-add')\n\n/**\n * Update tape geometry during drawing.\n * Stretches tape from start to end position.\n */\nexport const DrawTape = defineCommand<{\n entityId: EntityId\n start: Vec2\n end: Vec2\n}>('tape-draw')\n\n/**\n * Remove a tape entity (on cancel).\n */\nexport const RemoveTape = defineCommand<{\n entityId: EntityId\n}>('tape-remove')\n\n/**\n * Complete drawing a tape.\n * Finalizes the tape and selects it.\n */\nexport const CompleteTape = defineCommand<{\n entityId: EntityId\n}>('tape-complete')\n\n/**\n * Place a default-sized tape at the given position (on simple click).\n */\nexport const PlaceTape = defineCommand<{\n entityId: EntityId\n position: Vec2\n}>('tape-place')\n","export { Tape } from './Tape'\n","import { defineCanvasComponent, field } from '@woven-canvas/core'\n\n/**\n * Tape component - stores tape-specific metadata for washi tape blocks.\n *\n * Tape is a ribbon-like element positioned by its two endpoints.\n * The block's width represents the tape length and height represents thickness.\n * Rotation is derived from the angle between endpoints.\n *\n * The tape image is stored via the Image and Asset components (same as image blocks).\n * For default tapes, the Asset identifier is set to the known URL directly —\n * AssetManager will return it as-is without going through the upload pipeline.\n * The image tiles horizontally along the tape length.\n */\nexport const Tape = defineCanvasComponent(\n { name: 'tape', sync: 'document' },\n {\n /** Tape thickness in world units (the height of the tape ribbon) */\n thickness: field.float64().default(30),\n },\n)\n","/** Plugin name identifier */\nexport const TAPES_PLUGIN_NAME = 'tapes'\n\n/** Default tape thickness in world units */\nexport const DEFAULT_TAPE_THICKNESS = 30\n\n/** Default tape length in world units (for click-to-place) */\nexport const DEFAULT_TAPE_LENGTH = 200\n\n/** Minimum distance (in screen pixels) before transitioning from Pointing to Drawing */\nexport const POINTING_THRESHOLD = 4\n\n/** Default tape image URL */\nexport const DEFAULT_TAPE_IMAGE =\n 'https://storage.googleapis.com/download/storage/v1/b/zine-maker-public/o/tapes%2F7e3b7dde-927d-4b09-aeb4-d49eac36d4ea.png?generation=1715183194653465&alt=media'\n","export { TapeDrawState } from './TapeDrawState'\n","import { defineEditorState, field } from '@woven-canvas/core'\nimport { TapeDrawStateEnum } from '../types'\n\n/**\n * Tape draw state singleton - stores the current state of the tape draw state machine.\n *\n * Tracks the drawing tool state and active tape entity while drawing new tape.\n */\nexport const TapeDrawState = defineEditorState('tapeDrawState', {\n /** Current state machine state */\n state: field.string().max(16).default(TapeDrawStateEnum.Idle),\n\n /** Reference to the active tape entity (while drawing) */\n activeTape: field.ref(),\n\n /** Pointing start position in client coordinates [x, y] */\n pointingStartClient: field.tuple(field.int32(), 2).default([0, 0]),\n\n /** Pointing start position in world coordinates [x, y] */\n pointingStartWorld: field.tuple(field.float64(), 2).default([0, 0]),\n})\n","/**\n * State values for the tape draw state machine.\n */\nexport const TapeDrawStateEnum = {\n /** Idle - waiting for user to start drawing */\n Idle: 'idle',\n /** Pointing - pointer down, waiting for drag threshold */\n Pointing: 'pointing',\n /** Drawing - tape created, stretching with pointer */\n Drawing: 'drawing',\n} as const\n\nexport type TapeDrawStateValue = (typeof TapeDrawStateEnum)[keyof typeof TapeDrawStateEnum]\n","import {\n Asset,\n CanvasComponentDef,\n CanvasSingletonDef,\n type EditorPlugin,\n type EditorPluginFactory,\n type EditorSystem,\n Image,\n ResizeMode,\n} from '@woven-canvas/core'\n\nimport * as components from './components'\nimport { TAPES_PLUGIN_NAME } from './constants'\nimport * as singletons from './singletons'\nimport * as systems from './systems'\n\n// Helper to filter EditorSystem instances from a namespace\nconst filterSystems = (ns: object): EditorSystem[] =>\n Object.values(ns).filter(\n (v): v is EditorSystem => typeof v === 'object' && v !== null && '_system' in v && 'phase' in v,\n )\n\n/**\n * Create a Tapes plugin.\n *\n * @returns Configured EditorPlugin\n */\nexport function createTapesPlugin(): EditorPlugin {\n return {\n name: TAPES_PLUGIN_NAME,\n\n dependencies: ['selection'],\n\n components: Object.values(components).filter((v) => v instanceof CanvasComponentDef),\n\n singletons: Object.values(singletons).filter((v) => v instanceof CanvasSingletonDef),\n\n blockDefs: [\n {\n tag: 'tape',\n components: [components.Tape, Image, Asset],\n resizeMode: ResizeMode.Scale,\n connectors: {\n enabled: false,\n },\n },\n ],\n\n systems: filterSystems(systems),\n }\n}\n\n/**\n * Tapes Plugin\n *\n * Provides washi tape drawing functionality for infinite canvas:\n * - Click and drag to draw tape across the canvas\n * - Tape stretches from start to end point with rotation\n * - Uses tiling tape texture images via Asset system\n * - RotateScale handles for repositioning tape endpoints\n *\n * @example\n * ```typescript\n * import { Editor } from '@woven-canvas/core';\n * import { TapesPlugin } from '@woven-canvas/plugin-tapes';\n *\n * const editor = new Editor(el, {\n * plugins: [TapesPlugin],\n * });\n * ```\n */\nexport const TapesPlugin: EditorPluginFactory = () => createTapesPlugin()\n","export { captureTapeDrawSystem } from './captureTapeDrawSystem'\nexport { updateTapeDrawSystem } from './updateTapeDrawSystem'\n","import {\n Controls,\n Cursor,\n createEntity,\n defineEditorSystem,\n type EntityId,\n getPointerInput,\n type InferStateContext,\n type PointerInput,\n} from '@woven-canvas/core'\nimport { Vec2 } from '@woven-canvas/math'\nimport { DeselectAll } from '@woven-canvas/plugin-selection'\nimport { assign, setup } from 'xstate'\nimport { AddTape, CompleteTape, DrawTape, PlaceTape, RemoveTape } from '../commands'\nimport { POINTING_THRESHOLD } from '../constants'\nimport { TapeDrawState } from '../singletons'\nimport { TapeDrawStateEnum } from '../types'\n\n/**\n * Tape draw state machine context - derived from TapeDrawState schema.\n */\ntype TapeDrawContext = InferStateContext<typeof TapeDrawState>\n\n/**\n * Tape draw state machine - handles pointer events for drawing new tape.\n *\n * Flow:\n * - Idle → pointerDown → Pointing (record start position)\n * - Pointing → pointerMove (past threshold) → Drawing (create tape entity)\n * - Drawing → pointerMove → update tape geometry\n * - Drawing → pointerUp → Idle (complete tape)\n * - Any → cancel → Idle (remove tape if exists)\n */\nconst tapeDrawMachine = setup({\n types: {\n context: {} as TapeDrawContext,\n events: {} as PointerInput,\n },\n guards: {\n isThresholdReached: ({ context, event }) => {\n const dist = Vec2.distance(context.pointingStartClient as [number, number], event.screenPosition)\n return dist >= POINTING_THRESHOLD\n },\n },\n actions: {\n setPointingStart: assign({\n pointingStartClient: ({ event }): [number, number] => [event.screenPosition[0], event.screenPosition[1]],\n pointingStartWorld: ({ event }): [number, number] => [event.worldPosition[0], event.worldPosition[1]],\n }),\n\n resetContext: assign({\n pointingStartClient: (): [number, number] => [0, 0],\n pointingStartWorld: (): [number, number] => [0, 0],\n activeTape: () => null,\n }),\n\n addTape: assign({\n activeTape: ({ context, event }): EntityId => {\n const startWorld = context.pointingStartWorld as [number, number]\n const entityId = createEntity(event.ctx)\n AddTape.spawn(event.ctx, {\n entityId,\n position: startWorld,\n })\n return entityId\n },\n }),\n\n drawTape: ({ context, event }) => {\n if (!context.activeTape) return\n const startWorld = context.pointingStartWorld as [number, number]\n DrawTape.spawn(event.ctx, {\n entityId: context.activeTape,\n start: startWorld,\n end: event.worldPosition,\n })\n },\n\n completeTape: ({ context, event }) => {\n if (!context.activeTape) return\n CompleteTape.spawn(event.ctx, { entityId: context.activeTape })\n },\n\n removeTape: assign({\n activeTape: ({ context, event }): EntityId | null => {\n if (!context.activeTape) return null\n RemoveTape.spawn(event.ctx, { entityId: context.activeTape })\n return null\n },\n }),\n\n placeTape: ({ context, event }) => {\n const startWorld = context.pointingStartWorld as [number, number]\n const entityId = createEntity(event.ctx)\n PlaceTape.spawn(event.ctx, {\n entityId,\n position: startWorld,\n })\n },\n\n exitTapeControl: ({ event }) => {\n const controls = Controls.write(event.ctx)\n controls.leftMouseTool = 'select'\n\n const cursor = Cursor.write(event.ctx)\n cursor.cursorKind = 'select'\n },\n\n deselectAll: ({ event }) => {\n DeselectAll.spawn(event.ctx)\n },\n },\n}).createMachine({\n id: 'tapeDraw',\n initial: TapeDrawStateEnum.Idle,\n context: {\n activeTape: null,\n pointingStartClient: [0, 0] as [number, number],\n pointingStartWorld: [0, 0] as [number, number],\n },\n states: {\n [TapeDrawStateEnum.Idle]: {\n entry: 'resetContext',\n on: {\n pointerDown: [\n {\n actions: 'deselectAll',\n target: TapeDrawStateEnum.Pointing,\n },\n ],\n },\n },\n [TapeDrawStateEnum.Pointing]: {\n entry: 'setPointingStart',\n on: {\n pointerMove: {\n guard: 'isThresholdReached',\n target: TapeDrawStateEnum.Drawing,\n },\n pointerUp: {\n actions: ['placeTape', 'exitTapeControl'],\n target: TapeDrawStateEnum.Idle,\n },\n cancel: {\n target: TapeDrawStateEnum.Idle,\n },\n },\n },\n [TapeDrawStateEnum.Drawing]: {\n entry: 'addTape',\n exit: 'exitTapeControl',\n on: {\n pointerMove: {\n actions: 'drawTape',\n },\n pointerUp: {\n actions: 'completeTape',\n target: TapeDrawStateEnum.Idle,\n },\n cancel: {\n actions: 'removeTape',\n target: TapeDrawStateEnum.Idle,\n },\n },\n },\n },\n})\n\n/**\n * Capture tape draw system - runs the tape draw state machine.\n *\n * Runs in the capture phase to handle pointer events for the tape draw tool.\n * Generates commands that are processed by the update system.\n */\nexport const captureTapeDrawSystem = defineEditorSystem({ phase: 'capture', priority: 100 }, (ctx) => {\n // Get pointer buttons mapped to tape tool\n const buttons = Controls.getButtons(ctx, 'tape')\n\n // Skip if tape tool is not active\n if (buttons.length === 0) return\n\n // Get pointer events\n const events = getPointerInput(ctx, buttons)\n\n if (events.length === 0) return\n\n TapeDrawState.run(ctx, tapeDrawMachine, events)\n})\n","import {\n Asset,\n addComponent,\n Block,\n type Context,\n defineEditorSystem,\n type EntityId,\n Grid,\n Image,\n on,\n RankBounds,\n removeEntity,\n Synced,\n UploadState,\n} from '@woven-canvas/core'\nimport type { Vec2 } from '@woven-canvas/math'\nimport { selectBlock } from '@woven-canvas/plugin-selection'\nimport { AddTape, CompleteTape, DrawTape, PlaceTape, RemoveTape } from '../commands'\nimport { Tape } from '../components'\nimport { DEFAULT_TAPE_IMAGE, DEFAULT_TAPE_LENGTH, DEFAULT_TAPE_THICKNESS } from '../constants'\n\n/**\n * Update tape draw system - handles tape commands.\n *\n * Processes:\n * - AddTape: Create new tape entity at start position\n * - DrawTape: Update tape geometry as user drags\n * - RemoveTape: Delete tape entity\n * - CompleteTape: Finalize and select tape\n */\nexport const updateTapeDrawSystem = defineEditorSystem({ phase: 'update' }, (ctx: Context) => {\n on(ctx, AddTape, (ctx, { entityId, position }) => {\n addTape(ctx, entityId, position)\n })\n\n on(ctx, DrawTape, (ctx, { entityId, start, end }) => {\n drawTape(ctx, entityId, start, end)\n })\n\n on(ctx, RemoveTape, (ctx, { entityId }) => {\n removeEntity(ctx, entityId)\n })\n\n on(ctx, CompleteTape, (ctx, { entityId }) => {\n completeTape(ctx, entityId)\n })\n\n on(ctx, PlaceTape, (ctx, { entityId, position }) => {\n placeTape(ctx, entityId, position)\n })\n})\n\n/**\n * Create a new tape entity at the given position.\n */\nfunction addTape(ctx: Context, entityId: EntityId, position: Vec2): void {\n // Snap start position to grid\n const snappedPos: Vec2 = [position[0], position[1]]\n Grid.snapPosition(ctx, snappedPos)\n\n // Create block with minimal initial size (will be updated by drawTape)\n addComponent(ctx, entityId, Block, {\n tag: 'tape',\n rank: RankBounds.genNext(ctx),\n position: [snappedPos[0], snappedPos[1] - DEFAULT_TAPE_THICKNESS / 2],\n size: [1, DEFAULT_TAPE_THICKNESS],\n })\n\n addComponent(ctx, entityId, Synced, {\n id: crypto.randomUUID(),\n })\n\n addComponent(ctx, entityId, Tape)\n\n addComponent(ctx, entityId, Image, {})\n\n addComponent(ctx, entityId, Asset, {\n identifier: DEFAULT_TAPE_IMAGE,\n uploadState: UploadState.Complete,\n })\n}\n\n/**\n * Update tape geometry based on start and end positions.\n *\n * The tape stretches from the start point to the current cursor position.\n * Position is the midpoint, width is the distance, height is the thickness,\n * and rotation is derived from the angle between the two points.\n */\nfunction drawTape(ctx: Context, entityId: EntityId, start: Vec2, end: Vec2): void {\n // Snap both endpoints to grid\n const s: Vec2 = [start[0], start[1]]\n const e: Vec2 = [end[0], end[1]]\n Grid.snapPosition(ctx, s)\n Grid.snapPosition(ctx, e)\n\n const dx = e[0] - s[0]\n const dy = e[1] - s[1]\n const length = Math.sqrt(dx * dx + dy * dy)\n const angle = Math.atan2(dy, dx)\n\n // Midpoint between start and end\n const midX = (s[0] + e[0]) / 2\n const midY = (s[1] + e[1]) / 2\n\n const block = Block.write(ctx, entityId)\n const tape = Tape.read(ctx, entityId)\n const thickness = tape.thickness\n\n // Position is top-left corner of the unrotated bounding box centered on midpoint\n block.position = [midX - length / 2, midY - thickness / 2]\n block.size = [Math.max(length, 1), thickness]\n block.rotateZ = angle\n}\n\n/**\n * Place a default-sized tape at the given position (simple click).\n */\nfunction placeTape(ctx: Context, entityId: EntityId, position: Vec2): void {\n const snappedPos: Vec2 = [position[0], position[1]]\n Grid.snapPosition(ctx, snappedPos)\n\n addComponent(ctx, entityId, Block, {\n tag: 'tape',\n rank: RankBounds.genNext(ctx),\n position: [snappedPos[0] - DEFAULT_TAPE_LENGTH / 2, snappedPos[1] - DEFAULT_TAPE_THICKNESS / 2],\n size: [DEFAULT_TAPE_LENGTH, DEFAULT_TAPE_THICKNESS],\n })\n\n addComponent(ctx, entityId, Synced, {\n id: crypto.randomUUID(),\n })\n\n addComponent(ctx, entityId, Tape)\n\n addComponent(ctx, entityId, Image, {})\n\n addComponent(ctx, entityId, Asset, {\n identifier: DEFAULT_TAPE_IMAGE,\n uploadState: UploadState.Complete,\n })\n\n selectBlock(ctx, entityId)\n}\n\n/**\n * Complete tape drawing - select it.\n */\nfunction completeTape(ctx: Context, entityId: EntityId): void {\n // Check the tape has meaningful size\n const block = Block.read(ctx, entityId)\n if (block.size[0] <= 1) {\n // Too small - remove it\n removeEntity(ctx, entityId)\n return\n }\n\n selectBlock(ctx, entityId)\n}\n"],"mappings":"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","names":["field","field","Asset","Image","defineEditorSystem","defineEditorSystem","ctx","Image","Asset"]}