@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.
- package/LICENSE +661 -0
- package/README.md +281 -2
- package/package.json +65 -3
- package/src/ConsolePanel.svelte +139 -0
- package/src/ExportMenu.svelte +36 -0
- package/src/ParamField.svelte +390 -0
- package/src/ParamsPanel.svelte +216 -0
- package/src/PreviewPanel.svelte +372 -0
- package/src/ShortcutsDialog.svelte +170 -0
- package/src/Splitter.svelte +148 -0
- package/src/Viewer.svelte +175 -0
- package/src/ViewerPane.svelte +745 -0
- package/src/base64.js +16 -0
- package/src/console.js +78 -0
- package/src/controls.css +183 -0
- package/src/index.js +40 -0
- package/src/measures.js +52 -0
- package/src/params.js +348 -0
- package/src/range.js +19 -0
- package/src/recent.js +44 -0
- package/src/run-status.js +78 -0
- package/src/settings.js +82 -0
- package/src/shortcuts.js +59 -0
- package/src/theme.js +131 -0
- package/src/tokens.css +70 -0
- package/src/values.svelte.js +13 -0
- package/src/view-settings.js +81 -0
- package/src/viewer/appearance.js +90 -0
- package/src/viewer/camera.js +100 -0
- package/src/viewer/dispose.js +30 -0
- package/src/viewer/environment.js +145 -0
- package/src/viewer/faces.js +311 -0
- package/src/viewer/hover-mark.js +125 -0
- package/src/viewer/index.js +7 -0
- package/src/viewer/model.js +293 -0
- package/src/viewer/motion.js +96 -0
- package/src/viewer/section.js +166 -0
- package/src/viewer/testing.js +90 -0
- package/src/viewer/theme.js +32 -0
- package/src/viewer/types.d.ts +136 -0
- package/src/viewer/view-cube.js +314 -0
- package/src/viewer/viewer.js +1027 -0
- package/src/viewer/wheel.js +55 -0
- package/src/viewport-socket.js +64 -0
- 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
|
+
}
|