@graview/render 0.0.0-stage → 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.
Files changed (47) hide show
  1. package/LICENSE +96 -0
  2. package/README.md +43 -2
  3. package/dist/gpu.d.ts +6 -0
  4. package/dist/gpu.d.ts.map +1 -0
  5. package/dist/gpu.js +23 -0
  6. package/dist/gpu.js.map +1 -0
  7. package/dist/index.d.ts +12 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +31 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/interaction/pointer-router.d.ts +94 -0
  12. package/dist/interaction/pointer-router.d.ts.map +1 -0
  13. package/dist/interaction/pointer-router.js +148 -0
  14. package/dist/interaction/pointer-router.js.map +1 -0
  15. package/dist/platform/html-in-canvas.d.ts +100 -0
  16. package/dist/platform/html-in-canvas.d.ts.map +1 -0
  17. package/dist/platform/html-in-canvas.js +172 -0
  18. package/dist/platform/html-in-canvas.js.map +1 -0
  19. package/dist/platform/matrix.d.ts +53 -0
  20. package/dist/platform/matrix.d.ts.map +1 -0
  21. package/dist/platform/matrix.js +61 -0
  22. package/dist/platform/matrix.js.map +1 -0
  23. package/dist/scene/compositor.d.ts +112 -0
  24. package/dist/scene/compositor.d.ts.map +1 -0
  25. package/dist/scene/compositor.js +340 -0
  26. package/dist/scene/compositor.js.map +1 -0
  27. package/dist/scene/compositor.wgsl.d.ts +15 -0
  28. package/dist/scene/compositor.wgsl.d.ts.map +1 -0
  29. package/dist/scene/compositor.wgsl.js +106 -0
  30. package/dist/scene/compositor.wgsl.js.map +1 -0
  31. package/dist/scene/connectors.d.ts +60 -0
  32. package/dist/scene/connectors.d.ts.map +1 -0
  33. package/dist/scene/connectors.js +95 -0
  34. package/dist/scene/connectors.js.map +1 -0
  35. package/dist/scene/frame-plan.d.ts +83 -0
  36. package/dist/scene/frame-plan.d.ts.map +1 -0
  37. package/dist/scene/frame-plan.js +119 -0
  38. package/dist/scene/frame-plan.js.map +1 -0
  39. package/dist/scene/from-layout.d.ts +14 -0
  40. package/dist/scene/from-layout.d.ts.map +1 -0
  41. package/dist/scene/from-layout.js +35 -0
  42. package/dist/scene/from-layout.js.map +1 -0
  43. package/dist/scene/plane.d.ts +68 -0
  44. package/dist/scene/plane.d.ts.map +1 -0
  45. package/dist/scene/plane.js +94 -0
  46. package/dist/scene/plane.js.map +1 -0
  47. package/package.json +64 -3
