@deltarobotics/uhd-viewer 0.0.0-stage → 0.2.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 (101) hide show
  1. package/CHANGELOG.md +74 -0
  2. package/LICENSE +202 -0
  3. package/NOTICE +22 -0
  4. package/README.md +168 -2
  5. package/bin/serve.d.mts +62 -0
  6. package/bin/serve.mjs +257 -0
  7. package/bin/uhd-viewer.mjs +75 -0
  8. package/dist/app/assets/KodeMono-Bold-DdIivhPN.woff2 +0 -0
  9. package/dist/app/assets/KodeMono-Medium-CVnTuv5A.ttf +0 -0
  10. package/dist/app/assets/KodeMono-Regular-Bdr_-rJX.woff2 +0 -0
  11. package/dist/app/assets/KodeMono-SemiBold-JAfn5Dpm.ttf +0 -0
  12. package/dist/app/assets/index-CEJyT8hF.css +2 -0
  13. package/dist/app/assets/index-DWZ-48wc.js +3853 -0
  14. package/dist/app/index.html +16 -0
  15. package/dist/components/components.css +6372 -0
  16. package/dist/components/index.d.ts +1 -0
  17. package/dist/components/index.js +26609 -0
  18. package/dist/components/index.js.map +1 -0
  19. package/dist/components/types/uhd-viewer/src/api.d.ts +286 -0
  20. package/dist/components/types/uhd-viewer/src/cad/CadView.d.ts +52 -0
  21. package/dist/components/types/uhd-viewer/src/cad/ModelView.d.ts +30 -0
  22. package/dist/components/types/uhd-viewer/src/cad/explode.d.ts +110 -0
  23. package/dist/components/types/uhd-viewer/src/cad/explodeSample.d.ts +25 -0
  24. package/dist/components/types/uhd-viewer/src/cad/findings.d.ts +41 -0
  25. package/dist/components/types/uhd-viewer/src/cad/labels.d.ts +76 -0
  26. package/dist/components/types/uhd-viewer/src/cad/model.d.ts +132 -0
  27. package/dist/components/types/uhd-viewer/src/cad/row.d.ts +15 -0
  28. package/dist/components/types/uhd-viewer/src/cad/scene.d.ts +95 -0
  29. package/dist/components/types/uhd-viewer/src/cad/scope.d.ts +89 -0
  30. package/dist/components/types/uhd-viewer/src/canvas/Canvas.d.ts +90 -0
  31. package/dist/components/types/uhd-viewer/src/canvas/Icon.d.ts +5 -0
  32. package/dist/components/types/uhd-viewer/src/canvas/LinkEdge.d.ts +40 -0
  33. package/dist/components/types/uhd-viewer/src/canvas/Port.d.ts +18 -0
  34. package/dist/components/types/uhd-viewer/src/canvas/actions.d.ts +5 -0
  35. package/dist/components/types/uhd-viewer/src/canvas/geometry.d.ts +72 -0
  36. package/dist/components/types/uhd-viewer/src/canvas/interaction.d.ts +162 -0
  37. package/dist/components/types/uhd-viewer/src/canvas/nodes.d.ts +43 -0
  38. package/dist/components/types/uhd-viewer/src/canvas/reveal.d.ts +55 -0
  39. package/dist/components/types/uhd-viewer/src/canvas/rightDrag.d.ts +51 -0
  40. package/dist/components/types/uhd-viewer/src/canvas/routing.d.ts +28 -0
  41. package/dist/components/types/uhd-viewer/src/chrome/ArtifactCards.d.ts +30 -0
  42. package/dist/components/types/uhd-viewer/src/chrome/Artifacts.d.ts +44 -0
  43. package/dist/components/types/uhd-viewer/src/chrome/BoardInspector.d.ts +53 -0
  44. package/dist/components/types/uhd-viewer/src/chrome/Chrome.d.ts +126 -0
  45. package/dist/components/types/uhd-viewer/src/chrome/Evidence.d.ts +20 -0
  46. package/dist/components/types/uhd-viewer/src/chrome/InterfaceCards.d.ts +66 -0
  47. package/dist/components/types/uhd-viewer/src/chrome/PairView.d.ts +37 -0
  48. package/dist/components/types/uhd-viewer/src/chrome/Sections.d.ts +128 -0
  49. package/dist/components/types/uhd-viewer/src/components.d.ts +60 -0
  50. package/dist/components/types/uhd-viewer/src/host/channel.d.ts +49 -0
  51. package/dist/components/types/uhd-viewer/src/host/context.d.ts +29 -0
  52. package/dist/components/types/uhd-viewer/src/host/protocol.d.ts +22 -0
  53. package/dist/components/types/uhd-viewer/src/host/targets.d.ts +101 -0
  54. package/dist/components/types/uhd-viewer/src/layout/board-layout.d.ts +69 -0
  55. package/dist/components/types/uhd-viewer/src/layout/card-body.d.ts +64 -0
  56. package/dist/components/types/uhd-viewer/src/layout/layout.d.ts +94 -0
  57. package/dist/components/types/uhd-viewer/src/layout/module-layout.d.ts +32 -0
  58. package/dist/components/types/uhd-viewer/src/layout/router.d.ts +55 -0
  59. package/dist/components/types/uhd-viewer/src/layout/taps.d.ts +20 -0
  60. package/dist/components/types/uhd-viewer/src/model/artifacts.d.ts +129 -0
  61. package/dist/components/types/uhd-viewer/src/model/classification.d.ts +41 -0
  62. package/dist/components/types/uhd-viewer/src/model/diagnostics.d.ts +27 -0
  63. package/dist/components/types/uhd-viewer/src/model/evidence.d.ts +63 -0
  64. package/dist/components/types/uhd-viewer/src/model/from-uhd.d.ts +58 -0
  65. package/dist/components/types/uhd-viewer/src/model/hierarchy.d.ts +173 -0
  66. package/dist/components/types/uhd-viewer/src/model/isolate.d.ts +33 -0
  67. package/dist/components/types/uhd-viewer/src/model/level.d.ts +7 -0
  68. package/dist/components/types/uhd-viewer/src/model/nets.d.ts +53 -0
  69. package/dist/components/types/uhd-viewer/src/model/outputs.d.ts +79 -0
  70. package/dist/components/types/uhd-viewer/src/model/slots.d.ts +184 -0
  71. package/dist/components/types/uhd-viewer/src/model/types.d.ts +213 -0
  72. package/dist/components/types/uhd-viewer/src/options.d.ts +27 -0
  73. package/dist/components/types/uhd-viewer/src/source/source.d.ts +109 -0
  74. package/dist/components/types/uhd-viewer/src/source/tolerant.d.ts +45 -0
  75. package/dist/components/types/uhd-viewer/src/theme/ThemeProvider.d.ts +33 -0
  76. package/dist/components/types/uhd-viewer/src/theme/adapters.d.ts +28 -0
  77. package/dist/components/types/uhd-viewer/src/theme/resolve.d.ts +19 -0
  78. package/dist/components/types/uhd-viewer/src/theme/themes.d.ts +67 -0
  79. package/dist/components/types/uhd-viewer/src/theme/tokens.d.ts +175 -0
  80. package/dist/components/types/uhd-viewer/src/ui/Inspector.d.ts +45 -0
  81. package/dist/components/types/uhd-viewer/src/ui/Legend.d.ts +59 -0
  82. package/dist/components/types/uhd-viewer/src/ui/ScrollArea.d.ts +16 -0
  83. package/dist/components/types/uhd-viewer/src/ui/Toolbar.d.ts +49 -0
  84. package/dist/components/types/uhd-viewer/src/ui/Tooltips.d.ts +3 -0
  85. package/dist/components/types/uhd-viewer/src/ui/cx.d.ts +2 -0
  86. package/dist/components/types/uhd-viewer/src/ui/legendFit.d.ts +55 -0
  87. package/dist/components/types/uhd-viewer/src/viewer/controller.d.ts +219 -0
  88. package/dist/components/types/uhd-viewer/src/viewer/details.d.ts +81 -0
  89. package/dist/components/types/uhd-viewer/src/viewer/hierarchy.d.ts +82 -0
  90. package/dist/components/types/uhd-viewer/src/viewer/mount.d.ts +12 -0
  91. package/dist/components/types/uhd-viewer/src/viewer/views.d.ts +187 -0
  92. package/dist/headless/index.d.ts +71 -0
  93. package/dist/headless/index.js +7425 -0
  94. package/dist/headless/index.js.map +1 -0
  95. package/dist/lib/api.d.ts +252 -0
  96. package/dist/lib/uhd-viewer.css +3 -0
  97. package/dist/lib/uhd-viewer.d.ts +4 -0
  98. package/dist/lib/uhd-viewer.js +97787 -0
  99. package/package.json +110 -4
  100. package/src/styles/fonts/OFL.txt +93 -0
  101. package/src/styles/tailwind-theme.css +48 -0
