@kupcad/ui 0.0.0-stage → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +281 -2
  3. package/package.json +65 -3
  4. package/src/ConsolePanel.svelte +139 -0
  5. package/src/ExportMenu.svelte +36 -0
  6. package/src/ParamField.svelte +390 -0
  7. package/src/ParamsPanel.svelte +216 -0
  8. package/src/PreviewPanel.svelte +372 -0
  9. package/src/ShortcutsDialog.svelte +170 -0
  10. package/src/Splitter.svelte +148 -0
  11. package/src/Viewer.svelte +175 -0
  12. package/src/ViewerPane.svelte +745 -0
  13. package/src/base64.js +16 -0
  14. package/src/console.js +78 -0
  15. package/src/controls.css +183 -0
  16. package/src/index.js +40 -0
  17. package/src/measures.js +52 -0
  18. package/src/params.js +348 -0
  19. package/src/range.js +19 -0
  20. package/src/recent.js +44 -0
  21. package/src/run-status.js +78 -0
  22. package/src/settings.js +82 -0
  23. package/src/shortcuts.js +59 -0
  24. package/src/theme.js +131 -0
  25. package/src/tokens.css +70 -0
  26. package/src/values.svelte.js +13 -0
  27. package/src/view-settings.js +81 -0
  28. package/src/viewer/appearance.js +90 -0
  29. package/src/viewer/camera.js +100 -0
  30. package/src/viewer/dispose.js +30 -0
  31. package/src/viewer/environment.js +145 -0
  32. package/src/viewer/faces.js +311 -0
  33. package/src/viewer/hover-mark.js +125 -0
  34. package/src/viewer/index.js +7 -0
  35. package/src/viewer/model.js +293 -0
  36. package/src/viewer/motion.js +96 -0
  37. package/src/viewer/section.js +166 -0
  38. package/src/viewer/testing.js +90 -0
  39. package/src/viewer/theme.js +32 -0
  40. package/src/viewer/types.d.ts +136 -0
  41. package/src/viewer/view-cube.js +314 -0
  42. package/src/viewer/viewer.js +1027 -0
  43. package/src/viewer/wheel.js +55 -0
  44. package/src/viewport-socket.js +64 -0
  45. package/src/vscode.css +49 -0
