pmx-canvas 0.7.2 → 0.8.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.
- package/.github/extensions/pmx-canvas/THIRD_PARTY_LICENSES.txt +331 -0
- package/.github/extensions/pmx-canvas/extension.mjs +25 -172
- package/.github/extensions/pmx-canvas/mcp-bootstrap.ts +198 -0
- package/.github/extensions/pmx-canvas/runtime.d.mts +41 -0
- package/.github/extensions/pmx-canvas/runtime.json +3 -0
- package/.github/extensions/pmx-canvas/runtime.mjs +194 -0
- package/.github/extensions/pmx-canvas/start-mcp.mjs +51 -0
- package/.github/extensions/pmx-canvas/tools.json +2560 -0
- package/CHANGELOG.md +60 -0
- package/Readme.md +44 -16
- package/dist/canvas/fonts/OFL.txt +93 -0
- package/dist/canvas/fonts/ibm-plex-mono-latin-400-normal.woff2 +0 -0
- package/dist/canvas/fonts/ibm-plex-mono-latin-500-normal.woff2 +0 -0
- package/dist/canvas/fonts/ibm-plex-mono-latin-ext-400-normal.woff2 +0 -0
- package/dist/canvas/fonts/ibm-plex-mono-latin-ext-500-normal.woff2 +0 -0
- package/dist/canvas/fonts/ibm-plex-sans-latin-400-normal.woff2 +0 -0
- package/dist/canvas/fonts/ibm-plex-sans-latin-500-normal.woff2 +0 -0
- package/dist/canvas/fonts/ibm-plex-sans-latin-600-normal.woff2 +0 -0
- package/dist/canvas/fonts/ibm-plex-sans-latin-ext-400-normal.woff2 +0 -0
- package/dist/canvas/fonts/ibm-plex-sans-latin-ext-500-normal.woff2 +0 -0
- package/dist/canvas/fonts/ibm-plex-sans-latin-ext-600-normal.woff2 +0 -0
- package/dist/canvas/global.css +844 -710
- package/dist/canvas/index.js +92 -90
- package/dist/canvas/mcp-app.html +7878 -0
- package/dist/canvas/mermaid-entry.js +1 -1
- package/dist/canvas/surface-theme.css +151 -46
- package/dist/json-render/index.css +1 -1
- package/dist/json-render/index.js +55 -55
- package/dist/types/cli/commands/record.d.ts +1 -1
- package/dist/types/client/canvas/ChoiceMenu.d.ts +13 -0
- package/dist/types/client/canvas/NodeContextMark.d.ts +24 -0
- package/dist/types/client/canvas/SessionReceipt.d.ts +3 -1
- package/dist/types/client/icons.d.ts +1 -2
- package/dist/types/client/mcp-app/index.d.ts +1 -0
- package/dist/types/client/nodes/McpAppNode.d.ts +2 -1
- package/dist/types/client/nodes/ax-node-actions.d.ts +2 -2
- package/dist/types/client/nodes/markdown-sanitize.d.ts +2 -0
- package/dist/types/client/nodes/use-workbench-asset.d.ts +2 -0
- package/dist/types/client/nodes/viewer-runtime-state.d.ts +1 -0
- package/dist/types/client/state/attention-store.d.ts +0 -5
- package/dist/types/client/state/canvas-store.d.ts +2 -0
- package/dist/types/client/state/context-status-store.d.ts +53 -0
- package/dist/types/client/state/intent-bridge.d.ts +4 -1
- package/dist/types/client/state/near-pin-store.d.ts +16 -0
- package/dist/types/client/state/presence-store.d.ts +5 -0
- package/dist/types/client/state/session-store.d.ts +33 -3
- package/dist/types/client/state/workbench-transport.d.ts +16 -0
- package/dist/types/client/theme/tokens.d.ts +1 -3
- package/dist/types/client/types.d.ts +9 -0
- package/dist/types/json-render/renderer/index.d.ts +2 -1
- package/dist/types/json-render/server.d.ts +3 -1
- package/dist/types/mcp/app-server.d.ts +3 -0
- package/dist/types/mcp/canvas-access.d.ts +1 -1
- package/dist/types/mcp/canvas-app.d.ts +4 -0
- package/dist/types/mcp/workbench-app.d.ts +4 -0
- package/dist/types/server/agent-presence.d.ts +1 -1
- package/dist/types/server/ax-state.d.ts +1 -1
- package/dist/types/server/canvas-db.d.ts +8 -0
- package/dist/types/server/canvas-geometry.d.ts +25 -0
- package/dist/types/server/canvas-operations.d.ts +1 -11
- package/dist/types/server/canvas-state.d.ts +25 -3
- package/dist/types/server/context-brief.d.ts +8 -1
- package/dist/types/server/context-reads.d.ts +30 -7
- package/dist/types/server/index.d.ts +6 -1
- package/dist/types/server/mcp-app-runtime.d.ts +1 -0
- package/dist/types/server/operations/http.d.ts +2 -0
- package/dist/types/server/operations/invoker.d.ts +4 -2
- package/dist/types/server/operations/ops/nodes.d.ts +0 -6
- package/dist/types/server/server.d.ts +1 -0
- package/dist/types/server/spatial-analysis.d.ts +2 -0
- package/dist/types/shared/agent-context.d.ts +22 -0
- package/dist/types/shared/agent-presence.d.ts +3 -10
- package/dist/types/shared/ax-surface-protocol.d.ts +2 -0
- package/dist/types/shared/canvas-app.d.ts +54 -0
- package/dist/types/shared/themes.d.ts +1 -1
- package/docs/RELEASE.md +7 -3
- package/docs/agent-plugin.md +123 -0
- package/docs/ax-host-adapter-contract.md +13 -2
- package/docs/ax-state-contract.md +40 -0
- package/docs/cli.md +7 -2
- package/docs/design/AgentContext.dc.html +186 -0
- package/docs/design/Before.dc.html +208 -0
- package/docs/design/BoardPins.dc.html +151 -0
- package/docs/design/Chrome.dc.html +208 -0
- package/docs/design/Context.dc.html +239 -0
- package/docs/design/Flows.dc.html +181 -0
- package/docs/design/Home.dc.html +209 -0
- package/docs/design/HomeGraph.dc.html +211 -0
- package/docs/design/HomeMap.dc.html +117 -0
- package/docs/design/HomeTeam.dc.html +176 -0
- package/docs/design/Light.dc.html +28 -0
- package/docs/design/Main.dc.html +280 -0
- package/docs/design/NearPin.dc.html +260 -0
- package/docs/design/Pane600.dc.html +120 -0
- package/docs/design/Relations.dc.html +297 -0
- package/docs/design/Themes.dc.html +121 -0
- package/docs/design/TokenSystem.dc.html +136 -0
- package/docs/design/Tokens.dc.html +163 -0
- package/docs/design/Types1.dc.html +177 -0
- package/docs/design/Types2.dc.html +226 -0
- package/docs/design/Types3.dc.html +195 -0
- package/docs/design/Uses.dc.html +152 -0
- package/docs/design/Vision.dc.html +116 -0
- package/docs/design/Zoom.dc.html +82 -0
- package/docs/design/canvas.json +274 -0
- package/docs/design.md +214 -0
- package/docs/environment.md +1 -1
- package/docs/http-api.md +80 -15
- package/docs/mcp.md +198 -3
- package/docs/node-types.md +34 -10
- package/docs/plans/plan-009-tech-debt-backlog.md +1 -1
- package/docs/plans/plan-015-design-foundation-wave-0.md +177 -0
- package/docs/plans/plan-016-context-made-visible-wave-1.md +148 -0
- package/docs/product-vision-2026-09.md +47 -7
- package/docs/screenshot.png +0 -0
- package/docs/sdk.md +1 -0
- package/package.json +10 -4
- package/plugins/pmx-canvas/LICENSE +21 -0
- package/plugins/pmx-canvas/THIRD_PARTY_LICENSES.txt +331 -0
- package/plugins/pmx-canvas/assets/preview.png +0 -0
- package/plugins/pmx-canvas/com.github.copilot/extensions/pmx-canvas/extension.mjs +930 -0
- package/plugins/pmx-canvas/com.github.copilot/extensions/pmx-canvas/runtime.json +3 -0
- package/plugins/pmx-canvas/com.github.copilot/extensions/pmx-canvas/runtime.mjs +194 -0
- package/plugins/pmx-canvas/com.github.copilot/extensions/pmx-canvas/steering-delivery.mjs +79 -0
- package/plugins/pmx-canvas/mcp.json +12 -0
- package/plugins/pmx-canvas/plugin.json +24 -0
- package/plugins/pmx-canvas/runtime.json +3 -0
- package/plugins/pmx-canvas/runtime.mjs +194 -0
- package/plugins/pmx-canvas/start-mcp.mjs +51 -0
- package/plugins/pmx-canvas/tools.json +2560 -0
- package/skills/pmx-canvas/SKILL.md +31 -16
- package/skills/pmx-canvas/evals/evals.json +69 -0
- package/skills/pmx-canvas/references/full-reference.md +14 -10
- package/skills/pmx-canvas/references/github-copilot-app-adapter.md +20 -8
- package/skills/pmx-canvas/references/installing-pmx-canvas.md +76 -4
- package/skills/pmx-canvas-testing/SKILL.md +54 -4
- package/src/cli/commands/copilot.ts +5 -0
- package/src/cli/commands/view.ts +1 -1
- package/src/cli/index.ts +8 -3
- package/src/client/App.tsx +6 -1
- package/src/client/canvas/AgentPresenceLayer.tsx +3 -3
- package/src/client/canvas/AnnotationLayer.tsx +1 -1
- package/src/client/canvas/CanvasNode.tsx +208 -220
- package/src/client/canvas/CanvasViewport.tsx +6 -2
- package/src/client/canvas/ChoiceMenu.tsx +122 -0
- package/src/client/canvas/CommandBar.tsx +25 -23
- package/src/client/canvas/CommandPalette.tsx +3 -2
- package/src/client/canvas/ContextMenu.tsx +11 -0
- package/src/client/canvas/EdgeLayer.tsx +1 -1
- package/src/client/canvas/ExportDialog.tsx +33 -6
- package/src/client/canvas/FeedbackDialog.tsx +10 -8
- package/src/client/canvas/IntentLayer.tsx +2 -2
- package/src/client/canvas/Minimap.tsx +12 -7
- package/src/client/canvas/NodeContextMark.tsx +156 -0
- package/src/client/canvas/SessionPanel.tsx +4 -7
- package/src/client/canvas/SessionReceipt.tsx +114 -17
- package/src/client/canvas/ShortcutOverlay.tsx +6 -1
- package/src/client/canvas/SnapshotPanel.tsx +11 -2
- package/src/client/canvas/ToolRail.tsx +58 -108
- package/src/client/canvas/TopBar.tsx +16 -11
- package/src/client/icons.tsx +2 -12
- package/src/client/mcp-app/index.tsx +137 -0
- package/src/client/mcp-app/style.css +10 -0
- package/src/client/nodes/AttachmentNode.tsx +8 -1
- package/src/client/nodes/AxStepControls.tsx +1 -1
- package/src/client/nodes/ContextNode.tsx +9 -9
- package/src/client/nodes/ExtAppFrame.tsx +13 -8
- package/src/client/nodes/FileNode.tsx +8 -5
- package/src/client/nodes/ImageNode.tsx +4 -2
- package/src/client/nodes/InlineMarkdownEditor.tsx +2 -1
- package/src/client/nodes/LedgerNode.tsx +2 -2
- package/src/client/nodes/MarkdownNode.tsx +44 -9
- package/src/client/nodes/McpAppNode.tsx +22 -4
- package/src/client/nodes/PromptNode.tsx +5 -17
- package/src/client/nodes/ResponseNode.tsx +3 -15
- package/src/client/nodes/StatusNode.tsx +2 -2
- package/src/client/nodes/StatusSummary.tsx +3 -1
- package/src/client/nodes/TraceNode.tsx +6 -4
- package/src/client/nodes/WebpageNode.tsx +1 -1
- package/src/client/nodes/ax-node-actions.ts +2 -2
- package/src/client/nodes/iframe-document-url.ts +3 -2
- package/src/client/nodes/markdown-sanitize.ts +10 -0
- package/src/client/nodes/surface-url.ts +10 -0
- package/src/client/nodes/use-ax-surface-bridge.ts +4 -2
- package/src/client/nodes/use-surface-frame.ts +3 -1
- package/src/client/nodes/use-workbench-asset.ts +26 -0
- package/src/client/nodes/viewer-runtime-state.ts +78 -0
- package/src/client/state/attention-bridge.ts +0 -8
- package/src/client/state/attention-store.ts +0 -17
- package/src/client/state/canvas-store.ts +7 -2
- package/src/client/state/context-status-store.ts +66 -0
- package/src/client/state/human-store.ts +2 -0
- package/src/client/state/iframe-mode.ts +5 -0
- package/src/client/state/intent-bridge.ts +24 -6
- package/src/client/state/near-pin-store.ts +53 -0
- package/src/client/state/presence-store.ts +5 -10
- package/src/client/state/session-store.ts +106 -9
- package/src/client/state/sse-bridge.ts +26 -7
- package/src/client/state/theme-override.ts +1 -1
- package/src/client/state/workbench-transport.ts +36 -0
- package/src/client/theme/global.css +844 -710
- package/src/client/theme/surface-theme.css +151 -46
- package/src/client/theme/tokens.ts +7 -11
- package/src/client/types.ts +10 -0
- package/src/json-render/renderer/index.tsx +58 -38
- package/src/json-render/server.ts +79 -15
- package/src/mcp/app-server.ts +64 -0
- package/src/mcp/canvas-access.ts +14 -11
- package/src/mcp/canvas-app.ts +318 -0
- package/src/mcp/server.ts +1 -1
- package/src/mcp/workbench-app.ts +211 -0
- package/src/server/agent-presence.ts +45 -6
- package/src/server/ax-context.ts +1 -1
- package/src/server/ax-state.ts +1 -1
- package/src/server/board-export.ts +5 -2
- package/src/server/canvas-db.ts +46 -12
- package/src/server/canvas-geometry.ts +64 -0
- package/src/server/canvas-operations.ts +6 -24
- package/src/server/canvas-state.ts +105 -15
- package/src/server/canvas-validation.ts +19 -4
- package/src/server/context-brief.ts +39 -2
- package/src/server/context-reads.ts +86 -15
- package/src/server/demo-state.json +31 -31
- package/src/server/html-surface.ts +4 -5
- package/src/server/index.ts +19 -3
- package/src/server/mcp-app-runtime.ts +11 -0
- package/src/server/operations/composites.ts +4 -3
- package/src/server/operations/http.ts +4 -4
- package/src/server/operations/invoker.ts +13 -4
- package/src/server/operations/ops/ax-read.ts +1 -1
- package/src/server/operations/ops/ax-timeline.ts +37 -0
- package/src/server/operations/ops/boards.ts +1 -1
- package/src/server/operations/ops/canvas-wire.ts +3 -6
- package/src/server/operations/ops/intent.ts +31 -2
- package/src/server/operations/ops/json-render.ts +1 -1
- package/src/server/operations/ops/nodes.ts +8 -76
- package/src/server/operations/ops/query.ts +8 -2
- package/src/server/operations/ops/snapshots.ts +4 -1
- package/src/server/operations/ops/viewport.ts +29 -5
- package/src/server/operations/registry.ts +38 -4
- package/src/server/scope-fence.ts +55 -10
- package/src/server/server.ts +86 -6
- package/src/server/spatial-analysis.ts +2 -2
- package/src/server/workboard.ts +6 -1
- package/src/{server → shared}/agent-context.ts +2 -2
- package/src/shared/agent-presence.ts +3 -15
- package/src/shared/ax-surface-protocol.ts +3 -0
- package/src/shared/canvas-app.ts +62 -0
- package/src/shared/themes.ts +5 -5
- package/src/client/canvas/FocusFieldLayer.tsx +0 -116
- package/src/client/canvas/kind-colors.ts +0 -23
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<title>Relations</title>
|
|
6
|
+
<script src="./support.js"></script>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<x-dc>
|
|
10
|
+
<helmet>
|
|
11
|
+
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500&family=IBM+Plex+Sans:wght@400;500;600&display=swap">
|
|
12
|
+
<style>
|
|
13
|
+
body{margin:0}
|
|
14
|
+
</style>
|
|
15
|
+
</helmet>
|
|
16
|
+
<div style="width: 1440px; height: 1340px; box-sizing: border-box; padding: 48px 56px; background: #081524; color: #e6eef7; font-family: 'IBM Plex Sans', system-ui, sans-serif; font-size: 13px; line-height: 1.5; display: flex; flex-direction: column; gap: 32px">
|
|
17
|
+
|
|
18
|
+
<div>
|
|
19
|
+
<h1 style="margin: 0; font-size: 28px; font-weight: 600; letter-spacing: -0.015em">Relations</h1>
|
|
20
|
+
<p style="margin: 4px 0 0; font-size: 13px; color: #8ea3bd">A research board: one question, two findings, the evidence and the data behind them. Relations should say what supports a claim, what contradicts it, and where each number came from.</p>
|
|
21
|
+
</div>
|
|
22
|
+
|
|
23
|
+
<section style="display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 40px">
|
|
24
|
+
|
|
25
|
+
<div style="display: flex; flex-direction: column; gap: 8px">
|
|
26
|
+
<span style="font-size: 11px; font-weight: 500; letter-spacing: 0.06em; text-transform: uppercase; color: #6b7d94">Today — hovering the question</span>
|
|
27
|
+
<div style="position: relative; width: 644px; height: 600px; border-radius: 10px; border: 1px solid #1b2c44; overflow: hidden; background-color: #081524; background-image: radial-gradient(rgba(142,163,189,0.10) 1px, transparent 1.2px); background-size: 24px 24px; font-family: -apple-system, 'SF Pro Text', system-ui, sans-serif">
|
|
28
|
+
<svg width="644" height="600" viewBox="0 0 644 600" style="position: absolute; left: 0; top: 0; overflow: visible; fill: none; stroke-linecap: round">
|
|
29
|
+
<path d="{{t.e0.d}}" style="stroke: {{t.e0.c}}; stroke-width: 1.5; opacity: {{t.e0.o}}"></path><path d="{{t.e0.h}}" style="fill: {{t.e0.c}}; stroke: none; opacity: {{t.e0.ho}}"></path>
|
|
30
|
+
<path d="{{t.e1.d}}" style="stroke: {{t.e1.c}}; stroke-width: 1.5; opacity: {{t.e1.o}}"></path><path d="{{t.e1.h}}" style="fill: {{t.e1.c}}; stroke: none; opacity: {{t.e1.ho}}"></path>
|
|
31
|
+
<path d="{{t.e2.d}}" style="stroke: {{t.e2.c}}; stroke-width: 1.5; opacity: {{t.e2.o}}"></path><path d="{{t.e2.h}}" style="fill: {{t.e2.c}}; stroke: none; opacity: {{t.e2.ho}}"></path>
|
|
32
|
+
<path d="{{t.e3.d}}" style="stroke: {{t.e3.c}}; stroke-width: 1.5; opacity: {{t.e3.o}}"></path><path d="{{t.e3.h}}" style="fill: {{t.e3.c}}; stroke: none; opacity: {{t.e3.ho}}"></path>
|
|
33
|
+
<path d="{{t.e4.d}}" style="stroke: {{t.e4.c}}; stroke-width: 1.5; opacity: {{t.e4.o}}"></path><path d="{{t.e4.h}}" style="fill: {{t.e4.c}}; stroke: none; opacity: {{t.e4.ho}}"></path>
|
|
34
|
+
<path d="{{t.e5.d}}" style="stroke: {{t.e5.c}}; stroke-width: 1.5; opacity: {{t.e5.o}}"></path><path d="{{t.e5.h}}" style="fill: {{t.e5.c}}; stroke: none; opacity: {{t.e5.ho}}"></path>
|
|
35
|
+
<path d="{{t.e6.d}}" style="stroke: {{t.e6.c}}; stroke-width: 1.5; opacity: {{t.e6.o}}"></path><path d="{{t.e6.h}}" style="fill: {{t.e6.c}}; stroke: none; opacity: {{t.e6.ho}}"></path>
|
|
36
|
+
<path d="{{t.e7.d}}" style="stroke: {{t.e7.c}}; stroke-width: 1.5; opacity: {{t.e7.o}}"></path><path d="{{t.e7.h}}" style="fill: {{t.e7.c}}; stroke: none; opacity: {{t.e7.ho}}"></path>
|
|
37
|
+
<path d="{{t.e8.d}}" style="stroke: {{t.e8.c}}; stroke-width: 1.5; opacity: {{t.e8.o}}"></path><path d="{{t.e8.h}}" style="fill: {{t.e8.c}}; stroke: none; opacity: {{t.e8.ho}}"></path>
|
|
38
|
+
</svg>
|
|
39
|
+
<sc-for list="{{tLabels}}" as="l" hint-placeholder-count="9">
|
|
40
|
+
<span style="position: absolute; left: {{l.x}}px; top: {{l.y}}px; width: {{l.w}}px; height: 20px; box-sizing: border-box; border-radius: 4px; border: 0.5px solid #1b2c44; background: rgba(15,29,49,0.85); font-size: 11px; line-height: 19px; text-align: center; color: #e6eef7; opacity: {{l.o}}">{{l.text}}</span>
|
|
41
|
+
</sc-for>
|
|
42
|
+
<sc-for list="{{tNodes}}" as="nd" hint-placeholder-count="7">
|
|
43
|
+
<div style="position: absolute; left: {{nd.x}}px; top: {{nd.y}}px; width: 160px; height: 56px; box-sizing: border-box; border-radius: 12px 12px 8px 8px; border: 1px solid {{nd.border}}; background: #0f1d31; box-shadow: 0 4px 24px rgba(0,0,0,0.3); overflow: hidden">
|
|
44
|
+
<div style="height: 24px; padding: 0 8px; display: flex; align-items: center; background: #0b1828; border-bottom: 1px solid #1b2c44; font-size: 11px; font-weight: 600">{{nd.title}}</div>
|
|
45
|
+
<div style="padding: 3px 8px; font-size: 9.5px; color: #8ea3bd">{{nd.meta}}</div>
|
|
46
|
+
</div>
|
|
47
|
+
</sc-for>
|
|
48
|
+
</div>
|
|
49
|
+
<span style="font-size: 12px; color: #ff8a9b">Supports, contradicts and cites are the same grey line; only the pill text tells them apart. The two links between the first finding and the question sit exactly on top of each other.</span>
|
|
50
|
+
</div>
|
|
51
|
+
|
|
52
|
+
<div style="display: flex; flex-direction: column; gap: 8px">
|
|
53
|
+
<span style="font-size: 11px; font-weight: 500; letter-spacing: 0.06em; text-transform: uppercase; color: #6b7d94">Proposed — hovering the question</span>
|
|
54
|
+
<div style="position: relative; width: 644px; height: 600px; border-radius: 10px; border: 1px solid #1b2c44; overflow: hidden; background-color: #081524; background-image: radial-gradient(rgba(142,163,189,0.14) 1px, transparent 1.2px); background-size: 24px 24px">
|
|
55
|
+
<div style="position: absolute; left: 14px; top: 12px; right: 14px; display: flex; align-items: center; gap: 6px; flex-wrap: wrap">
|
|
56
|
+
<sc-for list="{{legend}}" as="lg" hint-placeholder-count="6">
|
|
57
|
+
<button style="display: flex; align-items: center; gap: 6px; height: 24px; padding: 0 9px; border-radius: 999px; border: 1px solid #1b2c44; background: #0f1d31; color: #e6eef7; font-family: inherit; font-size: 11px; font-weight: 500"><svg width="18" height="6" viewBox="0 0 18 6" style="fill: none; stroke: {{lg.c}}; stroke-width: 2; stroke-dasharray: {{lg.dash}}; stroke-linecap: round"><path d="M1 3 H17"></path></svg>{{lg.name}}<span style="color: #6b7d94; font-variant-numeric: tabular-nums">{{lg.n}}</span></button>
|
|
58
|
+
</sc-for>
|
|
59
|
+
</div>
|
|
60
|
+
<svg width="644" height="600" viewBox="0 0 644 600" style="position: absolute; left: 0; top: 0; overflow: visible; fill: none; stroke-linecap: round">
|
|
61
|
+
<path d="{{p.e0.d}}" style="stroke: {{p.e0.c}}; stroke-width: {{p.e0.w}}; opacity: {{p.e0.o}}; stroke-dasharray: {{p.e0.dash}}"></path><path d="{{p.e0.h}}" style="fill: {{p.e0.c}}; stroke: none; opacity: {{p.e0.o}}"></path>
|
|
62
|
+
<path d="{{p.e1.d}}" style="stroke: {{p.e1.c}}; stroke-width: {{p.e1.w}}; opacity: {{p.e1.o}}; stroke-dasharray: {{p.e1.dash}}"></path><path d="{{p.e1.h}}" style="fill: {{p.e1.c}}; stroke: none; opacity: {{p.e1.o}}"></path>
|
|
63
|
+
<path d="{{p.e2.d}}" style="stroke: {{p.e2.c}}; stroke-width: {{p.e2.w}}; opacity: {{p.e2.o}}; stroke-dasharray: {{p.e2.dash}}"></path><path d="{{p.e2.h}}" style="fill: {{p.e2.c}}; stroke: none; opacity: {{p.e2.o}}"></path>
|
|
64
|
+
<path d="{{p.e3.d}}" style="stroke: {{p.e3.c}}; stroke-width: {{p.e3.w}}; opacity: {{p.e3.o}}; stroke-dasharray: {{p.e3.dash}}"></path><path d="{{p.e3.h}}" style="fill: {{p.e3.c}}; stroke: none; opacity: {{p.e3.o}}"></path>
|
|
65
|
+
<path d="{{p.e4.d}}" style="stroke: {{p.e4.c}}; stroke-width: {{p.e4.w}}; opacity: {{p.e4.o}}; stroke-dasharray: {{p.e4.dash}}"></path><path d="{{p.e4.h}}" style="fill: {{p.e4.c}}; stroke: none; opacity: {{p.e4.o}}"></path>
|
|
66
|
+
<path d="{{p.e5.d}}" style="stroke: {{p.e5.c}}; stroke-width: {{p.e5.w}}; opacity: {{p.e5.o}}; stroke-dasharray: {{p.e5.dash}}"></path><path d="{{p.e5.h}}" style="fill: {{p.e5.c}}; stroke: none; opacity: {{p.e5.o}}"></path>
|
|
67
|
+
<path d="{{p.e6.d}}" style="stroke: {{p.e6.c}}; stroke-width: {{p.e6.w}}; opacity: {{p.e6.o}}; stroke-dasharray: {{p.e6.dash}}"></path><path d="{{p.e6.h}}" style="fill: {{p.e6.c}}; stroke: none; opacity: {{p.e6.o}}"></path>
|
|
68
|
+
<path d="{{p.e7.d}}" style="stroke: {{p.e7.c}}; stroke-width: {{p.e7.w}}; opacity: {{p.e7.o}}; stroke-dasharray: {{p.e7.dash}}"></path><path d="{{p.e7.h}}" style="fill: {{p.e7.c}}; stroke: none; opacity: {{p.e7.o}}"></path>
|
|
69
|
+
<path d="{{p.e8.d}}" style="stroke: {{p.e8.c}}; stroke-width: {{p.e8.w}}; opacity: {{p.e8.o}}; stroke-dasharray: {{p.e8.dash}}"></path><path d="{{p.e8.h}}" style="fill: {{p.e8.c}}; stroke: none; opacity: {{p.e8.o}}"></path>
|
|
70
|
+
</svg>
|
|
71
|
+
<span style="position: absolute; left: 512px; top: 300px; height: 18px; padding: 0 6px; border-radius: 999px; border: 1px solid #2a4566; background: #0f1d31; font-size: 11px; font-weight: 600; line-height: 16px; color: #e6eef7">2</span>
|
|
72
|
+
<sc-for list="{{pNodes}}" as="nd" hint-placeholder-count="7">
|
|
73
|
+
<div style="position: absolute; left: {{nd.x}}px; top: {{nd.y}}px; width: 160px; height: 56px; box-sizing: border-box; padding: 8px 12px; border-radius: 10px; border: {{nd.border}}; background: #0f1d31; box-shadow: {{nd.shadow}}; opacity: {{nd.o}}; display: flex; flex-direction: column; justify-content: center">
|
|
74
|
+
<span style="font-size: 12px; font-weight: 600; line-height: 1.3">{{nd.title}}</span>
|
|
75
|
+
<span style="font-size: 11px; color: #8ea3bd">{{nd.meta}}</span>
|
|
76
|
+
</div>
|
|
77
|
+
</sc-for>
|
|
78
|
+
<span style="position: absolute; left: 252px; top: 166px; height: 18px; padding: 0 6px; border-radius: 999px; border: 1px solid #2a4566; background: #0f1d31; font-size: 11px; font-weight: 600; line-height: 16px; color: #e6eef7">2</span>
|
|
79
|
+
<div style="position: absolute; left: 418px; top: 96px; width: 214px; box-sizing: border-box; padding: 10px 12px; border-radius: 10px; border: 1px solid #2a4566; background: #13243b; box-shadow: 0 10px 30px rgba(0,0,0,0.55); display: flex; flex-direction: column; gap: 4px">
|
|
80
|
+
<span style="font-size: 12px; font-weight: 600">SMB is price-sensitive → Raise Pro to $24?</span>
|
|
81
|
+
<span style="display: flex; align-items: center; gap: 6px; font-size: 11px; color: #E59B6B"><svg width="16" height="6" viewBox="0 0 16 6" style="fill: none; stroke: #E59B6B; stroke-width: 2; stroke-linecap: round"><path d="M1 3 H15"></path></svg>contradicts</span>
|
|
82
|
+
<span style="font-size: 11px; color: #b9c6d6">6 of 9 SMB interviewees would downgrade at $24.</span>
|
|
83
|
+
</div>
|
|
84
|
+
</div>
|
|
85
|
+
<span style="font-size: 12px; color: #8ea3bd">Hovering the question shows what supports it (teal) and what contradicts it (coral); the sources and data step back. Each link carries its reason.</span>
|
|
86
|
+
</div>
|
|
87
|
+
|
|
88
|
+
</section>
|
|
89
|
+
|
|
90
|
+
<section style="display: flex; flex-direction: column; gap: 12px">
|
|
91
|
+
<h2 style="margin: 0; font-size: 15px; font-weight: 600">Edge anatomy</h2>
|
|
92
|
+
<div style="display: grid; grid-template-columns: 100px repeat(5, minmax(0, 1fr)); column-gap: 12px; row-gap: 10px; align-items: center">
|
|
93
|
+
<span></span>
|
|
94
|
+
<span style="{{a.h}}">Two links, same pair</span>
|
|
95
|
+
<span style="{{a.h}}">Many into one</span>
|
|
96
|
+
<span style="{{a.h}}">Label</span>
|
|
97
|
+
<span style="{{a.h}}">Added by the agent</span>
|
|
98
|
+
<span style="{{a.h}}">Selected</span>
|
|
99
|
+
|
|
100
|
+
<span style="font-size: 12px; font-weight: 600">Today</span>
|
|
101
|
+
<div style="{{a.cell}}">
|
|
102
|
+
<svg width="220" height="110" viewBox="0 0 220 110" style="position: absolute; left: 0; top: 0; fill: none; stroke-linecap: round"><path d="M 60 55 C 100 55, 120 55, 160 55" style="stroke: #8ea3bd; stroke-width: 1.5; opacity: 0.85"></path></svg>
|
|
103
|
+
<div style="{{a.box}} left: 14px; top: 41px">A</div><div style="{{a.box}} left: 160px; top: 41px">B</div>
|
|
104
|
+
<span style="{{a.oldLabel}} left: 82px; top: 45px">supports</span><span style="{{a.oldLabel}} left: 86px; top: 47px">cites</span>
|
|
105
|
+
</div>
|
|
106
|
+
<div style="{{a.cell}}">
|
|
107
|
+
<svg width="220" height="110" viewBox="0 0 220 110" style="position: absolute; left: 0; top: 0; fill: none; stroke-linecap: round"><path d="M 40 30 C 40 60, 104 50, 108 78" style="stroke: #4BBCFF; stroke-width: 1.5; opacity: 0.85"></path><path d="M 110 30 C 110 50, 110 60, 110 78" style="stroke: #4BBCFF; stroke-width: 1.5; opacity: 0.85"></path><path d="M 180 30 C 180 60, 116 50, 112 78" style="stroke: #4BBCFF; stroke-width: 1.5; opacity: 0.85"></path><path d="M 106 72 L 110 80 L 114 72 Z" style="fill: #4BBCFF; stroke: none; opacity: 0.75"></path></svg>
|
|
108
|
+
<div style="{{a.box}} left: 20px; top: 8px">A</div><div style="{{a.box}} left: 90px; top: 8px">B</div><div style="{{a.box}} left: 160px; top: 8px">C</div><div style="{{a.box}} left: 80px; top: 80px; width: 60px">D</div>
|
|
109
|
+
</div>
|
|
110
|
+
<div style="{{a.cell}}">
|
|
111
|
+
<svg width="220" height="110" viewBox="0 0 220 110" style="position: absolute; left: 0; top: 0; fill: none; stroke-linecap: round"><path d="M 60 55 L 160 55" style="stroke: #8ea3bd; stroke-width: 1.5; opacity: 0.85"></path></svg>
|
|
112
|
+
<div style="{{a.box}} left: 14px; top: 41px">A</div><div style="{{a.box}} left: 160px; top: 41px">B</div>
|
|
113
|
+
<span style="{{a.oldLabel}} left: 72px; top: 45px; width: 76px">contradicts</span>
|
|
114
|
+
</div>
|
|
115
|
+
<div style="{{a.cell}}">
|
|
116
|
+
<svg width="220" height="110" viewBox="0 0 220 110" style="position: absolute; left: 0; top: 0; fill: none; stroke-linecap: round"><path d="M 60 55 L 158 55" style="stroke: #4BBCFF; stroke-width: 1.5; opacity: 0.85"></path><path d="M 152 51 L 160 55 L 152 59 Z" style="fill: #4BBCFF; stroke: none; opacity: 0.75"></path></svg>
|
|
117
|
+
<div style="{{a.box}} left: 14px; top: 41px">A</div><div style="{{a.box}} left: 160px; top: 41px">B</div>
|
|
118
|
+
<span style="position: absolute; left: 14px; bottom: 8px; font-size: 11px; color: #6b7d94">Looks like any other edge.</span>
|
|
119
|
+
</div>
|
|
120
|
+
<div style="{{a.cell}}">
|
|
121
|
+
<svg width="220" height="110" viewBox="0 0 220 110" style="position: absolute; left: 0; top: 0; fill: none; stroke-linecap: round"><path d="M 60 55 L 158 55" style="stroke: #4BBCFF; stroke-width: 6; opacity: 0.25"></path><path d="M 60 55 L 158 55" style="stroke: #4BBCFF; stroke-width: 3"></path></svg>
|
|
122
|
+
<div style="{{a.box}} left: 14px; top: 41px">A</div><div style="{{a.box}} left: 160px; top: 41px">B</div>
|
|
123
|
+
<span style="position: absolute; left: 14px; bottom: 8px; font-size: 11px; color: #6b7d94">Delete or double-click for a menu.</span>
|
|
124
|
+
</div>
|
|
125
|
+
|
|
126
|
+
<span style="font-size: 12px; font-weight: 600">Proposed</span>
|
|
127
|
+
<div style="{{a.cell}}">
|
|
128
|
+
<svg width="220" height="110" viewBox="0 0 220 110" style="position: absolute; left: 0; top: 0; fill: none; stroke-linecap: round"><path d="M 60 48 L 156 48" style="stroke: #5FCFC0; stroke-width: 1.75"></path><path d="M 152 44 L 160 48 L 152 52 Z" style="fill: #5FCFC0; stroke: none"></path><path d="M 60 62 L 156 62" style="stroke: #7C9CFF; stroke-width: 1.75"></path><path d="M 152 58 L 160 62 L 152 66 Z" style="fill: #7C9CFF; stroke: none"></path></svg>
|
|
129
|
+
<div style="{{a.box}} left: 14px; top: 41px">A</div><div style="{{a.box}} left: 160px; top: 41px">B</div>
|
|
130
|
+
<span style="position: absolute; left: 84px; top: 24px; font-size: 11px; color: #5FCFC0">supports</span><span style="position: absolute; left: 94px; top: 68px; font-size: 11px; color: #7C9CFF">cites</span>
|
|
131
|
+
</div>
|
|
132
|
+
<div style="{{a.cell}}">
|
|
133
|
+
<svg width="220" height="110" viewBox="0 0 220 110" style="position: absolute; left: 0; top: 0; fill: none; stroke-linecap: round"><path d="M 40 30 C 40 56, 92 52, 92 76" style="stroke: #5FCFC0; stroke-width: 1.75"></path><path d="M 88 72 L 92 80 L 96 72 Z" style="fill: #5FCFC0; stroke: none"></path><path d="M 110 30 L 110 76" style="stroke: #5FCFC0; stroke-width: 1.75"></path><path d="M 106 72 L 110 80 L 114 72 Z" style="fill: #5FCFC0; stroke: none"></path><path d="M 180 30 C 180 56, 128 52, 128 76" style="stroke: #E59B6B; stroke-width: 1.75"></path><path d="M 124 72 L 128 80 L 132 72 Z" style="fill: #E59B6B; stroke: none"></path></svg>
|
|
134
|
+
<div style="{{a.box}} left: 20px; top: 8px">A</div><div style="{{a.box}} left: 90px; top: 8px">B</div><div style="{{a.box}} left: 160px; top: 8px">C</div><div style="{{a.box}} left: 80px; top: 80px; width: 60px">D</div>
|
|
135
|
+
</div>
|
|
136
|
+
<div style="{{a.cell}}">
|
|
137
|
+
<svg width="220" height="110" viewBox="0 0 220 110" style="position: absolute; left: 0; top: 0; fill: none; stroke-linecap: round"><path d="M 60 40 L 156 40" style="stroke: #E59B6B; stroke-width: 1.75"></path><path d="M 152 36 L 160 40 L 152 44 Z" style="fill: #E59B6B; stroke: none"></path></svg>
|
|
138
|
+
<div style="{{a.box}} left: 14px; top: 26px">A</div><div style="{{a.box}} left: 160px; top: 26px">B</div>
|
|
139
|
+
<span style="position: absolute; left: 78px; top: 18px; font-size: 11px; color: #E59B6B">contradicts</span>
|
|
140
|
+
<div style="position: absolute; left: 14px; top: 62px; right: 14px; padding: 5px 8px; border-radius: 6px; background: #13243b; border: 1px solid #2a4566; font-size: 11px; color: #b9c6d6">Why: 6 of 9 SMB interviewees would downgrade.</div>
|
|
141
|
+
</div>
|
|
142
|
+
<div style="{{a.cell}}">
|
|
143
|
+
<svg width="220" height="110" viewBox="0 0 220 110" style="position: absolute; left: 0; top: 0; fill: none; stroke-linecap: round"><path d="M 60 55 L 156 55" style="stroke: #B388FF; stroke-width: 2; stroke-dasharray: 6 5"></path><path d="M 152 51 L 160 55 L 152 59 Z" style="fill: #B388FF; stroke: none"></path></svg>
|
|
144
|
+
<div style="{{a.box}} left: 14px; top: 41px">A</div><div style="{{a.box}} left: 160px; top: 41px">B</div>
|
|
145
|
+
<span style="position: absolute; left: 70px; top: 30px; height: 18px; padding: 0 7px; border-radius: 999px; background: rgba(179,136,255,0.16); color: #B388FF; font-size: 11px; font-weight: 600; line-height: 18px">suggested by agent</span>
|
|
146
|
+
<span style="position: absolute; left: 14px; bottom: 8px; font-size: 11px; color: #6b7d94">Accept or dismiss; then it takes its ink.</span>
|
|
147
|
+
</div>
|
|
148
|
+
<div style="{{a.cell}}">
|
|
149
|
+
<svg width="220" height="110" viewBox="0 0 220 110" style="position: absolute; left: 0; top: 0; fill: none; stroke-linecap: round"><path d="M 60 62 L 156 62" style="stroke: #5FCFC0; stroke-width: 2.5"></path><path d="M 151 57 L 160 62 L 151 67 Z" style="fill: #5FCFC0; stroke: none"></path></svg>
|
|
150
|
+
<div style="{{a.box}} left: 14px; top: 48px">A</div><div style="{{a.box}} left: 160px; top: 48px">B</div>
|
|
151
|
+
<span style="position: absolute; left: 56px; top: 58px; width: 8px; height: 8px; box-sizing: border-box; border-radius: 999px; background: #0f1d31; border: 2px solid #5FCFC0"></span>
|
|
152
|
+
<div style="position: absolute; left: 8px; right: 8px; top: 10px; display: flex; align-items: center; justify-content: space-between; gap: 2px; padding: 3px; border-radius: 8px; background: #13243b; border: 1px solid #2a4566; box-shadow: 0 10px 30px rgba(0,0,0,0.5); font-size: 11px"><span style="padding: 0 6px; color: #5FCFC0">supports ▾</span><span style="padding: 0 6px; color: #b9c6d6">Label</span><span style="padding: 0 6px; color: #b9c6d6">Why</span><span style="padding: 0 6px; color: #ff8a9b">Delete</span></div>
|
|
153
|
+
</div>
|
|
154
|
+
</div>
|
|
155
|
+
</section>
|
|
156
|
+
|
|
157
|
+
<section style="display: flex; flex-direction: column; gap: 12px">
|
|
158
|
+
<h2 style="margin: 0; font-size: 15px; font-weight: 600">Relation inks</h2>
|
|
159
|
+
<div style="display: flex; gap: 12px; flex-wrap: wrap">
|
|
160
|
+
<sc-for list="{{inks}}" as="ik" hint-placeholder-count="7">
|
|
161
|
+
<div style="width: 170px; box-sizing: border-box; padding: 10px 12px; border-radius: 10px; border: 1px solid #1b2c44; background: #0f1d31; display: flex; flex-direction: column; gap: 6px">
|
|
162
|
+
<svg width="146" height="10" viewBox="0 0 146 10" style="fill: none; stroke: {{ik.c}}; stroke-width: 2; stroke-dasharray: {{ik.dash}}; stroke-linecap: round"><path d="M2 5 H136"></path><path d="M136 1 L144 5 L136 9 Z" style="fill: {{ik.c}}; stroke: none"></path></svg>
|
|
163
|
+
<span style="font-size: 12px; font-weight: 600">{{ik.name}}</span>
|
|
164
|
+
<span style="font-size: 11px; color: #8ea3bd">{{ik.use}}</span>
|
|
165
|
+
</div>
|
|
166
|
+
</sc-for>
|
|
167
|
+
</div>
|
|
168
|
+
<span style="font-size: 12px; color: #8ea3bd">Relation inks never reuse the reserved colors: amber = warning (e.g. a stale source), accent blue = pinned and selected, violet = the agent.</span>
|
|
169
|
+
</section>
|
|
170
|
+
|
|
171
|
+
</div>
|
|
172
|
+
</x-dc>
|
|
173
|
+
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":1440,"height":1340}}'>
|
|
174
|
+
class Component extends DCLogic {
|
|
175
|
+
renderVals() {
|
|
176
|
+
var W = 160, H = 56;
|
|
177
|
+
var N = {
|
|
178
|
+
Q: { x: 242, y: 80, title: 'Raise Pro to $24?', meta: 'question' },
|
|
179
|
+
F1: { x: 100, y: 220, title: 'Churn flat after last raise', meta: 'finding' },
|
|
180
|
+
F2: { x: 384, y: 220, title: 'SMB is price-sensitive', meta: 'finding' },
|
|
181
|
+
C: { x: 40, y: 360, title: 'Churn by plan', meta: 'chart' },
|
|
182
|
+
S1: { x: 242, y: 360, title: 'Competitor pricing', meta: 'webpage' },
|
|
183
|
+
S3: { x: 444, y: 360, title: 'Customer interviews', meta: 'notes · 9 calls' },
|
|
184
|
+
S2: { x: 40, y: 490, title: 'churn-2025.csv', meta: 'file · 14k rows' }
|
|
185
|
+
};
|
|
186
|
+
function r(v) { return Math.round(v * 10) / 10; }
|
|
187
|
+
function head(tip, from, len, half) {
|
|
188
|
+
var dx = tip.x - from.x, dy = tip.y - from.y, m = Math.sqrt(dx * dx + dy * dy) || 1;
|
|
189
|
+
var ux = dx / m, uy = dy / m, bx = tip.x - ux * len, by = tip.y - uy * len;
|
|
190
|
+
return 'M ' + r(tip.x) + ' ' + r(tip.y) + ' L ' + r(bx - uy * half) + ' ' + r(by + ux * half) + ' L ' + r(bx + uy * half) + ' ' + r(by - ux * half) + ' Z';
|
|
191
|
+
}
|
|
192
|
+
var OFF = { top: [0, -1], bottom: [0, 1], left: [-1, 0], right: [1, 0] };
|
|
193
|
+
// Today: EdgeLayer.tsx computeAnchor + sideControlPoint, curvature clamp(dist * 0.35, 32, 160)
|
|
194
|
+
function anchor(n, t) {
|
|
195
|
+
var cx = n.x + W / 2, cy = n.y + H / 2, tx = t.x + W / 2, ty = t.y + H / 2;
|
|
196
|
+
var dx = tx - cx, dy = ty - cy, hw = W / 2, hh = H / 2;
|
|
197
|
+
var tan = Math.abs(dy / (dx || 0.001)), ratio = hh / hw;
|
|
198
|
+
if (tan > ratio) { var sg = dy > 0 ? 1 : -1; return { x: cx + (hh / tan) * (dx > 0 ? 1 : -1), y: cy + hh * sg, side: sg > 0 ? 'bottom' : 'top' }; }
|
|
199
|
+
var s2 = dx > 0 ? 1 : -1; return { x: cx + hw * s2, y: cy + tan * hw * (dy > 0 ? 1 : -1), side: s2 > 0 ? 'right' : 'left' };
|
|
200
|
+
}
|
|
201
|
+
// relation = grey, undirected (no head); depends-on = amber, directed
|
|
202
|
+
function today(a, b, kind, dim, label) {
|
|
203
|
+
var s = anchor(N[a], N[b]), e = anchor(N[b], N[a]);
|
|
204
|
+
var dist = Math.sqrt(Math.pow(e.x - s.x, 2) + Math.pow(e.y - s.y, 2));
|
|
205
|
+
var c = Math.min(Math.max(dist * 0.35, 32), 160);
|
|
206
|
+
var c1 = { x: s.x + OFF[s.side][0] * c, y: s.y + OFF[s.side][1] * c };
|
|
207
|
+
var c2 = { x: e.x + OFF[e.side][0] * c, y: e.y + OFF[e.side][1] * c };
|
|
208
|
+
var mid = { x: 0.125 * s.x + 0.375 * c1.x + 0.375 * c2.x + 0.125 * e.x, y: 0.125 * s.y + 0.375 * c1.y + 0.375 * c2.y + 0.125 * e.y };
|
|
209
|
+
var wl = label.length * 7 + 16;
|
|
210
|
+
var directed = kind === 'depends-on';
|
|
211
|
+
return {
|
|
212
|
+
d: 'M ' + r(s.x) + ' ' + r(s.y) + ' C ' + r(c1.x) + ' ' + r(c1.y) + ', ' + r(c2.x) + ' ' + r(c2.y) + ', ' + r(e.x) + ' ' + r(e.y),
|
|
213
|
+
h: directed ? head(e, c2, 8, 3.2) : 'M 0 0', c: directed ? '#f4c542' : '#8ea3bd', o: dim ? 0.2 : 0.85, ho: dim ? 0.15 : 0.75,
|
|
214
|
+
label: { x: r(mid.x - wl / 2), y: r(mid.y - 10), w: wl, text: label, o: dim ? 0.35 : 1 }
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
var te = [
|
|
218
|
+
today('F1', 'Q', 'relation', false, 'supports'), today('F2', 'Q', 'relation', false, 'contradicts'),
|
|
219
|
+
today('F2', 'F1', 'relation', true, 'contradicts'), today('C', 'F1', 'relation', true, 'cites'),
|
|
220
|
+
today('S1', 'F1', 'relation', true, 'supports'), today('S3', 'F2', 'relation', true, 'quotes'),
|
|
221
|
+
today('S3', 'F2', 'relation', true, 'supports'), today('S2', 'C', 'depends-on', true, 'derived from'),
|
|
222
|
+
today('F1', 'Q', 'relation', false, 'cites')
|
|
223
|
+
];
|
|
224
|
+
var t = {};
|
|
225
|
+
te.forEach(function (e, i) { t['e' + i] = e; });
|
|
226
|
+
var tLabels = te.map(function (e) { return e.label; });
|
|
227
|
+
var tNodes = Object.keys(N).map(function (k) { return { x: N[k].x, y: N[k].y, title: N[k].title, meta: N[k].meta, border: '#1b2c44' }; });
|
|
228
|
+
|
|
229
|
+
function port(k, side, frac) {
|
|
230
|
+
var n = N[k];
|
|
231
|
+
if (side === 'top') return { x: n.x + W * frac, y: n.y, side: side };
|
|
232
|
+
if (side === 'bottom') return { x: n.x + W * frac, y: n.y + H, side: side };
|
|
233
|
+
if (side === 'left') return { x: n.x, y: n.y + H * frac, side: side };
|
|
234
|
+
return { x: n.x + W, y: n.y + H * frac, side: side };
|
|
235
|
+
}
|
|
236
|
+
var INK = { supports: '#5FCFC0', contradicts: '#E59B6B', cites: '#7C9CFF', derived: '#D5DEEA' };
|
|
237
|
+
function prop(s, e, ink, dim, c, dash) {
|
|
238
|
+
var tip = { x: e.x + OFF[e.side][0] * 2, y: e.y + OFF[e.side][1] * 2 };
|
|
239
|
+
var dist = Math.sqrt(Math.pow(tip.x - s.x, 2) + Math.pow(tip.y - s.y, 2));
|
|
240
|
+
var k = c || Math.min(Math.max(dist * 0.45, 24), 110);
|
|
241
|
+
var c1 = { x: s.x + OFF[s.side][0] * k, y: s.y + OFF[s.side][1] * k };
|
|
242
|
+
var c2 = { x: tip.x + OFF[e.side][0] * k, y: tip.y + OFF[e.side][1] * k };
|
|
243
|
+
return {
|
|
244
|
+
d: 'M ' + r(s.x) + ' ' + r(s.y) + ' C ' + r(c1.x) + ' ' + r(c1.y) + ', ' + r(c2.x) + ' ' + r(c2.y) + ', ' + r(tip.x) + ' ' + r(tip.y),
|
|
245
|
+
h: head(tip, c2, 9, 4), c: ink, w: dim ? 1.5 : 2, o: dim ? 0.14 : 1, dash: dash || 'none'
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
var pe = [
|
|
249
|
+
prop(port('F1', 'top', 0.5), port('Q', 'bottom', 0.3), INK.supports, false),
|
|
250
|
+
prop(port('F2', 'top', 0.5), port('Q', 'bottom', 0.75), INK.contradicts, false),
|
|
251
|
+
prop(port('F2', 'left', 0.5), port('F1', 'right', 0.5), INK.contradicts, true),
|
|
252
|
+
prop(port('C', 'top', 0.5), port('F1', 'bottom', 0.35), INK.cites, true),
|
|
253
|
+
prop(port('S1', 'top', 0.5), port('F1', 'bottom', 0.8), INK.supports, true),
|
|
254
|
+
prop(port('S3', 'top', 0.4), port('F2', 'bottom', 0.55), INK.cites, true),
|
|
255
|
+
prop(port('S3', 'top', 0.6), port('F2', 'bottom', 0.75), INK.supports, true),
|
|
256
|
+
prop(port('S2', 'top', 0.5), port('C', 'bottom', 0.5), INK.derived, true),
|
|
257
|
+
prop(port('F1', 'top', 0.62), port('Q', 'bottom', 0.4), INK.cites, false)
|
|
258
|
+
];
|
|
259
|
+
var p = {};
|
|
260
|
+
pe.forEach(function (e, i) { p['e' + i] = e; });
|
|
261
|
+
var neighbors = { Q: 1, F1: 1, F2: 1 };
|
|
262
|
+
var pNodes = Object.keys(N).map(function (k) {
|
|
263
|
+
var focus = k === 'Q';
|
|
264
|
+
return {
|
|
265
|
+
x: N[k].x, y: N[k].y, title: N[k].title, meta: N[k].meta,
|
|
266
|
+
o: neighbors[k] ? 1 : 0.35,
|
|
267
|
+
border: focus ? '1px solid #8ea3bd' : '1px solid #1b2c44',
|
|
268
|
+
shadow: focus ? '0 0 0 3px rgba(142,163,189,0.18), 0 10px 30px rgba(0,0,0,0.5)' : '0 1px 2px rgba(0,0,0,0.4), 0 6px 20px rgba(0,0,0,0.24)'
|
|
269
|
+
};
|
|
270
|
+
});
|
|
271
|
+
var legend = [
|
|
272
|
+
{ name: 'supports', n: 3, c: INK.supports, dash: 'none' },
|
|
273
|
+
{ name: 'contradicts', n: 2, c: INK.contradicts, dash: 'none' },
|
|
274
|
+
{ name: 'cites', n: 3, c: INK.cites, dash: 'none' },
|
|
275
|
+
{ name: 'derived from', n: 1, c: INK.derived, dash: 'none' }
|
|
276
|
+
];
|
|
277
|
+
var inks = [
|
|
278
|
+
{ name: 'supports', use: 'Evidence for a claim', c: INK.supports, dash: 'none' },
|
|
279
|
+
{ name: 'contradicts', use: 'Evidence against it', c: INK.contradicts, dash: 'none' },
|
|
280
|
+
{ name: 'cites', use: 'Where a claim or number comes from', c: INK.cites, dash: 'none' },
|
|
281
|
+
{ name: 'derived from', use: 'Data lineage: chart ← table ← source', c: INK.derived, dash: 'none' },
|
|
282
|
+
{ name: 'answers', use: 'Finding → the question it settles', c: '#E58FB0', dash: 'none' },
|
|
283
|
+
{ name: 'related', use: 'Loose link; undirected', c: '#8ea3bd', dash: '2 5' },
|
|
284
|
+
{ name: 'suggested by agent', use: 'Until you accept it', c: '#B388FF', dash: '6 5' }
|
|
285
|
+
];
|
|
286
|
+
var a = {
|
|
287
|
+
h: 'font-size:12px;font-weight:600;',
|
|
288
|
+
cell: 'position:relative;height:110px;border-radius:8px;border:1px solid #1b2c44;background:#081524;overflow:hidden;',
|
|
289
|
+
box: 'position:absolute;width:46px;height:28px;box-sizing:border-box;border-radius:6px;border:1px solid #2a4566;background:#0f1d31;font-size:11px;font-weight:600;line-height:26px;text-align:center;color:#e6eef7;',
|
|
290
|
+
oldLabel: 'position:absolute;width:48px;height:20px;box-sizing:border-box;border-radius:4px;border:0.5px solid #1b2c44;background:rgba(15,29,49,0.85);font-family:-apple-system,system-ui,sans-serif;font-size:11px;line-height:19px;text-align:center;color:#e6eef7;'
|
|
291
|
+
};
|
|
292
|
+
return { t: t, tLabels: tLabels, tNodes: tNodes, p: p, pNodes: pNodes, legend: legend, inks: inks, a: a };
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
</script>
|
|
296
|
+
</body>
|
|
297
|
+
</html>
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<title>Meaning colours across all themes</title>
|
|
6
|
+
<script src="./support.js"></script>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<x-dc>
|
|
10
|
+
<helmet>
|
|
11
|
+
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500&family=IBM+Plex+Sans:wght@400;500;600&display=swap">
|
|
12
|
+
<style>
|
|
13
|
+
body{margin:0}
|
|
14
|
+
</style>
|
|
15
|
+
</helmet>
|
|
16
|
+
<div style="width: 1440px; height: 1220px; box-sizing: border-box; padding: 48px 56px; background: #081524; color: #e6eef7; font-family: 'IBM Plex Sans', system-ui, sans-serif; font-size: 13px; line-height: 1.5; display: flex; flex-direction: column; gap: 24px">
|
|
17
|
+
|
|
18
|
+
<div style="display: flex; gap: 32px; align-items: flex-end">
|
|
19
|
+
<div style="flex: 1">
|
|
20
|
+
<h1 style="margin: 0; font-size: 28px; font-weight: 600; letter-spacing: -0.015em">Meaning colours across all nine themes</h1>
|
|
21
|
+
<p style="margin: 4px 0 0; font-size: 13px; color: #8ea3bd">Each theme keeps its own surfaces and accent (buttons, selection). The meaning colours — in context, agent, warning and the relation inks — keep the same hue in every theme, tuned only for lightness, and a token test checks they stay apart.</p>
|
|
22
|
+
</div>
|
|
23
|
+
<div style="display: flex; gap: 8px; font-size: 11px; color: #8ea3bd">
|
|
24
|
+
<span style="display: flex; align-items: center; gap: 6px"><span style="width: 10px; height: 10px; border-radius: 3px; background: #4BBCFF"></span>in context</span><span style="display: flex; align-items: center; gap: 6px"><span style="width: 10px; height: 10px; border-radius: 3px; background: #E879F9"></span>subagent</span>
|
|
25
|
+
<span style="display: flex; align-items: center; gap: 6px"><span style="width: 10px; height: 10px; border-radius: 3px; background: #B388FF"></span>agent</span>
|
|
26
|
+
<span style="display: flex; align-items: center; gap: 6px"><span style="width: 10px; height: 10px; border-radius: 3px; background: #f4c542"></span>warning</span>
|
|
27
|
+
<span style="display: flex; align-items: center; gap: 6px"><span style="width: 10px; height: 10px; border-radius: 3px; background: #5FCFC0"></span>supports</span>
|
|
28
|
+
<span style="display: flex; align-items: center; gap: 6px"><span style="width: 10px; height: 10px; border-radius: 3px; background: #E59B6B"></span>contradicts</span>
|
|
29
|
+
</div>
|
|
30
|
+
</div>
|
|
31
|
+
|
|
32
|
+
<div style="display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 16px">
|
|
33
|
+
<sc-for list="{{themes}}" as="t" hint-placeholder-count="9">
|
|
34
|
+
<section style="display: flex; flex-direction: column; gap: 8px; padding: 14px; border-radius: 12px; border: 1px solid #1b2c44; background: #0b1828">
|
|
35
|
+
<div style="display: flex; align-items: baseline; gap: 8px">
|
|
36
|
+
<span style="font-size: 15px; font-weight: 600">{{t.name}}</span>
|
|
37
|
+
<span style="font-size: 11px; color: #6b7d94">{{t.was}}</span>
|
|
38
|
+
<span style="flex: 1"></span>
|
|
39
|
+
<span style="font-size: 11px; padding: 0 7px; border-radius: 999px; border: 1px solid #2a4566; color: #b9c6d6">{{t.scheme}}</span>
|
|
40
|
+
</div>
|
|
41
|
+
<div style="position: relative; height: 200px; border-radius: 8px; overflow: hidden; background: {{t.bg}}; font-family: 'IBM Plex Sans', sans-serif">
|
|
42
|
+
<svg width="398" height="200" viewBox="0 0 398 200" style="position: absolute; left: 0; top: 0; fill: none; stroke-linecap: round">
|
|
43
|
+
<path d="M 100 112 C 100 92, 150 84, 150 70" style="stroke: {{t.sup}}; stroke-width: 2"></path><path d="M 150 66 L 145.5 75 L 154.5 75 Z" style="fill: {{t.sup}}"></path>
|
|
44
|
+
<path d="M 290 112 C 290 92, 240 84, 240 70" style="stroke: {{t.con}}; stroke-width: 2"></path><path d="M 240 66 L 235.5 75 L 244.5 75 Z" style="fill: {{t.con}}"></path>
|
|
45
|
+
</svg>
|
|
46
|
+
<div style="{{t.n1}}">
|
|
47
|
+
<div style="display: flex; align-items: center; gap: 6px; height: 26px; padding: 0 6px 0 9px; background: {{t.pinTint}}; border-bottom: 1px solid {{t.line}}"><span style="flex: 1; font-size: 11px; font-weight: 600; color: {{t.text}}">Raise Pro to $24?</span><span style="width: 16px; height: 16px; border-radius: 999px; background: {{t.pin}}; color: {{t.onPin}}; display: flex; align-items: center; justify-content: center"><svg width="9" height="9" viewBox="0 0 24 24" style="fill: none; stroke: currentColor; stroke-width: 2.8; stroke-linecap: round; stroke-linejoin: round"><path d="M9 4h6l-.8 5.5 2.8 3H7l2.8-3zM12 12.5V20"></path></svg></span></div>
|
|
48
|
+
<div style="padding: 3px 9px; font-size: 10px; color: {{t.muted}}">question · in context</div>
|
|
49
|
+
</div>
|
|
50
|
+
<div style="{{t.n2}}">
|
|
51
|
+
<div style="height: 2.5px; background: {{t.agent}}"></div>
|
|
52
|
+
<div style="display: flex; align-items: center; gap: 4px; height: 24px; padding: 0 6px 0 9px; border-bottom: 1px solid {{t.line}}"><span style="flex: 1; font-size: 11px; font-weight: 600; color: {{t.text}}; white-space: nowrap; overflow: hidden; text-overflow: ellipsis">Churn flat</span><span style="height: 16px; padding: 0 6px; border-radius: 999px; background: {{t.agentTint}}; color: {{t.agent}}; font-size: 10px; font-weight: 500; line-height: 16px">edited</span></div>
|
|
53
|
+
<div style="padding: 4px 9px; font-size: 10px; color: {{t.muted}}">supports the question</div>
|
|
54
|
+
</div>
|
|
55
|
+
<div style="{{t.n3}}">
|
|
56
|
+
<div style="display: flex; align-items: center; gap: 4px; height: 26px; padding: 0 6px 0 9px; border-bottom: 1px solid {{t.line}}"><span style="flex: 1; font-size: 11px; font-weight: 600; color: {{t.text}}">SMB interviews</span></div>
|
|
57
|
+
<div style="padding: 5px 9px; display: flex; align-items: center; gap: 6px"><span style="height: 16px; padding: 0 6px; border-radius: 999px; background: {{t.warnTint}}; color: {{t.warn}}; font-size: 10px; font-weight: 500; line-height: 16px">changed since read</span><span style="height: 18px; padding: 0 7px; border-radius: 5px; background: {{t.accent}}; color: {{t.onAccent}}; font-size: 10px; font-weight: 600; line-height: 18px">Open</span></div>
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
60
|
+
<div style="display: flex; gap: 4px">
|
|
61
|
+
<sc-for list="{{t.swatches}}" as="sw" hint-placeholder-count="7">
|
|
62
|
+
<span style="flex: 1; height: 8px; border-radius: 2px; background: {{sw}}"></span>
|
|
63
|
+
</sc-for>
|
|
64
|
+
</div>
|
|
65
|
+
<span style="font-size: 11px; line-height: 1.45; color: {{t.noteColor}}">{{t.note}}</span>
|
|
66
|
+
</section>
|
|
67
|
+
</sc-for>
|
|
68
|
+
</div>
|
|
69
|
+
|
|
70
|
+
</div>
|
|
71
|
+
</x-dc>
|
|
72
|
+
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":1440,"height":1220}}'>
|
|
73
|
+
class Component extends DCLogic {
|
|
74
|
+
renderVals() {
|
|
75
|
+
function hexA(hex, a) {
|
|
76
|
+
var h = hex.replace('#', '');
|
|
77
|
+
var r = parseInt(h.slice(0, 2), 16), g = parseInt(h.slice(2, 4), 16), b = parseInt(h.slice(4, 6), 16);
|
|
78
|
+
return 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')';
|
|
79
|
+
}
|
|
80
|
+
var DARK = { pin: '#4BBCFF', onPin: '#081524', agent: '#B388FF', subagent: '#E879F9', sup: '#5FCFC0', con: '#E59B6B', e1: '0 1px 2px rgba(0,0,0,0.4), 0 6px 20px rgba(0,0,0,0.24)' };
|
|
81
|
+
var LIGHT = { pin: '#1A7ABF', onPin: '#FFFFFF', agent: '#7C4DDB', subagent: '#A83BB0', sup: '#1E8C80', con: '#B8572A', e1: '0 1px 2px rgba(8,21,36,0.1), 0 6px 20px rgba(8,21,36,0.08)' };
|
|
82
|
+
function t(o) {
|
|
83
|
+
var base = o.scheme === 'light' ? LIGHT : DARK;
|
|
84
|
+
var x = Object.assign({}, base, o);
|
|
85
|
+
x.pinTint = hexA(x.pin, o.scheme === 'light' ? 0.10 : 0.12);
|
|
86
|
+
x.agentTint = hexA(x.agent, 0.16);
|
|
87
|
+
x.warnTint = hexA(x.warn, 0.14);
|
|
88
|
+
x.swatches = [x.bg, x.panel, x.accent, x.pin, x.agent, x.subagent, x.warn, x.sup];
|
|
89
|
+
var nodeBase = 'position:absolute;box-sizing:border-box;border-radius:9px;overflow:hidden;background:' + x.panel + ';box-shadow:' + x.e1 + ';';
|
|
90
|
+
x.n1 = nodeBase + 'left:100px;top:14px;width:198px;height:52px;border:1.5px solid ' + x.pin + ';';
|
|
91
|
+
x.n2 = nodeBase + 'left:14px;top:114px;width:172px;height:70px;border:1px solid ' + x.line + ';';
|
|
92
|
+
x.n3 = nodeBase + 'left:204px;top:114px;width:180px;height:70px;border:1px solid ' + x.line + ';';
|
|
93
|
+
x.noteColor = o.bad ? '#ff8a9b' : '#8ea3bd';
|
|
94
|
+
return x;
|
|
95
|
+
}
|
|
96
|
+
var themes = [
|
|
97
|
+
t({ name: 'Harbor', was: 'id harbor · default', scheme: 'dark', bg: '#081524', panel: '#0f1d31', line: '#1b2c44', text: '#e6eef7', muted: '#8ea3bd', accent: '#4BBCFF', onAccent: '#081524', warn: '#f4c542',
|
|
98
|
+
note: 'Accent and pin are the same blue here, so selection is told apart by its gap ring and handles.' }),
|
|
99
|
+
t({ name: 'Daylight', was: 'id daylight', scheme: 'light', bg: '#F6F7F9', panel: '#FFFFFF', line: '#DDE2E9', text: '#0B1726', muted: '#55657a', accent: '#1A7ABF', onAccent: '#FFFFFF', warn: '#94600A',
|
|
100
|
+
note: 'Neutral surfaces instead of beige, so it no longer looks like Sepia. Shadows are ink-tinted, not black.' }),
|
|
101
|
+
t({ name: 'High contrast', was: 'unchanged', scheme: 'dark', bg: '#000000', panel: '#0a0a0a', line: '#ffffff', text: '#ffffff', muted: '#cccccc', accent: '#00ffff', onAccent: '#000000', warn: '#ffff00', pin: '#00ffff', onPin: '#000000', agent: '#e040fb', subagent: '#ff99ff', sup: '#00e5c0', con: '#ff8a00',
|
|
102
|
+
note: 'Keeps a literal name. Meaning colours use the theme’s own pure hues.' }),
|
|
103
|
+
t({ name: 'Midnight', was: 'unchanged', scheme: 'dark', bg: '#0A0D1C', panel: '#12172E', line: '#232B4A', text: '#E6E9F7', muted: '#8D96BC', accent: '#8B96FF', onAccent: '#0A0D1C', warn: '#F5C452',
|
|
104
|
+
note: 'Accent periwinkle sits between pin blue and agent violet — pin can’t be the accent here.', bad: true }),
|
|
105
|
+
t({ name: 'Sepia', was: 'unchanged', scheme: 'light', bg: '#F2E7D5', panel: '#EBDCC2', line: '#D3C1A0', text: '#2E2416', muted: '#77664C', accent: '#B4632C', onAccent: '#FFFFFF', warn: '#8A5A00', pin: '#1F6FA8', agent: '#7046A6', con: '#A3461C',
|
|
106
|
+
note: 'Accent copper is close to the warning brown — another reason pin is its own colour. Shadows are ink-tinted.', bad: true }),
|
|
107
|
+
t({ name: 'Arctic', was: 'unchanged', scheme: 'dark', bg: '#20242E', panel: '#2A2F3C', line: '#3A4152', text: '#E9EDF4', muted: '#939DB1', accent: '#7FC8DE', onAccent: '#20242E', warn: '#E8C476', pin: '#6EC1F5',
|
|
108
|
+
note: 'Works as is; pin is a touch bluer than the accent ice.' }),
|
|
109
|
+
t({ name: 'Ember', was: 'unchanged', scheme: 'dark', bg: '#0B0B0C', panel: '#161618', line: '#29292C', text: '#EDEBE6', muted: '#96948D', accent: '#F34E1C', onAccent: '#0B0B0C', warn: '#F5B944',
|
|
110
|
+
note: 'Accent orange-red would read as an error if it marked “in context”.', bad: true }),
|
|
111
|
+
t({ name: 'Forest', was: 'unchanged', scheme: 'dark', bg: '#0C1712', panel: '#14231B', line: '#26402F', text: '#E4EFE7', muted: '#8BA695', accent: '#5CCF8F', onAccent: '#0C1712', warn: '#E0B84F', sup: '#4FC9D9',
|
|
112
|
+
note: 'Accent green equals “done” green; supports shifts to cyan so it isn’t lost.', bad: true }),
|
|
113
|
+
t({ name: 'Volt', was: 'unchanged', scheme: 'dark', bg: '#0B0D0B', panel: '#171A17', line: '#272A27', text: '#F6FFF5', muted: '#9CA49C', accent: '#DFDFC1', onAccent: '#0B0D0B', warn: '#E4C465',
|
|
114
|
+
note: 'Accent is near-white, so a pin in the accent would barely show.', bad: true })
|
|
115
|
+
];
|
|
116
|
+
return { themes: themes };
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
</script>
|
|
120
|
+
</body>
|
|
121
|
+
</html>
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<title>Token system today and proposed</title>
|
|
6
|
+
<script src="./support.js"></script>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<x-dc>
|
|
10
|
+
<helmet>
|
|
11
|
+
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500&family=IBM+Plex+Sans:wght@400;500;600&display=swap">
|
|
12
|
+
<style>
|
|
13
|
+
body{margin:0}
|
|
14
|
+
</style>
|
|
15
|
+
</helmet>
|
|
16
|
+
<div style="width: 1440px; height: 1000px; box-sizing: border-box; padding: 44px 56px; background: #081524; color: #e6eef7; font-family: 'IBM Plex Sans', system-ui, sans-serif; font-size: 13px; line-height: 1.5; display: flex; flex-direction: column; gap: 20px">
|
|
17
|
+
|
|
18
|
+
<div>
|
|
19
|
+
<h1 style="margin: 0; font-size: 28px; font-weight: 600; letter-spacing: -0.015em">The token system — today and proposed</h1>
|
|
20
|
+
<p style="margin: 4px 0 0; font-size: 13px; color: #8ea3bd">Today is one flat list of about 55 colours that components borrow meaning from. Proposed is three layers — palette, meaning, scale — and components only ever reference tokens.</p>
|
|
21
|
+
</div>
|
|
22
|
+
|
|
23
|
+
<div style="flex: 1; display: grid; grid-template-columns: 520px minmax(0, 1fr); gap: 32px">
|
|
24
|
+
|
|
25
|
+
<section style="display: flex; flex-direction: column; gap: 12px">
|
|
26
|
+
<span style="{{s.label}}">Today · src/client/theme/global.css</span>
|
|
27
|
+
<div style="{{s.card}} gap: 10px">
|
|
28
|
+
<div style="font-size: 15px; font-weight: 600">≈ 55 tokens, almost all colour</div>
|
|
29
|
+
<sc-for list="{{today}}" as="g" hint-placeholder-count="6">
|
|
30
|
+
<div style="display: flex; flex-direction: column; gap: 4px">
|
|
31
|
+
<span style="font-size: 11px; color: #8ea3bd">{{g.name}}</span>
|
|
32
|
+
<div style="display: flex; flex-wrap: wrap; gap: 4px"><sc-for list="{{g.tokens}}" as="t" hint-placeholder-count="6"><span style="{{s.tok}}">{{t}}</span></sc-for></div>
|
|
33
|
+
</div>
|
|
34
|
+
</sc-for>
|
|
35
|
+
</div>
|
|
36
|
+
<div style="{{s.card}} gap: 6px">
|
|
37
|
+
<div style="font-size: 12px; font-weight: 600">What goes wrong</div>
|
|
38
|
+
<sc-for list="{{problems}}" as="p" hint-placeholder-count="6">
|
|
39
|
+
<div style="display: flex; gap: 8px; font-size: 12px; color: #b9c6d6"><span style="color: #ff8a9b; flex-shrink: 0">✕</span><span>{{p}}</span></div>
|
|
40
|
+
</sc-for>
|
|
41
|
+
</div>
|
|
42
|
+
</section>
|
|
43
|
+
|
|
44
|
+
<section style="display: flex; flex-direction: column; gap: 12px">
|
|
45
|
+
<span style="{{s.label}}">Proposed · three layers</span>
|
|
46
|
+
|
|
47
|
+
<div style="{{s.card}} gap: 8px">
|
|
48
|
+
<div style="display: flex; align-items: baseline; gap: 10px"><span style="{{s.num}}">1</span><span style="font-size: 15px; font-weight: 600">Palette</span><span style="font-size: 12px; color: #8ea3bd">per theme · names kept · the accent is free for flavour (buttons, selection)</span></div>
|
|
49
|
+
<div style="display: flex; flex-wrap: wrap; gap: 6px"><sc-for list="{{palette}}" as="t" hint-placeholder-count="12"><span style="{{s.swTok}}"><span style="width: 12px; height: 12px; border-radius: 3px; background: {{t.c}}; border: 1px solid #2a4566"></span>{{t.n}}</span></sc-for></div>
|
|
50
|
+
</div>
|
|
51
|
+
|
|
52
|
+
<div style="{{s.card}} gap: 8px">
|
|
53
|
+
<div style="display: flex; align-items: baseline; gap: 10px"><span style="{{s.num}}">2</span><span style="font-size: 15px; font-weight: 600">Meaning</span><span style="font-size: 12px; color: #8ea3bd">one hue in every theme, tuned for lightness · used only for its meaning</span></div>
|
|
54
|
+
<div style="display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px">
|
|
55
|
+
<sc-for list="{{meaning}}" as="t" hint-placeholder-count="9"><div style="display: flex; align-items: center; gap: 8px; padding: 6px 8px; border-radius: 6px; background: #13243b"><span style="width: 14px; height: 14px; border-radius: 4px; background: {{t.c}}; flex-shrink: 0"></span><span style="display: flex; flex-direction: column; min-width: 0"><span style="font-family: 'IBM Plex Mono', monospace; font-size: 11px; color: #e6eef7">{{t.n}}</span><span style="font-size: 11px; color: #8ea3bd">{{t.m}}</span></span></div></sc-for>
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
58
|
+
|
|
59
|
+
<div style="{{s.card}} gap: 8px">
|
|
60
|
+
<div style="display: flex; align-items: baseline; gap: 10px"><span style="{{s.num}}">3</span><span style="font-size: 15px; font-weight: 600">Scale</span><span style="font-size: 12px; color: #8ea3bd">the same in every theme</span></div>
|
|
61
|
+
<sc-for list="{{scale}}" as="r" hint-placeholder-count="5">
|
|
62
|
+
<div style="display: grid; grid-template-columns: 90px 1fr; align-items: baseline; gap: 10px"><span style="font-size: 11px; color: #8ea3bd">{{r.k}}</span><span style="font-family: 'IBM Plex Mono', monospace; font-size: 11px; color: #e6eef7">{{r.v}}</span></div>
|
|
63
|
+
</sc-for>
|
|
64
|
+
</div>
|
|
65
|
+
|
|
66
|
+
<div style="display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px">
|
|
67
|
+
<sc-for list="{{rules}}" as="r" hint-placeholder-count="3">
|
|
68
|
+
<div style="{{s.card}} gap: 4px; padding: 12px 14px"><span style="font-size: 12px; font-weight: 600">{{r.t}}</span><span style="font-size: 11px; color: #b9c6d6">{{r.d}}</span></div>
|
|
69
|
+
</sc-for>
|
|
70
|
+
</div>
|
|
71
|
+
</section>
|
|
72
|
+
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
</x-dc>
|
|
76
|
+
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":1440,"height":1000}}'>
|
|
77
|
+
class Component extends DCLogic {
|
|
78
|
+
renderVals() {
|
|
79
|
+
var s = {
|
|
80
|
+
label: 'font-size:11px;font-weight:500;letter-spacing:0.06em;text-transform:uppercase;color:#6b7d94;',
|
|
81
|
+
card: 'display:flex;flex-direction:column;padding:16px 18px;border-radius:10px;border:1px solid #1b2c44;background:#0f1d31;',
|
|
82
|
+
tok: 'font-family:"IBM Plex Mono",monospace;font-size:11px;padding:1px 6px;border-radius:4px;background:#13243b;color:#b9c6d6;',
|
|
83
|
+
swTok: 'display:flex;align-items:center;gap:6px;font-family:"IBM Plex Mono",monospace;font-size:11px;padding:3px 8px;border-radius:6px;background:#13243b;color:#e6eef7;',
|
|
84
|
+
num: 'width:22px;height:22px;border-radius:999px;background:#1b2c44;font-size:12px;font-weight:600;text-align:center;line-height:22px;flex-shrink:0;'
|
|
85
|
+
};
|
|
86
|
+
var today = [
|
|
87
|
+
{ name: 'Palette (per theme)', tokens: ['--c-bg', '--c-panel', '--c-panel-soft', '--c-line', '--c-text', '--c-text-soft', '--c-muted', '--c-dim'] },
|
|
88
|
+
{ name: 'Status colours, borrowed for meaning', tokens: ['--c-accent', '--c-ok', '--c-warn', '--c-warn-alt', '--c-danger', '--c-purple', '--c-thinking', '--c-subagent'] },
|
|
89
|
+
{ name: 'Fixed alpha copies — 22 of them', tokens: ['--c-warn-10…60 ×9', '--c-accent-8…40 ×8', '--c-ok-10…25 ×4', '--c-danger-12'] },
|
|
90
|
+
{ name: 'Surfaces and effects', tokens: ['--c-panel-glass', '--c-panel-overlay', '--c-surface-hover', '--c-surface-subtle', '--c-input-bg', '--c-shadow', '--c-shadow-heavy', '--c-glow-accent'] },
|
|
91
|
+
{ name: 'Shape and type — the only non-colour tokens', tokens: ['--font', '--mono', '--radius', '--radius-sm', '--hud-bar-height'] },
|
|
92
|
+
{ name: 'A second scheme for embedded viewers', tokens: ['--color-bg', '--color-text', '--color-accent', '--color-warning', '…'] }
|
|
93
|
+
];
|
|
94
|
+
var problems = [
|
|
95
|
+
'Meaning is borrowed: a pin is --c-warn (amber, used 93 times in global.css), attention is --c-warn too; light theme hard-codes #4BBCFF instead.',
|
|
96
|
+
'No size, spacing or shadow tokens: 20 font sizes, 12 radii and 195 raw hex colours live directly in the CSS.',
|
|
97
|
+
'Alpha copies are fixed per colour, so every new tint is a new token (amber already has nine).',
|
|
98
|
+
'Embedded viewers get a different set (--color-*) collapsed to dark or light, so charts draw their own palette.',
|
|
99
|
+
'--c-subagent is cyan (#00E5FF), close to the pin blue (now a fuchsia, #E879F9).',
|
|
100
|
+
'Nothing checks any of it: no test that meanings stay apart, nothing stops a new raw hex.'
|
|
101
|
+
];
|
|
102
|
+
var palette = [
|
|
103
|
+
{ n: '--c-bg', c: '#081524' }, { n: '--c-panel', c: '#0f1d31' }, { n: '--c-panel-soft', c: '#13243b' }, { n: '--c-line', c: '#1b2c44' },
|
|
104
|
+
{ n: '--c-text', c: '#e6eef7' }, { n: '--c-text-soft', c: '#b9c6d6' }, { n: '--c-muted', c: '#8ea3bd' }, { n: '--c-dim', c: '#6b7d94' },
|
|
105
|
+
{ n: '--c-accent', c: '#4BBCFF' }, { n: '--c-on-accent', c: '#081524' }, { n: '--c-ok', c: '#2fd07f' }, { n: '--c-danger', c: '#ff6a7f' }
|
|
106
|
+
];
|
|
107
|
+
var meaning = [
|
|
108
|
+
{ n: '--c-pin', m: 'in the agent’s context', c: '#4BBCFF' },
|
|
109
|
+
{ n: '--c-agent', m: 'what the agent did', c: '#B388FF' },
|
|
110
|
+
{ n: '--c-subagent', m: 'a subagent at work', c: '#E879F9' },
|
|
111
|
+
{ n: '--c-warn', m: 'needs a look', c: '#f4c542' },
|
|
112
|
+
{ n: '--c-rel-supports', m: 'evidence for', c: '#5FCFC0' },
|
|
113
|
+
{ n: '--c-rel-contradicts', m: 'evidence against', c: '#E59B6B' },
|
|
114
|
+
{ n: '--c-rel-cites', m: 'where it comes from', c: '#7C9CFF' },
|
|
115
|
+
{ n: '--c-rel-derived', m: 'data lineage, flow', c: '#D5DEEA' },
|
|
116
|
+
{ n: '--c-rel-informs', m: 'answers, depends on', c: '#E58FB0' },
|
|
117
|
+
{ n: '--c-rel-related', m: 'loose link, dotted', c: '#8ea3bd' }
|
|
118
|
+
];
|
|
119
|
+
var scale = [
|
|
120
|
+
{ k: 'Type', v: '--fs-meta 11 · --fs-ui 12 · --fs-body 13 · --fs-title 15 · --fs-heading 20' },
|
|
121
|
+
{ k: 'Spacing', v: '--space-1 4 · --space-2 8 · --space-3 12 · --space-4 16 · --space-6 24 · --space-8 32' },
|
|
122
|
+
{ k: 'Radius', v: '--r-control 6 · --r-node 10 · --r-overlay 14 · --r-pill 999' },
|
|
123
|
+
{ k: 'Elevation', v: '--e-1 nodes · --e-2 floating chrome and menus · no glows · ink-tinted on Daylight and Sepia' },
|
|
124
|
+
{ k: 'Fonts', v: '--font-ui IBM Plex Sans · --font-code IBM Plex Mono (bundled)' }
|
|
125
|
+
];
|
|
126
|
+
var rules = [
|
|
127
|
+
{ t: 'Tints are derived', d: 'color-mix(in srgb, var(--c-pin) 12%, transparent) replaces the 22 fixed alpha copies.' },
|
|
128
|
+
{ t: 'One set for every surface', d: 'The frame host hands the same tokens to embedded viewers; --color-* goes.' },
|
|
129
|
+
{ t: 'Checked', d: 'A test keeps meanings apart from each other and the palette in all nine themes; no raw hex outside theme files.' }
|
|
130
|
+
];
|
|
131
|
+
return { s: s, today: today, problems: problems, palette: palette, meaning: meaning, scale: scale, rules: rules };
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
</script>
|
|
135
|
+
</body>
|
|
136
|
+
</html>
|