@geometra/client 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,26 @@
1
+ import type { ComputedLayout } from 'textura';
2
+ import type { Renderer, UIElement } from '@geometra/core';
3
+ export interface TexturaClientOptions {
4
+ /** WebSocket URL to connect to. Default: 'ws://localhost:3100'. */
5
+ url?: string;
6
+ /** The renderer to paint with. */
7
+ renderer: Renderer;
8
+ /** Optional canvas element for forwarding pointer events. */
9
+ canvas?: HTMLCanvasElement;
10
+ }
11
+ export interface TexturaClient {
12
+ /** Current layout (if received). */
13
+ layout: ComputedLayout | null;
14
+ /** Current tree (if received). */
15
+ tree: UIElement | null;
16
+ /** Disconnect from server. */
17
+ close(): void;
18
+ }
19
+ /**
20
+ * Connect to a Textura server and render received geometry.
21
+ *
22
+ * The client is a thin paint layer — all layout computation happens server-side.
23
+ * Pointer events on the canvas are forwarded to the server for hit-testing.
24
+ */
25
+ export declare function createClient(options: TexturaClientOptions): TexturaClient;
26
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAC7C,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAqBzD,MAAM,WAAW,oBAAoB;IACnC,mEAAmE;IACnE,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,kCAAkC;IAClC,QAAQ,EAAE,QAAQ,CAAA;IAClB,6DAA6D;IAC7D,MAAM,CAAC,EAAE,iBAAiB,CAAA;CAC3B;AAED,MAAM,WAAW,aAAa;IAC5B,oCAAoC;IACpC,MAAM,EAAE,cAAc,GAAG,IAAI,CAAA;IAC7B,kCAAkC;IAClC,IAAI,EAAE,SAAS,GAAG,IAAI,CAAA;IACtB,8BAA8B;IAC9B,KAAK,IAAI,IAAI,CAAA;CACd;AAqBD;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,oBAAoB,GAAG,aAAa,CAoEzE"}
package/dist/client.js ADDED
@@ -0,0 +1,82 @@
1
+ /** Apply patches to a computed layout tree (mutates in place). */
2
+ function applyPatches(layout, patches) {
3
+ for (const patch of patches) {
4
+ let node = layout;
5
+ for (const idx of patch.path) {
6
+ const child = node.children[idx];
7
+ if (!child)
8
+ break;
9
+ node = child;
10
+ }
11
+ if (patch.x !== undefined)
12
+ node.x = patch.x;
13
+ if (patch.y !== undefined)
14
+ node.y = patch.y;
15
+ if (patch.width !== undefined)
16
+ node.width = patch.width;
17
+ if (patch.height !== undefined)
18
+ node.height = patch.height;
19
+ }
20
+ }
21
+ /**
22
+ * Connect to a Textura server and render received geometry.
23
+ *
24
+ * The client is a thin paint layer — all layout computation happens server-side.
25
+ * Pointer events on the canvas are forwarded to the server for hit-testing.
26
+ */
27
+ export function createClient(options) {
28
+ const url = options.url ?? 'ws://localhost:3100';
29
+ const { renderer, canvas } = options;
30
+ const state = {
31
+ layout: null,
32
+ tree: null,
33
+ close() {
34
+ ws.close();
35
+ cleanup();
36
+ },
37
+ };
38
+ const ws = new WebSocket(url);
39
+ ws.addEventListener('message', (event) => {
40
+ const msg = JSON.parse(String(event.data));
41
+ if (msg.type === 'frame') {
42
+ state.layout = msg.layout;
43
+ state.tree = msg.tree;
44
+ renderer.render(msg.layout, msg.tree);
45
+ }
46
+ else if (msg.type === 'patch' && state.layout && state.tree) {
47
+ applyPatches(state.layout, msg.patches);
48
+ renderer.render(state.layout, state.tree);
49
+ }
50
+ });
51
+ // Forward pointer events to server
52
+ const sendEvent = (eventType, e) => {
53
+ if (ws.readyState !== WebSocket.OPEN)
54
+ return;
55
+ const rect = canvas?.getBoundingClientRect();
56
+ const x = rect ? e.clientX - rect.left : e.clientX;
57
+ const y = rect ? e.clientY - rect.top : e.clientY;
58
+ ws.send(JSON.stringify({ type: 'event', eventType, x, y }));
59
+ };
60
+ const handlers = [];
61
+ if (canvas) {
62
+ const onClick = (e) => sendEvent('onClick', e);
63
+ const onPointerDown = (e) => sendEvent('onPointerDown', e);
64
+ const onPointerUp = (e) => sendEvent('onPointerUp', e);
65
+ const onPointerMove = (e) => sendEvent('onPointerMove', e);
66
+ canvas.addEventListener('click', onClick);
67
+ canvas.addEventListener('pointerdown', onPointerDown);
68
+ canvas.addEventListener('pointerup', onPointerUp);
69
+ canvas.addEventListener('pointermove', onPointerMove);
70
+ handlers.push(['click', onClick], ['pointerdown', onPointerDown], ['pointerup', onPointerUp], ['pointermove', onPointerMove]);
71
+ }
72
+ function cleanup() {
73
+ if (canvas) {
74
+ for (const [event, handler] of handlers) {
75
+ canvas.removeEventListener(event, handler);
76
+ }
77
+ }
78
+ renderer.destroy();
79
+ }
80
+ return state;
81
+ }
82
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export { createClient } from './client.js';
2
+ export type { TexturaClient, TexturaClientOptions } from './client.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,YAAY,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export { createClient } from './client.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA"}
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@geometra/client",
3
+ "version": "0.1.0",
4
+ "description": "Thin client that receives server-computed geometry and paints via renderer",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/razroo/textrura-framework",
10
+ "directory": "packages/client"
11
+ },
12
+ "homepage": "https://razroo.github.io/textrura-framework",
13
+ "keywords": [
14
+ "textura",
15
+ "client",
16
+ "websocket",
17
+ "thin-client",
18
+ "dom-free"
19
+ ],
20
+ "main": "./dist/index.js",
21
+ "types": "./dist/index.d.ts",
22
+ "exports": {
23
+ ".": {
24
+ "types": "./dist/index.d.ts",
25
+ "import": "./dist/index.js"
26
+ }
27
+ },
28
+ "files": [
29
+ "dist"
30
+ ],
31
+ "scripts": {
32
+ "build": "rm -rf dist && tsc -p tsconfig.build.json",
33
+ "check": "tsc --noEmit"
34
+ },
35
+ "dependencies": {
36
+ "@geometra/core": "^0.1.0"
37
+ }
38
+ }