@@ -0,0 +1,55 @@
1
+ // What a turn of the wheel (or two fingers on a trackpad) does, by the key held, as Orca Slicer
2
+ // has it. Alone it zooms, and so does a pinch, which a browser sends as the wheel with Ctrl.
3
+ // With Shift it pans, as Shift with two fingers does in Orca on a Mac. With Option (Alt) it
4
+ // moves the section, as in Orca. With Cmd it turns the view: Orca has nothing for it there. With
5
+ // the middle button held it does nothing, as in Orca: that button is the wheel, which turns a
6
+ // little as it is pressed. Plain math over the event's numbers: the viewer does what it says.
7
+
8
+ import { ZOOM_STEP } from './camera.js';
9
+
10
+ /** A line of scrolling, in CSS pixels, for a browser that counts in lines. */
11
+ const LINE_PX = 16;
12
+ /**
13
+ * How much a pixel of scrolling zooms, as the log of the factor: three.js's OrbitControls',
14
+ * which zoomed with the wheel before.
15
+ */
16
+ const SCROLL_ZOOM_RATE = -Math.log(0.95) / 100;
17
+ /** A pinch comes in small steps: each pixel of it zooms ten times as much, as in OrbitControls. */
18
+ const PINCH_ZOOM_RATE = SCROLL_ZOOM_RATE * 10;
19
+ /** The most one turn zooms by, as the log of the factor: a key's step. */
20
+ const MOST_ZOOM = Math.log(ZOOM_STEP);
21
+ /** The middle button, in a mouse event's `buttons`. */
22
+ const MIDDLE_BUTTON = 4;
23
+
24
+ /**
25
+ * What a turn of the wheel does: zooms in by `factor` (out, below 1); pans or turns the view by
26
+ * `x` and `y` CSS pixels, as far as a page's content would scroll; or moves the section by `y`
27
+ * pixels, down as it grows.
28
+ * @typedef {{ kind: 'zoom', factor: number }
29
+ * | { kind: 'pan' | 'orbit', x: number, y: number }
30
+ * | { kind: 'section', y: number }} WheelGesture
31
+ */
32
+
33
+ /**
34
+ * What `event` does, or nothing (null).
35
+ * @param {Pick<WheelEvent, 'deltaX' | 'deltaY' | 'deltaMode' | 'buttons' | 'shiftKey' | 'metaKey' | 'altKey' | 'ctrlKey'>} event
36
+ * @param {number} pagePx how far a page of scrolling is, in CSS pixels: the canvas's height
37
+ * @returns {WheelGesture | null}
38
+ */
39
+ export function wheelGesture(event, pagePx) {
40
+ if (event.buttons & MIDDLE_BUTTON) return null;
41
+ const unit =
42
+ event.deltaMode === WheelEvent.DOM_DELTA_LINE
43
+ ? LINE_PX
44
+ : event.deltaMode === WheelEvent.DOM_DELTA_PAGE
45
+ ? pagePx
46
+ : 1;
47
+ const x = event.deltaX * unit;
48
+ const y = event.deltaY * unit;
49
+ if (event.shiftKey) return x || y ? { kind: 'pan', x, y } : null;
50
+ if (event.metaKey) return x || y ? { kind: 'orbit', x, y } : null;
51
+ if (event.altKey) return y ? { kind: 'section', y } : null;
52
+ if (!y) return null;
53
+ const rate = event.ctrlKey ? PINCH_ZOOM_RATE : SCROLL_ZOOM_RATE;
54
+ return { kind: 'zoom', factor: Math.exp(Math.min(MOST_ZOOM, Math.max(-MOST_ZOOM, -y * rate))) };
55
+ }
@@ -0,0 +1,64 @@
1
+ // The language server's viewport socket, as the page reads it: each binary message a preview
2
+ // frame (@kupcad/protocol's readFrame). A socket that closes (the server restarted, or wasn't
3
+ // up yet) is opened again, a little later each time.
4
+
5
+ import { errorText, readFrame } from '@kupcad/protocol';
6
+
7
+ /** @import { Preview } from '@kupcad/protocol/types' */
8
+
9
+ /** The first wait before opening a closed socket again, and the longest, in milliseconds. */
10
+ export const RETRY_MS = { first: 250, most: 5000 };
11
+
12
+ /**
13
+ * @typedef {object} ViewportEvents
14
+ * @property {(preview: Preview) => void} frame a frame arrived
15
+ * @property {() => void} open the socket opened: the host asks the server for a frame
16
+ * @property {(open: boolean) => void} state it opened or closed
17
+ * @property {(message: string) => void} problem a frame this page can't read
18
+ */
19
+
20
+ /**
21
+ * Connects to the socket at `url`, until the returned function is called.
22
+ * @param {string} url
23
+ * @param {ViewportEvents} on
24
+ * @param {{ WebSocket?: typeof WebSocket, setTimeout?: typeof setTimeout }} [platform]
25
+ * @returns {() => void} closes it for good
26
+ */
27
+ export function connectViewport(url, on, platform = {}) {
28
+ const Socket = platform.WebSocket ?? globalThis.WebSocket;
29
+ const later = platform.setTimeout ?? globalThis.setTimeout;
30
+ let wait = RETRY_MS.first;
31
+ let closed = false;
32
+ /** @type {WebSocket | null} */
33
+ let socket = null;
34
+
35
+ const open = () => {
36
+ if (closed) return;
37
+ socket = new Socket(url);
38
+ socket.binaryType = 'arraybuffer';
39
+ socket.addEventListener('open', () => {
40
+ wait = RETRY_MS.first;
41
+ on.state(true);
42
+ on.open();
43
+ });
44
+ socket.addEventListener('message', ({ data }) => {
45
+ if (!(data instanceof ArrayBuffer)) return;
46
+ try {
47
+ on.frame(readFrame(data));
48
+ } catch (error) {
49
+ on.problem(errorText(error));
50
+ }
51
+ });
52
+ socket.addEventListener('close', () => {
53
+ on.state(false);
54
+ if (closed) return;
55
+ later(open, wait);
56
+ wait = Math.min(wait * 2, RETRY_MS.most);
57
+ });
58
+ };
59
+ open();
60
+ return () => {
61
+ closed = true;
62
+ socket?.close();
63
+ };
64
+ }
package/src/vscode.css ADDED
@@ -0,0 +1,49 @@
1
+ /*
2
+ The --kc-* tokens as VS Code's theme sets its own, for the extension's webview: the panels and
3
+ the viewer follow the editor's theme, not KupCAD's brand, which would fight the editor around
4
+ them. The defaults underneath give what VS Code has no token for (the radius, the gap). The
5
+ accent is a button's colours, a pair VS Code keeps legible; orange as text becomes a link's
6
+ colour, a focus ring VS Code's own.
7
+ */
8
+ @import './tokens.css';
9
+
10
+ :root {
11
+ --kc-font: var(--vscode-font-family);
12
+ --kc-font-size: var(--vscode-font-size);
13
+ --kc-bg: var(--vscode-sideBar-background, var(--vscode-editor-background));
14
+ --kc-fg: var(--vscode-foreground);
15
+ --kc-muted: var(--vscode-descriptionForeground);
16
+ --kc-border: var(--vscode-panel-border, var(--vscode-widget-border));
17
+ --kc-control-border: var(
18
+ --vscode-input-border,
19
+ var(--vscode-checkbox-border, var(--vscode-widget-border))
20
+ );
21
+ --kc-input-bg: var(--vscode-input-background);
22
+ --kc-hover: var(--vscode-list-hoverBackground);
23
+ --kc-accent: var(--vscode-button-background);
24
+ --kc-accent-fg: var(--vscode-button-foreground);
25
+ --kc-accent-hover: var(--vscode-button-hoverBackground, var(--vscode-button-background));
26
+ --kc-accent-text: var(--vscode-textLink-foreground);
27
+ --kc-accent-subtle: var(--vscode-list-inactiveSelectionBackground);
28
+ --kc-focus: var(--vscode-focusBorder);
29
+ --kc-track: var(--vscode-scrollbarSlider-background, var(--vscode-panel-border));
30
+ --kc-error: var(--vscode-errorForeground);
31
+ --kc-warning: var(--vscode-editorWarning-foreground);
32
+ --kc-section-bg: var(
33
+ --vscode-sideBarSectionHeader-background,
34
+ var(--vscode-editorWidget-background)
35
+ );
36
+ --kc-section-fg: var(--vscode-sideBarSectionHeader-foreground, var(--vscode-foreground));
37
+
38
+ --kc-viewer-background: var(--vscode-editor-background);
39
+ --kc-viewer-grid: var(--vscode-editorIndentGuide-background1, var(--vscode-panel-border));
40
+ --kc-viewer-plate: var(--vscode-editorWidget-background);
41
+ --kc-viewer-edges: var(--vscode-editorLineNumber-foreground);
42
+ /* Lines on the background (a wireframe, a drawing): the text's colour, which every theme sets apart from it */
43
+ --kc-viewer-wire: var(--vscode-editor-foreground);
44
+ --kc-viewer-selection: var(--vscode-focusBorder);
45
+ --kc-viewer-cap: var(--vscode-editorError-foreground);
46
+ --kc-viewer-ghost: var(--vscode-editorInfo-foreground);
47
+ /* A colour of its own, as no other token's: a chart's, which every theme sets */
48
+ --kc-viewer-highlight: var(--vscode-charts-purple);
49
+ }