konpeki 0.3.0 → 0.4.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 (162) hide show
  1. package/AGENTS.md +21 -28
  2. package/AUTHORING.md +68 -229
  3. package/CONTRIBUTING.md +10 -23
  4. package/README.md +96 -87
  5. package/SETUP.md +50 -114
  6. package/docs/development.md +43 -248
  7. package/docs/workflow.md +6 -108
  8. package/html/README.md +140 -0
  9. package/html/browser.ts +103 -0
  10. package/html/document.ts +38 -0
  11. package/html/floor.ts +34 -0
  12. package/html/index.html +5 -0
  13. package/html/inspect.ts +313 -0
  14. package/html/preview.css +62 -0
  15. package/html/preview.tsx +463 -0
  16. package/html/review-hints.ts +63 -0
  17. package/html/server.ts +99 -0
  18. package/html/source.ts +104 -0
  19. package/html/starter.ts +6 -0
  20. package/html/theme-authoring.md +176 -0
  21. package/html/theme.md +61 -0
  22. package/index.html +9 -9
  23. package/package.json +21 -35
  24. package/plugin.json +1 -1
  25. package/public/og.png +0 -0
  26. package/runtime/browser-B-29TH1a.mjs +595 -0
  27. package/runtime/floor-Cmk7G3pU.mjs +41 -0
  28. package/runtime/konpeki.mjs +90 -1410
  29. package/runtime/server-BAqC_5WD.mjs +2 -0
  30. package/runtime/server-DfRpfcY9.mjs +205 -0
  31. package/runtime/source-B_Ui9tMp.mjs +141 -0
  32. package/runtime/source-CZQq9GUO.mjs +2 -0
  33. package/skills/konpeki/SKILL.md +88 -172
  34. package/skills/konpeki/assets/blank.html +17 -0
  35. package/skills/konpeki/floor.md +76 -0
  36. package/skills/konpeki/references/cover.md +27 -0
  37. package/skills/konpeki/references/long-document.md +40 -0
  38. package/skills/konpeki/references/one-pager.md +27 -0
  39. package/skills/konpeki/references/patterns.md +118 -0
  40. package/skills/konpeki/references/resume.md +28 -0
  41. package/skills/konpeki/references/slides.md +28 -0
  42. package/skills/konpeki/scripts/ensure-runtime.mjs +10 -31
  43. package/skills/konpeki/scripts/prepare-document.mjs +25 -14
  44. package/src/components/PageBoard.tsx +156 -0
  45. package/src/lib/alignment.ts +21 -0
  46. package/src/lib/page-board.ts +25 -0
  47. package/src/lib/review-position.ts +19 -0
  48. package/src/styles/base.css +4 -6
  49. package/src/styles/feedback.css +97 -61
  50. package/src/styles/shell.css +95 -323
  51. package/theme-base.css +90 -0
  52. package/theme.css +56 -0
  53. package/vite.config.ts +2 -5
  54. package/composition/README.md +0 -156
  55. package/composition/compile.ts +0 -227
  56. package/composition/document.ts +0 -600
  57. package/composition/schema.json +0 -3001
  58. package/composition/schema.ts +0 -437
  59. package/composition/theme-tokens.ts +0 -16
  60. package/composition/types.ts +0 -269
  61. package/composition/validate.ts +0 -226
  62. package/composition/vector.ts +0 -143
  63. package/composition/visualizations.ts +0 -319
  64. package/design/README.md +0 -17
  65. package/design/palettes/README.md +0 -14
  66. package/design/palettes/base.ts +0 -14
  67. package/design/palettes/candidates.ts +0 -19
  68. package/design/palettes/index.ts +0 -78
  69. package/design/review/color-theme.md +0 -44
  70. package/design/review/layout.md +0 -16
  71. package/design/review/text.md +0 -18
  72. package/design/review/typography.md +0 -15
  73. package/design/review/visuals.md +0 -31
  74. package/design/semantic-patterns.md +0 -43
  75. package/design/themes/README.md +0 -40
  76. package/design/themes/index.ts +0 -24
  77. package/design/visual-languages/technical-product.md +0 -17
  78. package/design/visual-review.md +0 -88
  79. package/lib/assets.d.ts +0 -8
  80. package/lib/charts.ts +0 -18
  81. package/lib/contrast.ts +0 -16
  82. package/lib/layouts.ts +0 -50
  83. package/lib/slide.tsx +0 -42
  84. package/lib/taste.ts +0 -17
  85. package/lib/text.tsx +0 -89
  86. package/lib/typeface.ts +0 -44
  87. package/scripts/migrate-react-page.ts +0 -120
  88. package/skills/konpeki/assets/blank.json +0 -23
  89. package/slides/README.md +0 -153
  90. package/slides/architecture/PROMPT.md +0 -31
  91. package/slides/architecture/index.tsx +0 -102
  92. package/slides/article-brief/PROMPT.md +0 -35
  93. package/slides/article-brief/index.tsx +0 -71
  94. package/slides/bar-chart/PROMPT.md +0 -39
  95. package/slides/bar-chart/index.tsx +0 -97
  96. package/slides/comparison/PROMPT.md +0 -29
  97. package/slides/comparison/index.tsx +0 -95
  98. package/slides/decision-memo/PROMPT.md +0 -34
  99. package/slides/decision-memo/index.tsx +0 -85
  100. package/slides/delivery-plan/PROMPT.md +0 -45
  101. package/slides/delivery-plan/index.tsx +0 -105
  102. package/slides/experiment/PROMPT.md +0 -44
  103. package/slides/experiment/index.tsx +0 -127
  104. package/slides/incident-workflow/PROMPT.md +0 -57
  105. package/slides/incident-workflow/index.tsx +0 -78
  106. package/slides/introducing-konpeki/PROMPT.md +0 -40
  107. package/slides/introducing-konpeki/README.md +0 -76
  108. package/slides/introducing-konpeki/SOURCE.md +0 -26
  109. package/slides/introducing-konpeki/author.ts +0 -165
  110. package/slides/introducing-konpeki/composition.json +0 -3270
  111. package/slides/line-chart/PROMPT.md +0 -40
  112. package/slides/line-chart/index.tsx +0 -72
  113. package/slides/migration/PROMPT.md +0 -38
  114. package/slides/migration/index.tsx +0 -89
  115. package/slides/og-images/PROMPT.md +0 -21
  116. package/slides/og-images/index.tsx +0 -76
  117. package/slides/product-introduction/PROMPT.md +0 -24
  118. package/slides/product-introduction/index.tsx +0 -105
  119. package/slides/research-brief/PROMPT.md +0 -40
  120. package/slides/research-brief/index.tsx +0 -104
  121. package/slides/results-explanation/PROMPT.md +0 -32
  122. package/slides/results-explanation/index.tsx +0 -96
  123. package/slides/retrospective/PROMPT.md +0 -43
  124. package/slides/retrospective/index.tsx +0 -105
  125. package/slides/sankey/PROMPT.md +0 -11
  126. package/slides/sankey/index.tsx +0 -93
  127. package/slides/teaching/PROMPT.md +0 -45
  128. package/slides/teaching/index.tsx +0 -124
  129. package/slides/vertical-bar-charts/PROMPT.md +0 -13
  130. package/slides/vertical-bar-charts/index.tsx +0 -97
  131. package/src/app/App.tsx +0 -820
  132. package/src/components/BuildOrb.tsx +0 -40
  133. package/src/components/Canvas.tsx +0 -1185
  134. package/src/components/DiagramTypeIcon.tsx +0 -78
  135. package/src/components/InspectorPanel.tsx +0 -773
  136. package/src/components/LeftPanel.tsx +0 -120
  137. package/src/components/PageSizePicker.tsx +0 -30
  138. package/src/components/Presentation.tsx +0 -105
  139. package/src/components/RevisionNotes.tsx +0 -56
  140. package/src/components/RightPanel.tsx +0 -201
  141. package/src/components/VectorOverflowWarning.tsx +0 -46
  142. package/src/components/WorkspaceChrome.tsx +0 -288
  143. package/src/components/ui.tsx +0 -53
  144. package/src/lib/examples/react-page-migration.json +0 -1295
  145. package/src/lib/examples.ts +0 -42
  146. package/src/lib/export-png.ts +0 -104
  147. package/src/lib/file-session.ts +0 -87
  148. package/src/lib/history.ts +0 -53
  149. package/src/lib/model.ts +0 -188
  150. package/src/lib/page-size.ts +0 -24
  151. package/src/lib/presentation.ts +0 -17
  152. package/src/lib/review.ts +0 -26
  153. package/src/lib/storage.ts +0 -71
  154. package/src/lib/theme.ts +0 -25
  155. package/src/lib/use-file-session.ts +0 -227
  156. package/src/main.tsx +0 -29
  157. package/src/styles/canvas.css +0 -299
  158. package/src/styles/chrome.css +0 -384
  159. package/src/styles/component-previews.css +0 -386
  160. package/src/styles/left-panel.css +0 -166
  161. package/src/styles/presentation.css +0 -72
  162. package/src/styles/right-panel.css +0 -1215