@@ -0,0 +1,132 @@
1
+ /**
2
+ * 3D view model (PB-775): what to load and where, derived from UHD alone.
3
+ *
4
+ * - Placements come from `assemble` (mechanical links with frames).
5
+ * - Each placement's body is the module's GLB artifact for that body.
6
+ * - Each interface reports how it is bound, per direction:
7
+ * feature D1 named sub-shape in the body artifact (+ signature)
8
+ * artifact D2 its own artifact file
9
+ * procedural D3 derived from its parameters at its frame
10
+ * plus whether it is logical, unmapped, or resolved through its children.
11
+ */
12
+ import type { ArtifactDef, GeometryFrame, GeometryRef, InterfaceDef, ModuleDef } from "@deltarobotics/uhd";
13
+ import { type Assembly, type GeometryBindingIssue, type GeometryManifest, type Mat4 } from "@deltarobotics/uhd";
14
+ import type { ModuleLookup } from "@deltarobotics/uhd";
15
+ /** Artifact URL for a definition's (relative) file path: supplied by the viewer's source. */
16
+ import type { ArtifactResolver } from "../api";
17
+ export type { ArtifactResolver };
18
+ export type Direction = "feature" | "artifact" | "procedural";
19
+ export declare const DIRECTIONS: {
20
+ id: Direction;
21
+ label: string;
22
+ hint: string;
23
+ icon: string;
24
+ }[];
25
+ export interface CadBody {
26
+ key: string;
27
+ path: string[];
28
+ def: ModuleDef;
29
+ /** GLB to load, if the module has one for this body. */
30
+ glb?: ArtifactDef;
31
+ /** The body artifact id feature refs point at (STEP or vendor source). */
32
+ bodyArtifact?: string;
33
+ matrix: Mat4;
34
+ via?: string;
35
+ /** Placed by a hint, not by a link. */
36
+ hint?: string;
37
+ /**
38
+ * Nothing places it: it is drawn beside the others in a row, laid out
39
+ * once its model is loaded (PB-1040), and the view says it is unplaced.
40
+ */
41
+ row?: boolean;
42
+ }
43
+ export type BindingStatus = "bound" | "stale" | "missing" | "unchecked" | "none";
44
+ export interface InterfaceRow {
45
+ iface: InterfaceDef;
46
+ frame?: GeometryFrame;
47
+ /** Geometry comes from these interfaces (itself, or its children). */
48
+ sources: string[];
49
+ refs: {
50
+ interfaceId: string;
51
+ ref: GeometryRef;
52
+ }[];
53
+ logical: boolean;
54
+ /** No frame and no refs, on itself or any child. */
55
+ unmapped: boolean;
56
+ /** Per-direction resolution. */
57
+ byDirection: Record<Direction, {
58
+ interfaceId: string;
59
+ ref: GeometryRef;
60
+ status: BindingStatus;
61
+ note?: string;
62
+ }[]>;
63
+ issues: GeometryBindingIssue[];
64
+ }
65
+ export interface CadModel {
66
+ assembly: Assembly;
67
+ bodies: CadBody[];
68
+ /** module path key -> def, for every leaf instance */
69
+ defs: Map<string, ModuleDef>;
70
+ manifests: Map<string, GeometryManifest>;
71
+ /**
72
+ * Instances drawn inside another module's body rather than placed: the
73
+ * components of a board whose body (board.glb) shows them (PB-823). Path
74
+ * key → the body key that holds them.
75
+ */
76
+ within: Map<string, string>;
77
+ /**
78
+ * Where the placements come from when not from the module's own assembly
79
+ * (PB-1040): an ancestor's assembly cut down to the module (`from` is the
80
+ * ancestor's path from the root, `""` the root), or nothing at all, the
81
+ * models side by side (`row`).
82
+ */
83
+ placedBy?: {
84
+ kind: "ancestor";
85
+ from: string;
86
+ } | {
87
+ kind: "row";
88
+ };
89
+ }
90
+ /** The definition at an instance path below `system` ([] is the system itself). */
91
+ export declare function defAt(system: ModuleDef, lookup: ModuleLookup, path: string[]): ModuleDef | undefined;
92
+ /** Artifact id of the GLB for a body: the one generated from `bodyArtifact`, or the module's first body GLB. */
93
+ export declare function glbFor(def: ModuleDef, bodyArtifact?: string): ArtifactDef | undefined;
94
+ /** Fetch every manifest JSON the modules declare (artifacts with format json generated from a body). */
95
+ export declare function loadManifests(defs: ModuleDef[], resolve: ArtifactResolver): Promise<Map<string, GeometryManifest>>;
96
+ export declare function buildCadModel(system: ModuleDef, lookup: ModuleLookup, manifests: Map<string, GeometryManifest>, hints?: {
97
+ path: string[];
98
+ matrix: Mat4;
99
+ note: string;
100
+ }[], rootPath?: string[]): CadModel;
101
+ /**
102
+ * The model with every part that nothing places, but that has a model of
103
+ * its own, added as a body in a row beside the rest (PB-1040): a module's
104
+ * 3D view never leaves out a part that has a model. The row is laid out by
105
+ * the view once the models are loaded (their sizes are known then). Undefined
106
+ * when there is no such part.
107
+ */
108
+ export declare function withUnplacedInRow(model: CadModel, shown: ModuleDef, lookup: ModuleLookup): CadModel | undefined;
109
+ /**
110
+ * The named bodies a GLB comes apart into when exploded (D17): the largest
111
+ * stays, the rest move away from it. Only a cad standard output does this:
112
+ * `body.glb` with a `body.manifest.json` whose `bodies` lists two or more (an
113
+ * enclosure's back and lid), when the manifest was generated from the GLB, or
114
+ * when the module's print or cut exports make those bodies as separate pieces
115
+ * (`lid.stl` beside `base.stl`: both came from the same export). A vendor or
116
+ * library part's GLB stays rigid even when its manifest names several bodies
117
+ * (a motor's bell and stator, a prop's hub and blades).
118
+ */
119
+ export declare function explodeParts(def: ModuleDef, glb: ArtifactDef | undefined, manifest: GeometryManifest | undefined): {
120
+ fixed: string;
121
+ moving: string[];
122
+ } | undefined;
123
+ export declare function interfaceRows(def: ModuleDef, manifests: Map<string, GeometryManifest>): InterfaceRow[];
124
+ /** Bolt-pattern / shaft parameters for procedural geometry (D3). */
125
+ export declare function param(iface: InterfaceDef, id: string): number | undefined;
126
+ export declare function traitParam<T>(iface: InterfaceDef, type: string, key: string): T | undefined;
127
+ /**
128
+ * The instance the assembly is placed from when the display hints don't say:
129
+ * the system itself when it has a body of its own, else the top-level module
130
+ * with the most interface frames (the structure the others mount to).
131
+ */
132
+ export declare function defaultRoot(system: ModuleDef, lookup: (id: string) => ModuleDef | undefined): string[];
@@ -0,0 +1,15 @@
1
+ import * as THREE from "three";
2
+ /**
3
+ * Bodies that nothing places (PB-1040) in a row beside what is placed, once
4
+ * their models are loaded and their sizes known: along x, after the placed
5
+ * bodies, centred on them across and resting on their lowest point; from the
6
+ * origin when nothing is placed. Each one's `base` is where it now sits.
7
+ */
8
+ export declare function layOutRow(recs: {
9
+ body: {
10
+ row?: boolean;
11
+ };
12
+ base: THREE.Matrix4;
13
+ obj: THREE.Object3D;
14
+ box: THREE.Box3;
15
+ }[]): void;
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Imperative three.js scene for the 3D view (PB-775). Units: mm, Z up.
3
+ *
4
+ * GLB artifacts are glTF (metres, Y up); each is wrapped in a group that
5
+ * rotates +90° about X and scales ×1000, which returns it to the module's
6
+ * own CAD coordinates — the coordinates UHD frames are written in.
7
+ */
8
+ import * as THREE from "three";
9
+ import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
10
+ import { type GLTF } from "three/examples/jsm/loaders/GLTFLoader.js";
11
+ import type { GeometryFrame, InterfaceDef, ModuleDef } from "@deltarobotics/uhd";
12
+ import type { Mat4 } from "@deltarobotics/uhd";
13
+ import type { Appearance } from "../source/source";
14
+ /** The theme's colours for the scene, as `#rrggbb` (ThemeProvider's tokenColor). */
15
+ export interface SceneTheme {
16
+ background: string;
17
+ grid: string;
18
+ gridMinor: string;
19
+ accent: string;
20
+ highlight: string;
21
+ }
22
+ /**
23
+ * Highlight colours of one scene. The focus colours follow the theme's accent
24
+ * and highlight tokens; the rest are data colours. Each scene owns its set, so
25
+ * two viewers with different themes never share focus colours.
26
+ */
27
+ export interface SceneColors {
28
+ focus: number;
29
+ counterpart: number;
30
+ normal: number;
31
+ xAxis: number;
32
+ phase: number[];
33
+ hint: number;
34
+ /** The selected body's emissive glow, and a stronger one for a picked interface's body. */
35
+ glow: number;
36
+ glowStrong: number;
37
+ }
38
+ /** The neutral default theme's accent and highlight (the stylesheet defaults), used until a theme is read. */
39
+ export declare const DEFAULT_SCENE_ACCENT = "#339fee";
40
+ export declare const DEFAULT_SCENE_HIGHLIGHT = "#22d3ee";
41
+ /** Fresh scene colours for a theme's accent and highlight (the selected body glows a dim accent). */
42
+ export declare function sceneColors(theme?: Pick<SceneTheme, "accent" | "highlight">): SceneColors;
43
+ /** WCAG relative luminance of a colour (0 black … 1 white). */
44
+ export declare function relativeLuminance(c: THREE.Color): number;
45
+ /** Load a GLB by URL (artifact URLs come from the viewer source's resolver). */
46
+ export declare function loadGlb(url: string): Promise<GLTF | null>;
47
+ /** glTF (m, Y-up) back to CAD coordinates (mm, Z-up). */
48
+ export declare function cadWrapper(obj: THREE.Object3D): THREE.Group;
49
+ export declare function toMatrix4(m: Mat4): THREE.Matrix4;
50
+ /**
51
+ * Surface for a module's body (or one named sub-body of its CAD), from, in
52
+ * order: display hints for the definition (and part), the part's declared
53
+ * material (UHD MaterialSpec), then neutral defaults by kind. Nothing here
54
+ * knows a particular project.
55
+ */
56
+ export declare function materialFor(def: ModuleDef, bodyPart: string, appearance?: Appearance): THREE.MeshStandardMaterial;
57
+ export declare const focusMaterial: (color: number) => THREE.MeshStandardMaterial;
58
+ /** Group whose local X/Y/Z are the frame's xAxis / (normal × xAxis) / normal, origin at the frame origin. */
59
+ export declare function frameGroup(frame: GeometryFrame): THREE.Group;
60
+ export declare function frameGizmo(frame: GeometryFrame, colors: SceneColors, size?: number): THREE.Group;
61
+ /**
62
+ * D3: geometry derived from the interface's own parameters, placed at its
63
+ * frame. Returns null when the generator has nothing to work with. `notes`
64
+ * collects what the parameters could not say (e.g. pattern phase).
65
+ */
66
+ export declare function proceduralGeometry(iface: InterfaceDef, generator: string, frame: GeometryFrame, color: number, notes: string[]): THREE.Object3D | null;
67
+ export interface SceneHandle {
68
+ scene: THREE.Scene;
69
+ camera: THREE.PerspectiveCamera;
70
+ controls: OrbitControls;
71
+ renderer: THREE.WebGLRenderer;
72
+ root: THREE.Group;
73
+ overlay: THREE.Group;
74
+ dispose: () => void;
75
+ frameAll: (box?: THREE.Box3) => void;
76
+ /**
77
+ * The model direction drawn up (default +z): the camera's up, the orbit
78
+ * axis, the ground grid and the lights follow it (a display hint, PB-873).
79
+ */
80
+ setUp: (up: THREE.Vector3) => void;
81
+ /** Put the ground grid under a box (the assembled model), across the up direction. */
82
+ setGround: (box: THREE.Box3) => void;
83
+ /** This scene's highlight colours (follow `setTheme`). */
84
+ colors: SceneColors;
85
+ /** The theme's background, grid and focus colours. */
86
+ setTheme: (theme: SceneTheme) => void;
87
+ /** Called every frame before rendering, with the frame time in seconds. */
88
+ onFrame: Set<(dt: number) => void>;
89
+ /** When set, the render loop is driven externally (video capture). */
90
+ manual: {
91
+ on: boolean;
92
+ };
93
+ renderOnce: () => void;
94
+ }
95
+ export declare function createScene(container: HTMLElement): SceneHandle;
@@ -0,0 +1,89 @@
1
+ /**
2
+ * The 3D view of one module (PB-897): a system's view shows the whole
3
+ * assembly, a module's shows that module alone, in its own coordinates. The
4
+ * model is then built from the module's definition, so every path in it is
5
+ * relative to the module; a host's paths, the display hints and the findings
6
+ * are all written from the root. These functions translate between the two,
7
+ * and say what a view shows and what it leaves out.
8
+ */
9
+ import type { ModuleDef } from "@deltarobotics/uhd";
10
+ import type { ModuleLookup } from "@deltarobotics/uhd";
11
+ import type { GeometryManifest, Mat4 } from "@deltarobotics/uhd";
12
+ import { type CadModel } from "./model";
13
+ /** A path from the root as a path inside `scope` ("" is the scope's own module); undefined when it is outside. */
14
+ export declare function intoScope(path: string, scope: string): string | undefined;
15
+ /** A path inside `scope` as a path from the root. */
16
+ export declare function outOfScope(path: string, scope: string): string;
17
+ /**
18
+ * A finding's reference from the root (`board/u2:pin_14`, `board:sda`,
19
+ * `link:board/<id>`) as one inside `scope`; undefined when it names
20
+ * something outside.
21
+ */
22
+ export declare function scopeRef(ref: string, scope: string): string | undefined;
23
+ /** The display hints' placements (keyed by path from the root, `#body` kept) that lie inside `scope`, re-keyed to it. */
24
+ export declare function scopedPlacements<T extends {
25
+ matrix: Mat4;
26
+ note?: string;
27
+ }>(placements: Record<string, T> | undefined, scope: string): {
28
+ path: string[];
29
+ matrix: Mat4;
30
+ note: string;
31
+ }[];
32
+ /** The display hints' assembly root (a path from the root) inside `scope`; undefined when it is not, or none is given. */
33
+ export declare function scopedRoot(root: string | undefined, scope: string): string[] | undefined;
34
+ /** The modules above `scope`, nearest first, as paths from the root (`""` is the root). */
35
+ export declare function ancestorsOf(scope: string): string[];
36
+ /**
37
+ * A model of an ancestor cut down to the module at `rel` (its path inside
38
+ * the ancestor) and re-keyed to it (PB-1040): what a module with no assembly
39
+ * of its own shows, its parts where the ancestor's assembly puts them. The
40
+ * matrices stay in the ancestor's coordinates (the view fits what is drawn);
41
+ * mates, routes and hardware are kept only when both of their ends lie in
42
+ * the module, and harnesses when they are in it.
43
+ */
44
+ export declare function borrowModel(model: CadModel, rel: string[], from: string): CadModel;
45
+ export interface Unplaced {
46
+ /** Child id in the shown module. */
47
+ id: string;
48
+ name: string;
49
+ }
50
+ /** What a 3D view shows of a module, and what it does not. */
51
+ export interface ShownSummary {
52
+ /** The module has a body of its own (a board's `board.glb`): it is drawn as that body, its children in it. */
53
+ ownBody: boolean;
54
+ /** The module's direct children that are parts (harnesses are drawn as cables and hardware, not counted). */
55
+ parts: number;
56
+ /** Those of them that are drawn: placed, or inside the module's own body. */
57
+ placed: Unplaced[];
58
+ /** Those that are not: nothing says where they sit. */
59
+ unplaced: Unplaced[];
60
+ /** Those of `placed` that nothing places either, drawn beside the others (PB-1040). */
61
+ inRow: Unplaced[];
62
+ /**
63
+ * Nothing joins the module's parts: it has no body of its own, more than
64
+ * one part, and no mate or hint places a second one. What would be drawn
65
+ * is one part on its own, which is not a picture of the module.
66
+ */
67
+ loose: boolean;
68
+ }
69
+ export declare function shownSummary(model: CadModel, shown: ModuleDef, lookup: ModuleLookup): ShownSummary;
70
+ /**
71
+ * The model a 3D view draws of the module at `at` (a path from the root;
72
+ * `""` is the root), PB-897 and PB-1040:
73
+ *
74
+ * 1. the module's own assembly: its mates and the display hints inside it;
75
+ * 2. when that leaves parts unplaced and the module has no body of its own,
76
+ * the nearest ancestor whose assembly places more of them: its assembly,
77
+ * cut down to the module (`borrowModel`);
78
+ * 3. what nothing places but has a model is drawn beside the rest, in a row
79
+ * (`withUnplacedInRow`), and the view says so.
80
+ *
81
+ * The root's view is its own assembly, as before.
82
+ */
83
+ export declare function scopedModel(system: ModuleDef, lookup: ModuleLookup, manifests: Map<string, GeometryManifest>, display: {
84
+ placements?: Record<string, {
85
+ matrix: Mat4;
86
+ note?: string;
87
+ }>;
88
+ root?: string;
89
+ }, at: string): CadModel;
@@ -0,0 +1,90 @@
1
+ import type { ViewModel } from "../model/types";
2
+ import type { NodeMark } from "../api";
3
+ import { type Classification } from "../model/classification";
4
+ import type { ComputedLayout } from "../layout/layout";
5
+ import type { LevelLayout, LinkLayout } from "../layout/layout";
6
+ import { type Detail } from "./LinkEdge";
7
+ import type { Pt } from "./routing";
8
+ import type { Isolation } from "../model/isolate";
9
+ import type { Live } from "../viewer/controller";
10
+ import { type InteractionAction, type InteractionState, type Viewport } from "./interaction";
11
+ /** A view command from outside the canvas (a toolbar, a menu): fit, or a zoom step; `seq` tells repeats apart. */
12
+ export interface ViewCommand {
13
+ type: "fit" | "in" | "out" | "reset";
14
+ seq: number;
15
+ }
16
+ export type Selection = {
17
+ kind: "node" | "link";
18
+ id: string;
19
+ } | null;
20
+ /** Fit padding that keeps the diagram clear of the floating chrome: the header, the toolbar and, when open, the inspector. */
21
+ export declare const fitPadding: (inspector: boolean) => {
22
+ readonly top: "56px";
23
+ readonly bottom: "72px";
24
+ readonly left: "64px";
25
+ readonly right: "376px" | "64px";
26
+ };
27
+ export interface CanvasProps {
28
+ vm: ViewModel;
29
+ /** The inspector is open over the right of the canvas (fitting leaves room for it). */
30
+ inspector?: boolean;
31
+ layout: ComputedLayout;
32
+ hand?: LevelLayout;
33
+ mode: Classification;
34
+ detail: Detail;
35
+ showGrounds: boolean;
36
+ openLinks: Set<string>;
37
+ selection: Selection;
38
+ onSelect: (s: Selection) => void;
39
+ onToggleLink: (id: string) => void;
40
+ onLayout: (linkId: string, patch: LinkLayout) => void;
41
+ onPins: (linkId: string, pins: Pt[]) => void;
42
+ onToggleExpand: (id: string) => void;
43
+ /** Double-click on a node (default: expand it in place). */
44
+ onOpenNode?: (id: string) => void;
45
+ onMove: (id: string, x: number, y: number) => void;
46
+ /** A drag starts (what moves) or ends (null): the layout reroutes only what moves meanwhile. */
47
+ onLive: (live: Live | null) => void;
48
+ /**
49
+ * A node to bring into view (a host's focus, a row of the hierarchy), once it is drawn; `seq` tells repeats
50
+ * apart. With `lines`, a harness drawn along lines (no card of its own): those lines are framed.
51
+ */
52
+ centre?: {
53
+ id: string;
54
+ seq: number;
55
+ lines?: readonly string[];
56
+ };
57
+ /** A selection to bring into view if it is not (a host's select): panned to, zoomed out only if it must; `seq` tells repeats apart. */
58
+ reveal?: {
59
+ selection: NonNullable<Selection>;
60
+ seq: number;
61
+ };
62
+ /** Right-click on a node: its context menu at the pointer (the browser's own when not given). */
63
+ onNodeContext?: (id: string, x: number, y: number) => void;
64
+ /** The host's marks by definition id (`ViewerOptions.nodeMarks`). */
65
+ marks?: Record<string, NodeMark>;
66
+ /** Legend entries are isolated: what stays at full strength (the rest fades). */
67
+ isolation?: Isolation | null;
68
+ /** Modules selected together (a selection box, clicks with Shift, Ctrl or Cmd, select all): two or more, else empty. */
69
+ group?: readonly string[];
70
+ /** React Flow selected or unselected modules (a box, a click with a key held, a press on a module): the changes, a rail's taps named as the rail. */
71
+ onSelectChanges?: (changes: {
72
+ id: string;
73
+ selected: boolean;
74
+ }[]) => void;
75
+ /** The tool chosen and whether Space is held (default: select). */
76
+ interaction?: InteractionState;
77
+ onInteraction?: (action: InteractionAction) => void;
78
+ /** Ctrl/Cmd+A, and Escape. */
79
+ onSelectAll?: () => void;
80
+ onEscape?: () => void;
81
+ /** Fit or zoom, asked for by a toolbar or a menu. */
82
+ command?: ViewCommand;
83
+ /** The viewport saved for this level: put back when the canvas opens (none: the diagram is fitted). */
84
+ viewport?: Viewport;
85
+ /** The user moved the view (its viewport), or asked for a fit (null: nothing is kept, the next opening fits). */
86
+ onViewport?: (viewport: Viewport | null) => void;
87
+ /** Right-click on the empty canvas: its menu at the pointer (the browser's own when not given). */
88
+ onPaneContext?: (x: number, y: number) => void;
89
+ }
90
+ export declare function Canvas(props: CanvasProps): import("react").JSX.Element;
@@ -0,0 +1,5 @@
1
+ import { type LucideProps } from "lucide-react";
2
+ /** Lucide icon by kebab-case name (UHD display hints use Lucide names). */
3
+ export declare function Icon({ name, ...props }: {
4
+ name: string;
5
+ } & LucideProps): import("react").JSX.Element;
@@ -0,0 +1,40 @@
1
+ import { type Edge, type EdgeProps } from "@xyflow/react";
2
+ import type { ViewLink } from "../model/types";
3
+ import { type Classification } from "../model/classification";
4
+ import { type Pt } from "./routing";
5
+ import type { LinkLayout } from "../layout/layout";
6
+ import type { Live } from "../viewer/controller";
7
+ export type Detail = "basic" | "ribbon";
8
+ export interface LinkData extends Record<string, unknown> {
9
+ link: ViewLink;
10
+ points: Pt[];
11
+ color: string;
12
+ faded: boolean;
13
+ mode: Classification;
14
+ detail: Detail;
15
+ /** Expanded (lanes shown). */
16
+ open: boolean;
17
+ openLanes: Set<string>;
18
+ /** Harness span along the route (arc lengths). */
19
+ run?: [number, number];
20
+ /** Label + toggle position (arc length); absent: no label. */
21
+ labelAt?: number;
22
+ /** The label was placed by the user (or the display file): honour it even on a short stretch. */
23
+ labelFixed?: boolean;
24
+ pins: Pt[];
25
+ bends: Pt[];
26
+ onToggle: (id: string) => void;
27
+ onToggleLane: (id: string) => void;
28
+ /** Select the link (a click on its label: the label stops the edge's own click). */
29
+ onSelect?: (linkId: string) => void;
30
+ /** Where the user put the label and harness tab (and which side of the line). */
31
+ edit?: LinkLayout;
32
+ onLayout: (linkId: string, patch: LinkLayout) => void;
33
+ onPins: (linkId: string, pins: Pt[]) => void;
34
+ onLive: (live: Live | null) => void;
35
+ }
36
+ export type LinkEdgeType = Edge<LinkData, "link">;
37
+ export declare function LinkEdge({ id, data, selected }: EdgeProps<LinkEdgeType>): import("react").JSX.Element | null;
38
+ export declare const edgeTypes: {
39
+ link: typeof LinkEdge;
40
+ };
@@ -0,0 +1,18 @@
1
+ import type { PlacedPort } from "../layout/layout";
2
+ export interface PortProps {
3
+ placed: PlacedPort;
4
+ /** Position relative to the node's top-left corner. */
5
+ x: number;
6
+ y: number;
7
+ color: string;
8
+ faded: boolean;
9
+ exported?: boolean;
10
+ label?: boolean;
11
+ ground?: boolean;
12
+ selected?: boolean;
13
+ /** Draw the dot (off where a ribbon's pin handle already marks the port). */
14
+ dot?: boolean;
15
+ /** Max label width in px (from port spacing and card size). */
16
+ labelWidth?: number;
17
+ }
18
+ export declare function Port({ placed, x, y, color, faded, exported, label, ground, selected, dot, labelWidth }: PortProps): import("react").JSX.Element;
@@ -0,0 +1,5 @@
1
+ export interface CanvasActions {
2
+ onToggleExpand?: (id: string) => void;
3
+ }
4
+ export declare const CanvasActionsContext: import("react").Context<CanvasActions>;
5
+ export declare const useCanvasActions: () => CanvasActions;
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Geometry along a routed link (PB-803): positions by arc length, sub-paths,
3
+ * lanes that fan out of the centre line, and harness regions traced around
4
+ * whatever runs through them. Pure functions, no React.
5
+ */
6
+ import { type Pt } from "./routing";
7
+ export declare const RUN = 24;
8
+ export declare const LANE_PITCH = 16;
9
+ export declare const RIBBON_PITCH = 6;
10
+ export declare function lengths(points: Pt[]): number[];
11
+ export declare const totalLength: (points: Pt[]) => number;
12
+ /** Point and unit direction at arc length `s`. */
13
+ export declare function at(points: Pt[], s: number): {
14
+ p: Pt;
15
+ d: Pt;
16
+ };
17
+ /** The polyline between arc lengths s0 and s1. */
18
+ export declare function subpath(points: Pt[], s0: number, s1: number): Pt[];
19
+ /** Arc length of the point on the polyline nearest to `q`. */
20
+ export declare function project(points: Pt[], q: Pt): number;
21
+ export declare function densify(points: Pt[], step?: number): Pt[];
22
+ /** Offsets for n lanes centred on the line. */
23
+ export declare const offsets: (n: number, pitch: number) => number[];
24
+ /** Fillet radius for the centre line of a ribbon `width` wide, so its inner conductor still turns round. */
25
+ export declare const ribbonRadius: (width: number) => number;
26
+ /** Stroke points of a ribbon (parallel conductors at a fixed pitch) along the whole route. */
27
+ export declare function ribbon(points: Pt[], n: number, radius?: number): {
28
+ d: string;
29
+ samples: Pt[];
30
+ }[];
31
+ /**
32
+ * The straight stretches of a route as arc-length intervals, each kept `clear`
33
+ * of the corners at its ends (and `end` of the route's own ends).
34
+ */
35
+ export declare function straights(points: Pt[], clear: number, end?: number): [number, number][];
36
+ /**
37
+ * The nearest arc length to `s` that sits on a straight stretch, clear of the
38
+ * bends (handles and toggles never sit in a corner). Where no stretch is long
39
+ * enough, the middle of the longest segment.
40
+ */
41
+ export declare function clearOfBends(points: Pt[], s: number, clear: number, end?: number): number;
42
+ /** The straight stretch (with `clear` at its corners) that contains arc length `s`. */
43
+ export declare function stretchAt(points: Pt[], s: number, clear: number, end?: number): [number, number];
44
+ /**
45
+ * Turn short S-jogs (a sidestep between two runs in the same direction,
46
+ * shorter than `min`) into a gentle diagonal: a wide ribbon cannot take two
47
+ * right angles in less than its own width without its conductors crossing.
48
+ */
49
+ export declare function easeJogs(points: Pt[], min: number): Pt[];
50
+ /**
51
+ * A closed outline around every sample (dilated by `pad`), traced on a 2 px
52
+ * raster and smoothed: the harness region, tight to what runs through it.
53
+ */
54
+ export declare function regionOutline(samples: Pt[], pad: number): string;
55
+ /** A stretch of a line at a constant offset from the centre line, between arc lengths a and b. */
56
+ export interface Plateau {
57
+ o: number;
58
+ a: number;
59
+ b: number;
60
+ }
61
+ /**
62
+ * A line that steps between offsets from the centre line: it runs each
63
+ * plateau parallel to the route and curves smoothly from one to the next over
64
+ * the gap between them (b of one to a of the next). Consecutive plateaus at
65
+ * the same offset join straight through. The building block of every
66
+ * breakout: a lane leaving its parent line, and a conductor stepping out
67
+ * level by level.
68
+ */
69
+ export declare function stepped(points: Pt[], plateaus: Plateau[], radius?: number): {
70
+ d: string;
71
+ samples: Pt[];
72
+ };