@@ -0,0 +1,83 @@
1
+ import type { Placement } from "../interaction/pointer-router.js";
2
+ import type { Matrix4 } from "../platform/matrix.js";
3
+ import { type ConnectorStyle } from "./connectors.js";
4
+ import { type PlaneStyle } from "./plane.js";
5
+ /** One view drawn into the scene: a DOM subtree, and where it belongs. */
6
+ export interface PlannedView {
7
+ readonly id: string;
8
+ /** 0 focus, 1 relations, 2 context. May be fractional mid-transition. */
9
+ readonly plane: number;
10
+ /** Layout position in canvas pixels, before the plane transform. */
11
+ readonly x: number;
12
+ readonly y: number;
13
+ readonly width: number;
14
+ readonly height: number;
15
+ /** Set when the view's DOM changed and its texture is stale. */
16
+ readonly dirty?: boolean;
17
+ readonly opacity?: number;
18
+ }
19
+ export interface PlannedConnector {
20
+ readonly id: string;
21
+ readonly kind: string;
22
+ readonly from: string;
23
+ readonly to: string;
24
+ readonly opacity?: number;
25
+ }
26
+ export interface CaptureCommand {
27
+ readonly viewId: string;
28
+ /** Why this frame needed the pixels again — useful when a budget blows. */
29
+ readonly reason: "first" | "live" | "changed";
30
+ }
31
+ export interface ViewDraw {
32
+ readonly viewId: string;
33
+ readonly transform: Matrix4;
34
+ readonly style: PlaneStyle;
35
+ /** Drawn width and height, after the plane's scale. */
36
+ readonly width: number;
37
+ readonly height: number;
38
+ readonly opacity: number;
39
+ }
40
+ export interface ConnectorDraw {
41
+ readonly id: string;
42
+ readonly kind: string;
43
+ readonly style: ConnectorStyle;
44
+ readonly x1: number;
45
+ readonly y1: number;
46
+ readonly x2: number;
47
+ readonly y2: number;
48
+ readonly opacity: number;
49
+ }
50
+ export interface GeometryReport {
51
+ readonly viewId: string;
52
+ readonly transform: Matrix4;
53
+ }
54
+ export interface FramePlan {
55
+ /** Views whose textures need refreshing, in draw order. */
56
+ readonly captures: readonly CaptureCommand[];
57
+ /** Back to front, so the focus plane lands on top. */
58
+ readonly draws: readonly ViewDraw[];
59
+ readonly connectors: readonly ConnectorDraw[];
60
+ /** What to tell the browser about where each view ended up. */
61
+ readonly geometry: readonly GeometryReport[];
62
+ /** What the pointer router needs to route a click. */
63
+ readonly placements: readonly Omit<Placement, "element">[];
64
+ /** Captures this frame. The number the budget is spent on. */
65
+ readonly captureCount: number;
66
+ }
67
+ export interface PlanOptions {
68
+ readonly canvasWidth: number;
69
+ readonly canvasHeight: number;
70
+ /** Frame index of the last capture per view; absent means never captured. */
71
+ readonly capturedAt?: Readonly<Record<string, number>>;
72
+ readonly connectorOverrides?: Readonly<Record<string, Partial<ConnectorStyle>>>;
73
+ }
74
+ /**
75
+ * What a frame consists of, as data — no GPU, no DOM, no browser.
76
+ *
77
+ * Separating the plan from its submission is what lets the fidelity policy,
78
+ * plane ordering and geometry reporting be tested in CI with no GPU present,
79
+ * while the executor that turns a plan into draw calls stays thin enough to
80
+ * verify in a real browser once.
81
+ */
82
+ export declare function planFrame(views: readonly PlannedView[], connectors: readonly PlannedConnector[], options: PlanOptions): FramePlan;
83
+ //# sourceMappingURL=frame-plan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frame-plan.d.ts","sourceRoot":"","sources":["../../src/scene/frame-plan.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,119 @@
1
+ import { connectorStyle } from "./connectors.js";
2
+ import { mixStyles, styleFor, transformFor } from "./plane.js";
3
+ /**
4
+ * What a frame consists of, as data — no GPU, no DOM, no browser.
5
+ *
6
+ * Separating the plan from its submission is what lets the fidelity policy,
7
+ * plane ordering and geometry reporting be tested in CI with no GPU present,
8
+ * while the executor that turns a plan into draw calls stays thin enough to
9
+ * verify in a real browser once.
10
+ */
11
+ export function planFrame(views, connectors, options) {
12
+ const capturedAt = options.capturedAt ?? {};
13
+ const captures = [];
14
+ const draws = [];
15
+ const geometry = [];
16
+ const placements = [];
17
+ const centres = new Map();
18
+ // Back to front: the deepest plane is drawn first so the focus plane lands
19
+ // on top of it. Sorting explicitly means callers may hand views over in any
20
+ // order without changing what the scene looks like.
21
+ const ordered = [...views].sort((a, b) => b.plane - a.plane);
22
+ for (const view of ordered) {
23
+ const style = styleAt(view.plane);
24
+ const reason = captureReason(view, style, capturedAt[view.id]);
25
+ if (reason)
26
+ captures.push({ viewId: view.id, reason });
27
+ const transform = transformFor(style, view.x, view.y, options.canvasWidth, options.canvasHeight);
28
+ const width = view.width * style.scale;
29
+ const height = view.height * style.scale;
30
+ draws.push({
31
+ viewId: view.id,
32
+ transform,
33
+ style,
34
+ width,
35
+ height,
36
+ opacity: view.opacity ?? 1,
37
+ });
38
+ geometry.push({ viewId: view.id, transform });
39
+ placements.push({
40
+ transform,
41
+ width: view.width,
42
+ height: view.height,
43
+ depth: view.plane,
44
+ });
45
+ centres.set(view.id, {
46
+ x: transform[12] + width / 2,
47
+ y: transform[13] + height / 2,
48
+ });
49
+ }
50
+ const connectorDraws = [];
51
+ for (const connector of connectors) {
52
+ const from = centres.get(connector.from);
53
+ const to = centres.get(connector.to);
54
+ // A connector to something off-scene is a line into nowhere.
55
+ if (!from || !to)
56
+ continue;
57
+ connectorDraws.push({
58
+ id: connector.id,
59
+ kind: connector.kind,
60
+ style: connectorStyle(connector.kind, options.connectorOverrides ?? {}),
61
+ x1: from.x,
62
+ y1: from.y,
63
+ x2: to.x,
64
+ y2: to.y,
65
+ opacity: connector.opacity ?? 1,
66
+ });
67
+ }
68
+ return {
69
+ captures,
70
+ draws,
71
+ connectors: connectorDraws,
72
+ geometry,
73
+ placements,
74
+ captureCount: captures.length,
75
+ };
76
+ }
77
+ /**
78
+ * The treatment for a possibly-fractional plane. Mid-transition a view is
79
+ * between two planes, and mixing their treatments is what makes the move read
80
+ * as travel rather than a cut.
81
+ */
82
+ function styleAt(plane) {
83
+ const lower = Math.floor(plane);
84
+ const upper = Math.ceil(plane);
85
+ if (lower === upper)
86
+ return styleFor(plane);
87
+ return mixStyles(styleFor(lower), styleFor(upper), plane - lower);
88
+ }
89
+ /**
90
+ * Whether a view needs recapturing, and why. Fidelity decides, not plane
91
+ * index — and the split is load-bearing rather than an optimisation:
92
+ * capture costs ~0.016 ms per node up to about 128 live captures a frame and
93
+ * then falls off a cliff (see docs/platform-findings.md).
94
+ *
95
+ * - `full` live: captured every frame, because it is being edited
96
+ * - `summary` cached: captured only when its DOM actually changed
97
+ * - `glyph` captured once, then only when its content actually changed —
98
+ * at glyph scale a cached texture is indistinguishable from a
99
+ * live one, but a stale one shows last week's number for ever
100
+ */
101
+ function captureReason(view, style, lastCapture) {
102
+ if (lastCapture === undefined)
103
+ return "first";
104
+ // Mid-transition a view's own DOM is still fading, so whatever was captured
105
+ // is not what it looks like. Caching that leaves an entering node stuck as
106
+ // the transparent frame it was first seen in — which is precisely what
107
+ // happened to every person raised onto plane 1.
108
+ if (view.opacity !== undefined && view.opacity < 1)
109
+ return "changed";
110
+ switch (style.fidelity) {
111
+ case "full":
112
+ return "live";
113
+ case "summary":
114
+ return view.dirty ? "changed" : null;
115
+ case "glyph":
116
+ return view.dirty ? "changed" : null;
117
+ }
118
+ }
119
+ //# sourceMappingURL=frame-plan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frame-plan.js","sourceRoot":"","sources":["../../src/scene/frame-plan.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { InterpolatedLayout, Layout } from "@graview/layout";
2
+ import type { PlannedConnector, PlannedView } from "./frame-plan.js";
3
+ /**
4
+ * Turns what layout emitted into what the renderer draws.
5
+ *
6
+ * Deliberately trivial: layout decides positions and planes, the renderer
7
+ * decides pixels, and this is the whole conversation between them. If this
8
+ * function ever starts making decisions, the two have begun to overlap.
9
+ */
10
+ export declare function fromLayout(result: Layout | InterpolatedLayout, dirty?: ReadonlySet<string>): {
11
+ views: PlannedView[];
12
+ connectors: PlannedConnector[];
13
+ };
14
+ //# sourceMappingURL=from-layout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"from-layout.d.ts","sourceRoot":"","sources":["../../src/scene/from-layout.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAClE,OAAO,KAAK,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAErE;;;;;;GAMG;AACH,wBAAgB,UAAU,CACxB,MAAM,EAAE,MAAM,GAAG,kBAAkB,EACnC,KAAK,GAAE,WAAW,CAAC,MAAM,CAAa,GACrC;IAAE,KAAK,EAAE,WAAW,EAAE,CAAC;IAAC,UAAU,EAAE,gBAAgB,EAAE,CAAA;CAAE,CA4B1D"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Turns what layout emitted into what the renderer draws.
3
+ *
4
+ * Deliberately trivial: layout decides positions and planes, the renderer
5
+ * decides pixels, and this is the whole conversation between them. If this
6
+ * function ever starts making decisions, the two have begun to overlap.
7
+ */
8
+ export function fromLayout(result, dirty = new Set()) {
9
+ // Planes may be fractional mid-transition; the frame plan mixes the two
10
+ // plane styles rather than snapping, so this passes them straight through.
11
+ const views = result.nodes.map((node) => ({
12
+ id: node.id,
13
+ plane: node.plane,
14
+ x: node.x,
15
+ y: node.y,
16
+ // Whole-pixel boxes. A fractional size reallocates the texture on every
17
+ // frame of a transition and desynchronises it from the element the
18
+ // browser actually rasterises.
19
+ width: Math.round(node.width),
20
+ height: Math.round(node.height),
21
+ // Mid-fade counts as dirty: the pixels on screen are not the pixels this
22
+ // view will settle at.
23
+ dirty: dirty.has(node.id) || ("opacity" in node && node.opacity < 1),
24
+ opacity: "opacity" in node ? node.opacity : 1,
25
+ }));
26
+ const connectors = result.connectors.map((connector) => ({
27
+ id: connector.id,
28
+ kind: connector.kind,
29
+ from: connector.from,
30
+ to: connector.to,
31
+ opacity: "opacity" in connector ? connector.opacity : 1,
32
+ }));
33
+ return { views, connectors };
34
+ }
35
+ //# sourceMappingURL=from-layout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"from-layout.js","sourceRoot":"","sources":["../../src/scene/from-layout.ts"],"names":[],"mappings":"AAGA;;;;;;GAMG;AACH,MAAM,UAAU,UAAU,CACxB,MAAmC,EACnC,QAA6B,IAAI,GAAG,EAAE;IAEtC,wEAAwE;IACxE,2EAA2E;IAC3E,MAAM,KAAK,GAAkB,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACvD,EAAE,EAAE,IAAI,CAAC,EAAE;QACX,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,CAAC,EAAE,IAAI,CAAC,CAAC;QACT,CAAC,EAAE,IAAI,CAAC,CAAC;QACT,wEAAwE;QACxE,mEAAmE;QACnE,+BAA+B;QAC/B,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC;QAC7B,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC;QAC/B,yEAAyE;QACzE,uBAAuB;QACvB,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,SAAS,IAAI,IAAI,IAAI,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;QACpE,OAAO,EAAE,SAAS,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;KAC9C,CAAC,CAAC,CAAC;IAEJ,MAAM,UAAU,GAAuB,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;QAC3E,EAAE,EAAE,SAAS,CAAC,EAAE;QAChB,IAAI,EAAE,SAAS,CAAC,IAAI;QACpB,IAAI,EAAE,SAAS,CAAC,IAAI;QACpB,EAAE,EAAE,SAAS,CAAC,EAAE;QAChB,OAAO,EAAE,SAAS,IAAI,SAAS,CAAC,CAAC,CAAE,SAAiC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;KACjF,CAAC,CAAC,CAAC;IAEJ,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC;AAC/B,CAAC"}
@@ -0,0 +1,68 @@
1
+ import { type Matrix4 } from "../platform/matrix.js";
2
+ /**
3
+ * Discrete z-planes with the camera locked to one axis. No free orbit: every
4
+ * view is nameable and returnable, which is what makes each stop a URL.
5
+ */
6
+ export declare const PLANES: {
7
+ /** Live, editable DOM. Captured every frame it moves. */
8
+ readonly focus: 0;
9
+ /** The entity type you asked to see, with connectors. */
10
+ readonly relations: 1;
11
+ /** Everything else, as aggregate blocks. */
12
+ readonly context: 2;
13
+ };
14
+ export type PlaneIndex = 0 | 1 | 2;
15
+ /**
16
+ * Atmospheric depth, expressed as numbers a shader can use.
17
+ *
18
+ * Every value here is affine or per-plane uniform — nothing per-element and
19
+ * nothing perspective — so the visual language survives whichever way the
20
+ * platform settles the perspective question. Blur and contrast falloff are
21
+ * near-free in a shader and expensive in CSS, which is what justifies the GPU
22
+ * pipeline at all.
23
+ */
24
+ export interface PlaneStyle {
25
+ /** Uniform scale. Recession, without foreshortening. */
26
+ readonly scale: number;
27
+ /** Gaussian radius in texels. */
28
+ readonly blur: number;
29
+ /** 0 = full contrast, 1 = fully dissolved into the ground colour. */
30
+ readonly falloff: number;
31
+ /** Drop-shadow opacity separating this plane from the one behind it. */
32
+ readonly shadow: number;
33
+ /** Fidelity the plane asks its views for. */
34
+ readonly fidelity: "full" | "summary" | "glyph";
35
+ }
36
+ export type Scheme = "light" | "dark";
37
+ /**
38
+ * Daylight recession.
39
+ *
40
+ * Not the dark numbers inverted. In daylight a distant thing loses CONTRAST
41
+ * and gains haze; it does not lose light, and it does not blur much — the eye
42
+ * reads distance from washed-out colour and a softer cast shadow. Reusing the
43
+ * dark blur here made receded planes look out of focus rather than far away.
44
+ */
45
+ export declare const LIGHT_PLANE_STYLES: Readonly<Record<PlaneIndex, PlaneStyle>>;
46
+ export declare const PLANE_STYLES: Readonly<Record<PlaneIndex, PlaneStyle>>;
47
+ export declare function styleFor(plane: number, scheme?: Scheme): PlaneStyle;
48
+ /**
49
+ * Interpolates between two plane styles. Every transition is animatable
50
+ * because both endpoints are the same small bag of numbers — the same reason
51
+ * any two layout states interpolate.
52
+ */
53
+ export declare function mixStyles(a: PlaneStyle, b: PlaneStyle, t: number): PlaneStyle;
54
+ /**
55
+ * The transform a view at `plane` gets, given where layout put it.
56
+ *
57
+ * Position is layout's, untouched. The plane contributes only treatment —
58
+ * scale, and through the shader blur, falloff and shadow.
59
+ *
60
+ * An earlier version scaled positions about the canvas centre as well, so a
61
+ * receded plane pulled inward. It looked plausible and was wrong: layout no
62
+ * longer knew where anything would end up, so connectors drawn from layout
63
+ * coordinates missed the views they connected. One owner per concern —
64
+ * layout owns position, the plane owns treatment — is what keeps the two
65
+ * halves of the picture agreeing.
66
+ */
67
+ export declare function transformFor(style: PlaneStyle, x: number, y: number, _canvasWidth?: number, _canvasHeight?: number): Matrix4;
68
+ //# sourceMappingURL=plane.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plane.d.ts","sourceRoot":"","sources":["../../src/scene/plane.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAErE;;;GAGG;AACH,eAAO,MAAM,MAAM;IACjB,yDAAyD;;IAEzD,yDAAyD;;IAEzD,4CAA4C;;CAEpC,CAAC;AAEX,MAAM,MAAM,UAAU,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAEnC;;;;;;;;GAQG;AACH,MAAM,WAAW,UAAU;IACzB,wDAAwD;IACxD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,iCAAiC;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,qEAAqE;IACrE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,wEAAwE;IACxE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,6CAA6C;IAC7C,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC;CACjD;AAED,MAAM,MAAM,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;AAEtC;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB,EAAE,QAAQ,CAAC,MAAM,CAAC,UAAU,EAAE,UAAU,CAAC,CAmBvE,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,UAAU,EAAE,UAAU,CAAC,CAejE,CAAC;AAEF,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,GAAE,MAAe,GAAG,UAAU,CAG3E;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,MAAM,GAAG,UAAU,CAU7E;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,UAAU,EACjB,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,YAAY,CAAC,EAAE,MAAM,EACrB,aAAa,CAAC,EAAE,MAAM,GACrB,OAAO,CAET"}
@@ -0,0 +1,94 @@
1
+ import { planeTransform } from "../platform/matrix.js";
2
+ /**
3
+ * Discrete z-planes with the camera locked to one axis. No free orbit: every
4
+ * view is nameable and returnable, which is what makes each stop a URL.
5
+ */
6
+ export const PLANES = {
7
+ /** Live, editable DOM. Captured every frame it moves. */
8
+ focus: 0,
9
+ /** The entity type you asked to see, with connectors. */
10
+ relations: 1,
11
+ /** Everything else, as aggregate blocks. */
12
+ context: 2,
13
+ };
14
+ /**
15
+ * Daylight recession.
16
+ *
17
+ * Not the dark numbers inverted. In daylight a distant thing loses CONTRAST
18
+ * and gains haze; it does not lose light, and it does not blur much — the eye
19
+ * reads distance from washed-out colour and a softer cast shadow. Reusing the
20
+ * dark blur here made receded planes look out of focus rather than far away.
21
+ */
22
+ export const LIGHT_PLANE_STYLES = {
23
+ 0: { scale: 1, blur: 0, falloff: 0, shadow: 0.16, fidelity: "full" },
24
+ 1: { scale: 0.95, blur: 0.3, falloff: 0.26, shadow: 0.12, fidelity: "summary" },
25
+ /*
26
+ * Depth comes from BLUR AND FALLOFF, not from shrinking.
27
+ *
28
+ * Pushing the scale to 0.6 did separate the planes and made the strip
29
+ * illegible — ten cards reading "P…", "REA…", "S…". A map you cannot read
30
+ * is not a map. The recession is carried by the atmosphere instead.
31
+ *
32
+ * 0.78 was still shrinking, and still too much: the layout allots each
33
+ * district a slot and the renderer drew it at 78% of it, so a name set at
34
+ * thirteen pixels reached the screen at ten and its kind at under eight.
35
+ * That is under every floor this project holds a control to, and it is a
36
+ * floor the reader's own text size could not lift either — the shrink
37
+ * came after it. The planes keep a shrink small enough to read as depth
38
+ * and no longer small enough to cost a word its legibility.
39
+ */
40
+ 2: { scale: 0.9, blur: 0.3, falloff: 0.34, shadow: 0.07, fidelity: "glyph" },
41
+ };
42
+ export const PLANE_STYLES = {
43
+ // The focus plane is unfiltered on purpose: everything else is judged
44
+ // against it, so it has to be the one true reading of the data.
45
+ 0: { scale: 1, blur: 0, falloff: 0, shadow: 0.34, fidelity: "full" },
46
+ // Plane 1 recedes but stays READABLE — its job is to be looked at next,
47
+ // not to be atmosphere. Enough separation to read as further away, little
48
+ // enough that a summary view can still be read.
49
+ 1: { scale: 0.95, blur: 0.45, falloff: 0.18, shadow: 0.24, fidelity: "summary" },
50
+ // Plane 2 is context, not content. It should register as presence and
51
+ // count, and reward a glance rather than a read.
52
+ //
53
+ // Blurrier than plane 1, necessarily: recession has to be monotonic or the
54
+ // depth cue inverts and the furthest plane reads as the nearest. This was
55
+ // briefly 0.6 against plane 1's 0.7, which `frame-plan.test.ts` caught.
56
+ 2: { scale: 0.9, blur: 0.45, falloff: 0.26, shadow: 0.14, fidelity: "glyph" },
57
+ };
58
+ export function styleFor(plane, scheme = "dark") {
59
+ const clamped = Math.max(0, Math.min(2, Math.round(plane)));
60
+ return (scheme === "light" ? LIGHT_PLANE_STYLES : PLANE_STYLES)[clamped];
61
+ }
62
+ /**
63
+ * Interpolates between two plane styles. Every transition is animatable
64
+ * because both endpoints are the same small bag of numbers — the same reason
65
+ * any two layout states interpolate.
66
+ */
67
+ export function mixStyles(a, b, t) {
68
+ const clamped = Math.max(0, Math.min(1, t));
69
+ const lerp = (x, y) => x + (y - x) * clamped;
70
+ return {
71
+ scale: lerp(a.scale, b.scale),
72
+ blur: lerp(a.blur, b.blur),
73
+ falloff: lerp(a.falloff, b.falloff),
74
+ shadow: lerp(a.shadow, b.shadow),
75
+ fidelity: clamped < 0.5 ? a.fidelity : b.fidelity,
76
+ };
77
+ }
78
+ /**
79
+ * The transform a view at `plane` gets, given where layout put it.
80
+ *
81
+ * Position is layout's, untouched. The plane contributes only treatment —
82
+ * scale, and through the shader blur, falloff and shadow.
83
+ *
84
+ * An earlier version scaled positions about the canvas centre as well, so a
85
+ * receded plane pulled inward. It looked plausible and was wrong: layout no
86
+ * longer knew where anything would end up, so connectors drawn from layout
87
+ * coordinates missed the views they connected. One owner per concern —
88
+ * layout owns position, the plane owns treatment — is what keeps the two
89
+ * halves of the picture agreeing.
90
+ */
91
+ export function transformFor(style, x, y, _canvasWidth, _canvasHeight) {
92
+ return planeTransform(style.scale, x, y);
93
+ }
94
+ //# sourceMappingURL=plane.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plane.js","sourceRoot":"","sources":["../../src/scene/plane.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,67 @@
1
1
  {
2
2
  "name": "@graview/render",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "default": "./dist/index.js"
11
+ },
12
+ "./gpu": {
13
+ "types": "./dist/gpu.d.ts",
14
+ "default": "./dist/gpu.js"
15
+ }
16
+ },
17
+ "dependencies": {
18
+ "@graview/core": "0.1.0",
19
+ "@graview/layout": "0.1.0"
20
+ },
21
+ "peerDependencies": {
22
+ "@webgpu/types": "^0.1.60"
23
+ },
24
+ "peerDependenciesMeta": {
25
+ "@webgpu/types": {
26
+ "optional": true
27
+ }
28
+ },
29
+ "devDependencies": {
30
+ "zod": "^4.4.3"
31
+ },
32
+ "description": "The spatial renderer. The DOM path is what ships; the GPU capture path is EXPERIMENTAL — see README.",
33
+ "keywords": [
34
+ "graview",
35
+ "context-graph",
36
+ "typed-graph",
37
+ "interface",
38
+ "declarative",
39
+ "renderer",
40
+ "canvas",
41
+ "webgpu"
42
+ ],
43
+ "files": [
44
+ "dist",
45
+ "README.md"
46
+ ],
47
+ "sideEffects": false,
48
+ "repository": {
49
+ "type": "git",
50
+ "url": "git+https://github.com/en-dash-consulting/graview.git",
51
+ "directory": "packages/render"
52
+ },
53
+ "publishConfig": {
54
+ "access": "public"
55
+ },
56
+ "license": "Elastic-2.0",
57
+ "homepage": "https://graview.dev/docs/packages/render.html",
58
+ "bugs": {
59
+ "url": "https://github.com/en-dash-consulting/graview/issues"
60
+ },
61
+ "engines": {
62
+ "node": ">=22"
63
+ },
64
+ "scripts": {
65
+ "build": "tsc -b"
66
+ }
6
67
  }