@@ -0,0 +1,21 @@
1
+ export type Guide = { axis: "x" | "y"; value: number };
2
+
3
+ export function closest(points: number[], targets: number[], threshold: number) {
4
+ let match: { delta: number; target: number } | undefined;
5
+ for (const point of points)
6
+ for (const target of targets) {
7
+ const delta = target - point;
8
+ if (Math.abs(delta) <= threshold && (!match || Math.abs(delta) < Math.abs(match.delta)))
9
+ match = { delta, target };
10
+ }
11
+ return match;
12
+ }
13
+
14
+ /** Visual references only. Never change the dragged coordinates. */
15
+ export function referenceGuides(rect: { x: number; y: number; width: number; height: number }, targets: { x: number[]; y: number[] }, threshold = 2): Guide[] {
16
+ return (["x", "y"] as const).flatMap(axis => {
17
+ const size = axis === "x" ? rect.width : rect.height;
18
+ const match = closest([rect[axis], rect[axis] + size / 2, rect[axis] + size], targets[axis], threshold);
19
+ return match ? [{ axis, value: match.target }] : [];
20
+ });
21
+ }
@@ -0,0 +1,25 @@
1
+ /** Presentation geometry only; never stored in the authored document. */
2
+ export function layoutPages(sizes: readonly { width: number; height: number }[], availableWidth: number, availableHeight: number) {
3
+ const gap = 80, heading = 32;
4
+ let nextX = 0;
5
+ const pages = sizes.map(size => {
6
+ const scale = Math.min(availableWidth / size.width, Math.max(0, availableHeight - heading) / size.height);
7
+ const width = size.width * scale, height = size.height * scale;
8
+ const x = nextX;
9
+ nextX += width + gap;
10
+ return { x, y: heading, width, height };
11
+ });
12
+ const arrows = pages.slice(1).map((next, index) => {
13
+ const previous = pages[index];
14
+ const start = previous.x + previous.width + 16;
15
+ const end = next.x - 16;
16
+ const middle = (start + end) / 2;
17
+ return `M ${start} ${previous.y + previous.height / 2} H ${middle} V ${next.y + next.height / 2} H ${end}`;
18
+ });
19
+ return {
20
+ // The board centers this tightly bounded row when it fits the viewport.
21
+ width: pages.length ? nextX - gap : availableWidth,
22
+ height: pages.length ? heading + Math.max(...pages.map(page => page.height)) : 0,
23
+ pages, arrows,
24
+ };
25
+ }
@@ -0,0 +1,19 @@
1
+ type Rect = { x: number; y: number; width: number; height: number };
2
+
3
+ /** Fixed viewport coordinates; the caller measures the already-zoomed target. */
4
+ export function reviewPosition(anchor: Rect, panel: Pick<Rect, "width" | "height">, viewport: Rect) {
5
+ const margin = 16, gap = 12;
6
+ const minX = viewport.x + margin, minY = viewport.y + margin;
7
+ const maxX = Math.max(minX, viewport.x + viewport.width - margin - panel.width);
8
+ const maxY = Math.max(minY, viewport.y + viewport.height - margin - panel.height);
9
+ const left = Math.max(minX, Math.min(anchor.x, maxX));
10
+ const top = Math.max(minY, Math.min(anchor.y, maxY));
11
+ const candidates = [
12
+ { left, top: anchor.y + anchor.height + gap },
13
+ { left, top: anchor.y - gap - panel.height },
14
+ { left: anchor.x + anchor.width + gap, top },
15
+ { left: anchor.x - gap - panel.width, top },
16
+ ];
17
+ return candidates.find(p => p.left >= minX && p.left <= maxX && p.top >= minY && p.top <= maxY)
18
+ ?? { left, top: Math.max(minY, Math.min(candidates[0].top, maxY)) };
19
+ }
@@ -17,6 +17,7 @@
17
17
  --ui-hover: #f2f2f2;
18
18
  --ui-selected: #edf6fa;
19
19
  --ui-shadow: 0 8px 28px #00000014, 0 1px 3px #00000012;
20
+ --ui-floating-shadow: 0 0 0 1px #0000000f, 0 2px 4px #00000006, 0 8px 24px #0000000a;
20
21
  }
21
22
  * {
22
23
  box-sizing: border-box;
@@ -52,6 +53,9 @@ button:disabled {
52
53
  cursor: default;
53
54
  color: #767676;
54
55
  }
56
+ .revision-note-count {
57
+ font-variant-numeric: tabular-nums;
58
+ }
55
59
  :focus-visible {
56
60
  outline: 2px solid var(--accent);
57
61
  outline-offset: 3px;
@@ -98,12 +102,6 @@ h2 {
98
102
  background: #383838;
99
103
  border-color: #383838;
100
104
  }
101
- .panel-toggle:active:not(:disabled),
102
- .action-island button:active:not(:disabled),
103
- .component-dock button:active:not(:disabled),
104
- .segmented-options button:active:not(:disabled),
105
- .theme-options button:active:not(:disabled),
106
- .appearance-options button:active:not(:disabled),
107
105
  .revision-note-submit button:active:not(:disabled),
108
106
  .revision-note-remove:active:not(:disabled) {
109
107
  transform: scale(0.96);
@@ -1,42 +1,79 @@
1
- .toast {
1
+ .feedback-notice {
2
2
  position: fixed;
3
- top: 20px;
4
- bottom: auto;
5
3
  left: 50%;
6
- transform: translateX(-50%);
7
- transform-origin: center top;
8
- display: none;
9
- align-items: center;
10
- gap: 12px;
4
+ z-index: 50;
5
+ opacity: 0;
6
+ visibility: hidden;
7
+ pointer-events: none;
8
+ transform: translate(-50%, -3px);
9
+ transition: opacity 120ms ease-in, transform 120ms ease-in,
10
+ visibility 0s 120ms;
11
11
  background: var(--ui-surface);
12
12
  color: var(--ui-text);
13
- border: 1px solid var(--ui-border);
14
- box-shadow: 0 4px 16px #0000000a, 0 1px 3px #00000008;
15
- padding: 10px 14px;
13
+ border: 1px solid transparent;
16
14
  border-radius: 12px;
15
+ box-shadow: var(--ui-floating-shadow);
17
16
  font-size: 13px;
18
17
  line-height: 1.5;
18
+ }
19
+ .feedback-notice.visible {
20
+ opacity: 1;
21
+ visibility: visible;
22
+ pointer-events: auto;
23
+ transform: translate(-50%, 0);
24
+ transition: opacity 180ms ease-out, transform 180ms ease-out,
25
+ visibility 0s;
26
+ }
27
+ @starting-style {
28
+ .feedback-notice.visible {
29
+ opacity: 0;
30
+ transform: translate(-50%, -6px);
31
+ }
32
+ }
33
+ .toast {
34
+ top: 20px;
35
+ display: flex;
36
+ align-items: center;
37
+ gap: 12px;
38
+ padding: 10px 14px;
19
39
  width: max-content;
20
- max-width: min(520px, max(240px, calc(100vw - 744px)), calc(100vw - 40px));
21
- z-index: 50;
40
+ max-width: min(560px, calc(100vw - 40px));
22
41
  }
23
- .toast > span {
42
+ .toast > span,
43
+ .recovery > span,
44
+ .parameter-error {
24
45
  min-width: 0;
25
46
  overflow-wrap: anywhere;
47
+ text-wrap: pretty;
26
48
  }
27
- .toast.visible {
28
- display: flex;
29
- animation: toast-enter 180ms ease-out both;
49
+ .toast > button {
50
+ flex: none;
51
+ min-height: 36px;
52
+ font-size: 12px;
53
+ border: 0;
30
54
  }
31
- .toast.visible.closing {
32
- pointer-events: none;
33
- animation: toast-exit 180ms ease-in both;
55
+ .toast > button,
56
+ .recovery-actions button {
57
+ border-radius: 6px;
58
+ background: transparent;
34
59
  }
60
+ .toast > button:hover:not(:disabled),
61
+ .recovery-actions button:hover:not(:disabled) {
62
+ background: var(--ui-hover);
63
+ }
64
+ .toast-dismiss {
65
+ width: 36px;
66
+ padding: 0;
67
+ border: 0;
68
+ background: transparent;
69
+ font-size: 20px !important;
70
+ color: inherit;
71
+ }
72
+ .toast-undo { margin-left: 12px; padding: 4px 8px; border: 0; background: transparent; color: var(--accent); font-weight: 500; }
35
73
  .toast.error {
36
- border-color: #e4b5b5;
37
74
  background: #fff7f7;
38
75
  color: #8d1717;
39
- box-shadow: 0 0 0 1px #b13d3d14, 0 4px 16px #5f11110d;
76
+ box-shadow: 0 0 0 1px #b13d3d33, 0 4px 16px #5f11110d;
40
77
  }
41
78
  .toast.error::before {
42
79
  display: grid;
@@ -50,52 +87,51 @@
50
87
  content: "!";
51
88
  font-weight: 600;
52
89
  }
53
- @keyframes toast-enter {
54
- from {
55
- opacity: 0;
56
- transform: translate(-50%, -6px);
57
- }
58
- to {
59
- opacity: 1;
60
- transform: translate(-50%, 0);
61
- }
62
- }
63
- @keyframes toast-exit {
64
- from {
65
- opacity: 1;
66
- transform: translate(-50%, 0);
67
- }
68
- to {
69
- opacity: 0;
70
- transform: translate(-50%, -6px);
71
- }
72
- }
73
90
  .recovery {
74
- position: fixed;
75
91
  bottom: 100px;
76
- left: 50%;
77
- transform: translateX(-50%);
78
- z-index: 50;
79
- display: flex;
80
- justify-content: center;
81
- align-items: center;
92
+ display: grid;
82
93
  gap: 12px;
83
94
  width: max-content;
84
- max-width: min(520px, max(240px, calc(100vw - 744px)), calc(100vw - 40px));
85
- background: var(--ui-surface);
86
- border: 1px solid var(--ui-border);
87
- border-radius: 12px;
88
- box-shadow: var(--ui-shadow);
95
+ max-width: min(420px, calc(100vw - 40px));
89
96
  padding: 12px;
90
- font-size: 13px;
91
- line-height: 1.5;
92
97
  }
93
- .recovery > span {
94
- min-width: 0;
95
- overflow-wrap: anywhere;
98
+ .recovery-actions {
99
+ display: flex;
100
+ flex-wrap: wrap;
101
+ justify-content: flex-end;
102
+ gap: 8px;
96
103
  }
97
- .recovery > button {
98
- flex: none;
104
+ .recovery-actions button {
105
+ min-height: 36px;
106
+ font-size: 12px;
107
+ border: 1px solid var(--ui-border);
108
+ }
109
+ .recovery-actions button:hover:not(:disabled) {
110
+ border-color: var(--ui-control);
111
+ }
112
+ input[aria-invalid="true"] {
113
+ border-color: #b13d3d;
114
+ box-shadow: none;
115
+ }
116
+ input[aria-invalid="true"]:focus-visible {
117
+ outline: 2px solid #b13d3d;
118
+ outline-offset: -1px;
119
+ }
120
+ .parameter-error {
121
+ position: fixed;
122
+ z-index: 60;
123
+ width: 260px;
124
+ padding: 10px 12px;
125
+ border: 1px solid #e4b5b5;
126
+ border-radius: 8px;
127
+ background: #fff7f7;
128
+ color: #8d1717;
129
+ box-shadow: 0 4px 16px #0000000a;
130
+ font-size: 12px;
131
+ line-height: 1.5;
132
+ }
133
+ @media (max-width: 900px) {
134
+ .toast { top: 16px; }
99
135
  }
100
136
  @media (prefers-reduced-motion: reduce) {
101
137
  *,