konpeki 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.
- package/.agents/skills/authoring-visuals/SKILL.md +82 -0
- package/AGENTS.md +33 -0
- package/AUTHORING.md +233 -0
- package/LICENSE +201 -0
- package/README.md +70 -0
- package/SETUP.md +86 -0
- package/composition/README.md +166 -0
- package/composition/compile.ts +227 -0
- package/composition/document.ts +709 -0
- package/composition/schema.json +2992 -0
- package/composition/schema.ts +435 -0
- package/composition/theme-tokens.ts +16 -0
- package/composition/types.ts +286 -0
- package/composition/validate.ts +684 -0
- package/composition/vector.ts +143 -0
- package/composition/visualizations.ts +335 -0
- package/design/README.md +17 -0
- package/design/palettes/README.md +14 -0
- package/design/palettes/base.ts +14 -0
- package/design/palettes/candidates.ts +19 -0
- package/design/palettes/index.ts +78 -0
- package/design/review/color-theme.md +44 -0
- package/design/review/layout.md +16 -0
- package/design/review/text.md +18 -0
- package/design/review/typography.md +15 -0
- package/design/review/visuals.md +31 -0
- package/design/semantic-patterns.md +43 -0
- package/design/themes/README.md +22 -0
- package/design/themes/index.ts +13 -0
- package/design/visual-languages/technical-product.md +17 -0
- package/design/visual-review.md +88 -0
- package/docs/development.md +140 -0
- package/docs/workflow.md +61 -0
- package/index.html +17 -0
- package/lib/assets.d.ts +8 -0
- package/lib/charts.ts +18 -0
- package/lib/contrast.ts +16 -0
- package/lib/layouts.ts +50 -0
- package/lib/slide.tsx +42 -0
- package/lib/taste.ts +17 -0
- package/lib/text.tsx +89 -0
- package/lib/typeface.ts +44 -0
- package/package.json +85 -0
- package/runtime/konpeki.mjs +1685 -0
- package/scripts/migrate-react-page.ts +120 -0
- package/slides/README.md +153 -0
- package/slides/architecture/PROMPT.md +31 -0
- package/slides/architecture/index.tsx +102 -0
- package/slides/article-brief/PROMPT.md +35 -0
- package/slides/article-brief/index.tsx +71 -0
- package/slides/bar-chart/PROMPT.md +39 -0
- package/slides/bar-chart/index.tsx +97 -0
- package/slides/comparison/PROMPT.md +29 -0
- package/slides/comparison/index.tsx +95 -0
- package/slides/decision-memo/PROMPT.md +34 -0
- package/slides/decision-memo/index.tsx +85 -0
- package/slides/delivery-plan/PROMPT.md +45 -0
- package/slides/delivery-plan/index.tsx +105 -0
- package/slides/experiment/PROMPT.md +44 -0
- package/slides/experiment/index.tsx +127 -0
- package/slides/incident-workflow/PROMPT.md +57 -0
- package/slides/incident-workflow/index.tsx +78 -0
- package/slides/introducing-konpeki/PROMPT.md +19 -0
- package/slides/introducing-konpeki/README.md +54 -0
- package/slides/introducing-konpeki/SOURCE.md +20 -0
- package/slides/introducing-konpeki/author.ts +163 -0
- package/slides/introducing-konpeki/composition.json +3265 -0
- package/slides/line-chart/PROMPT.md +40 -0
- package/slides/line-chart/index.tsx +72 -0
- package/slides/migration/PROMPT.md +38 -0
- package/slides/migration/index.tsx +89 -0
- package/slides/og-images/PROMPT.md +21 -0
- package/slides/og-images/index.tsx +76 -0
- package/slides/product-introduction/PROMPT.md +24 -0
- package/slides/product-introduction/index.tsx +105 -0
- package/slides/research-brief/PROMPT.md +40 -0
- package/slides/research-brief/index.tsx +104 -0
- package/slides/results-explanation/PROMPT.md +32 -0
- package/slides/results-explanation/index.tsx +96 -0
- package/slides/retrospective/PROMPT.md +43 -0
- package/slides/retrospective/index.tsx +105 -0
- package/slides/sankey/PROMPT.md +11 -0
- package/slides/sankey/index.tsx +93 -0
- package/slides/teaching/PROMPT.md +45 -0
- package/slides/teaching/index.tsx +124 -0
- package/slides/vertical-bar-charts/PROMPT.md +13 -0
- package/slides/vertical-bar-charts/index.tsx +97 -0
- package/src/app/App.tsx +694 -0
- package/src/assets/konpeki-mark.png +0 -0
- package/src/components/Canvas.tsx +1168 -0
- package/src/components/DiagramTypeIcon.tsx +78 -0
- package/src/components/InspectorPanel.tsx +687 -0
- package/src/components/LeftPanel.tsx +107 -0
- package/src/components/PageSizePicker.tsx +30 -0
- package/src/components/Presentation.tsx +105 -0
- package/src/components/RightPanel.tsx +201 -0
- package/src/components/VectorOverflowWarning.tsx +46 -0
- package/src/components/WorkspaceChrome.tsx +199 -0
- package/src/components/ui.tsx +53 -0
- package/src/lib/examples/react-page-migration.json +1295 -0
- package/src/lib/examples.ts +42 -0
- package/src/lib/export-png.ts +101 -0
- package/src/lib/file-session.ts +74 -0
- package/src/lib/history.ts +53 -0
- package/src/lib/model.ts +188 -0
- package/src/lib/page-size.ts +24 -0
- package/src/lib/presentation.ts +17 -0
- package/src/lib/storage.ts +43 -0
- package/src/lib/theme.ts +25 -0
- package/src/lib/use-file-session.ts +162 -0
- package/src/main.tsx +26 -0
- package/src/styles/base.css +105 -0
- package/src/styles/canvas.css +268 -0
- package/src/styles/chrome.css +214 -0
- package/src/styles/component-previews.css +386 -0
- package/src/styles/feedback.css +71 -0
- package/src/styles/left-panel.css +125 -0
- package/src/styles/presentation.css +72 -0
- package/src/styles/right-panel.css +1172 -0
- package/src/styles/shell.css +247 -0
- package/vite.config.ts +6 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Color / theme review
|
|
2
|
+
|
|
3
|
+
Owns palette use across the deck. Apply existing
|
|
4
|
+
[theme guidance](../../AUTHORING.md#taste-and-creative-freedom) and
|
|
5
|
+
[color roles](../palettes/README.md); this category adds no new style rules.
|
|
6
|
+
|
|
7
|
+
- Check palette roles, background and visual emphasis against the brief and
|
|
8
|
+
selected mode. Both modes use the original white-background/main-accent
|
|
9
|
+
fallback unless the user supplies another direction. Dynamic permits local
|
|
10
|
+
emphasis fills, not an automatic dark or colored canvas.
|
|
11
|
+
- Check text/mark contrast on actual surfaces at viewing size. Confirm category
|
|
12
|
+
and status meanings stay consistent and have cues beyond color alone.
|
|
13
|
+
|
|
14
|
+
Leave font rendering to typography and container structure to visuals.
|
|
15
|
+
Use the shared [review process](../visual-review.md#independent-review).
|
|
16
|
+
|
|
17
|
+
## Measure a declared solid pair
|
|
18
|
+
|
|
19
|
+
Use [contrastRatio](../../lib/contrast.ts) for opaque six-digit sRGB hex colors.
|
|
20
|
+
From the kit directory, this checks one declared normal-text pair:
|
|
21
|
+
|
|
22
|
+
```sh
|
|
23
|
+
node --input-type=module <<'JS'
|
|
24
|
+
import { contrastRatio } from './lib/contrast.ts';
|
|
25
|
+
const foreground = '#505B68', background = '#FFFFFF';
|
|
26
|
+
const ratio = contrastRatio(foreground, background);
|
|
27
|
+
console.log({ foreground, background, ratio, minimum: 4.5 });
|
|
28
|
+
if (ratio < 4.5) process.exitCode = 1;
|
|
29
|
+
JS
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Use actual palette roles or rendered values for the pair under review. Record
|
|
33
|
+
the page/element, pair, ratio and applicable threshold. Compare the unrounded
|
|
34
|
+
ratio: rounding 4.478 to 4.5 does not make it pass. Normal text needs 4.5:1;
|
|
35
|
+
large text can use 3:1 only when it qualifies at the delivered size (at least
|
|
36
|
+
24 CSS px regular or about 18.67 CSS px bold). A 32-unit SVG label scaled to
|
|
37
|
+
half size is not 32 CSS px. Contrast does not establish comfortable readability.
|
|
38
|
+
|
|
39
|
+
This helper does not discover backgrounds, classify text, composite opacity or
|
|
40
|
+
inspect images, gradients and overlapping shapes. Confirm the solid pair really
|
|
41
|
+
applies in the render. For other surfaces, measure the actual composite with an
|
|
42
|
+
appropriate tool and inspect the result; otherwise report contrast as Not verified.
|
|
43
|
+
Never report an unmeasured ratio. The existing theme browser check's containing-
|
|
44
|
+
rectangle assumption remains specimen-specific, not a general background solver.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Layout review
|
|
2
|
+
|
|
3
|
+
Owns composition and spatial relationships. Inspect the rendered deck for
|
|
4
|
+
reading order, grouping and balance. Leave glyph readability to typography,
|
|
5
|
+
diagram meaning and container structure to visuals, and factual claims to text review.
|
|
6
|
+
|
|
7
|
+
| Check | Guidance |
|
|
8
|
+
| --- | --- |
|
|
9
|
+
| Content balance | Recompose when one column runs far below its neighbor and leaves a stranded empty area. Equal heights are unnecessary. |
|
|
10
|
+
| Heading attachment | Give the heading more separation from the preceding section than from its own content. Respect visible group boundaries. |
|
|
11
|
+
| Evidence-led emphasis | Question the giant-number, small-label, supporting-stats formula. Use it when the metric explains the point, with scope and evidence intact. |
|
|
12
|
+
| Meaningful grouping | Repeated icon–heading–body cards can flatten different ideas into equal weight. Group and prioritize according to meaning. |
|
|
13
|
+
| Paired-row alignment | Align short headings with the first line of their descriptions, not the vertical center of multiline copy. Check visible text alignment as well as element bounds. |
|
|
14
|
+
| Spacing hierarchy | Avoid identical gaps between unrelated sections and within closely related content. A consistent spacing scale is still useful. |
|
|
15
|
+
|
|
16
|
+
Use the shared [review process](../visual-review.md#independent-review).
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Text review
|
|
2
|
+
|
|
3
|
+
Owns meaning and wording. Use the brief and sources to verify claims and caveats;
|
|
4
|
+
apply the [writing tone](../../AUTHORING.md#writing-tone). Leave font size and
|
|
5
|
+
visual placement to typography/layout review.
|
|
6
|
+
|
|
7
|
+
| Check | Guidance |
|
|
8
|
+
| --- | --- |
|
|
9
|
+
| Headline first | Inspect the rendered reading order against the authoring policy. For every eyebrow, brand label and numbered section heading, name the information lost if it were removed. Remove it when that information is already supplied by the headline, nearby content or page navigation, unless explicitly requested. Preserve essential context and required attribution. |
|
|
10
|
+
| Information economy | Avoid restating one message in a card’s headline, badge and note. Repeated values in tables or parallel items can be necessary. |
|
|
11
|
+
| Page purpose | State the audience question answered by the page. Can a reader identify the current state, the decision or mechanism, and its consequence without narration? Replace abstract choice labels and ambiguous pronouns with concrete outcomes and named actors. |
|
|
12
|
+
| Metadata versus evidence | Remove recurring deck metadata unless requested or required. Keep page-specific citations, units, synthetic-data disclosures and material caveats with the evidence; do not remove those as footer clutter. |
|
|
13
|
+
| Relevant limitations | Attach requirements and limits to the mechanism or claim they constrain. Do not give unrelated caveats equal weight on a next-action page or hide essential limits in notes merely to reduce density. |
|
|
14
|
+
| Sentence rhythm | Check for a repeated dash-heavy cadence across the copy. Keep occasional dashes that improve reading. |
|
|
15
|
+
| Concrete claims | Name the capability or supported outcome. Remove claims that could describe any product. |
|
|
16
|
+
| Direct explanation | Remove manufactured rebuttals such as “Not a feature. A platform.” and “not X, but Y.” Explain genuine distinctions directly. |
|
|
17
|
+
|
|
18
|
+
Use the shared [review process](../visual-review.md#independent-review).
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Typography review
|
|
2
|
+
|
|
3
|
+
Owns text rendering and reading comfort. Inspect full/half-size renders for
|
|
4
|
+
legibility, hierarchy, wrapping and clipping; verify actual fonts and weights
|
|
5
|
+
against the chosen [theme](../themes/README.md). Leave wording to text review
|
|
6
|
+
and section placement to layout review.
|
|
7
|
+
|
|
8
|
+
| Check | Guidance |
|
|
9
|
+
| --- | --- |
|
|
10
|
+
| Font category | Both modes use sans-serif unless the brief directs otherwise. Dynamic may vary typographic emphasis without changing the font category. Verify language coverage, loaded weights and readability in both modes. |
|
|
11
|
+
| Useful numbering | Remove repeated micro-indices beside headings when they add no ordering information. Keep useful step and page numbers readable. |
|
|
12
|
+
| Subheading distinction | Apply the mode table: default requires typographic emphasis; dynamic may establish hierarchy through placement, color or grouping. Check the result at review size. |
|
|
13
|
+
| Readable line measure | Keep paragraph lines easy to track into the next line. Judge the actual font and viewing size; avoid imposing a web character limit on every slide label. |
|
|
14
|
+
|
|
15
|
+
Use the shared [review process](../visual-review.md#independent-review).
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Visuals review
|
|
2
|
+
|
|
3
|
+
Owns diagrams, charts, imagery and containers. Apply the existing
|
|
4
|
+
[accuracy requirements](../../AUTHORING.md#requirements): verify arrow direction,
|
|
5
|
+
label/value associations, chart scales, asset provenance and faithful crops.
|
|
6
|
+
Text review verifies the underlying claims; this review checks their visual encoding.
|
|
7
|
+
Leave page arrangement to layout and color assignments to color/theme.
|
|
8
|
+
|
|
9
|
+
Apply the [mode table](../../AUTHORING.md#authoring-mode) first. The allowances
|
|
10
|
+
below for emphasis fills, framing, reinforcing arrows and filled heads apply to
|
|
11
|
+
dynamic mode or an explicit user direction; they do not override default mode's
|
|
12
|
+
original restrictions. Geometry and factual checks apply in both modes.
|
|
13
|
+
|
|
14
|
+
| Check | Guidance |
|
|
15
|
+
| --- | --- |
|
|
16
|
+
| Visual explanation | Would a diagram, image or annotated artifact make the relationships easier to grasp? Do not accept prose-only treatment merely because it is in bounds, or require a diagram when it adds nothing. |
|
|
17
|
+
| Purposeful boundaries | Judge whether surfaces improve grouping, emphasis or reading order in the chosen direction. Remove competing layers, not all layers that could be replaced by whitespace. Keep meaningful object boundaries and actual controls. |
|
|
18
|
+
| Rules and frames | Dividers must stop at the region they separate, not cross shared copy or subsequent sections. Give text clearance from borders and accent rules. Frames and rails may support grouping or emphasis; distinguish intentional treatment from accidental-looking missing edges. |
|
|
19
|
+
| Paragraphs versus rows | Apply the authoring boundary policy: independent text groups can use whitespace; corresponding table or paired rows may benefit from rules. If rules establish the rows, check for a clear ending before notes, usually a bottom rule. Do not require borders merely because text has columns. |
|
|
20
|
+
| Table ending versus page footer | A closing rule belongs to the table it ends. Do not extend it to the page bottom or add a second separator for generic metadata or a standalone page number. |
|
|
21
|
+
| Canvas padding | Check preview and requested export for unintended padding around differently proportioned artwork. Use the intended aspect ratio where supported or compose the surrounding space deliberately; intentional color bands are not a defect. |
|
|
22
|
+
| Emphasis backgrounds | Does the fill help the audience notice, group or navigate the content? Hierarchy, rhythm and emphasis are valid uses alongside state and evidence. Check contrast and avoid competing emphasis; when color encodes meaning, check that labels or symbols agree. |
|
|
23
|
+
| Connector endpoints | Every arrow needs an identifiable source and destination: a node, participant, lane or explicit continuation. Boxes are optional; meaningful attachment is not. Check what each endpoint refers to, not just its coordinates or alignment. Connectors should meet their intended anchors without stray tails or gaps; extend beyond them only to convey meaning. |
|
|
24
|
+
| Connector routing | Optimize for a clear, coherent route, not the fewest bends. Orthogonal corners are welcome when they support reading order, aligned entry/exit points or label placement. Remove needless doglegs, but do not replace useful elbows with awkward diagonal fans or detach a sequence rail from its stages. Place turns deliberately, with clearance from nodes, labels, boundaries and other connectors; avoid near-touches or crossings that imply unintended junctions. |
|
|
25
|
+
| Corresponding bends | For equivalent or mirrored relationships, check that turn positions, offsets and spacing align or mirror consistently. Preserve asymmetry when different endpoints, obstacles or meanings require it; do not add bends merely to force symmetry. |
|
|
26
|
+
| Arrow purpose | Check that arrows make the intended relationship easier to follow without implying unsupported transitions or dependencies. Reinforcing a relationship stated in words is useful when it speeds understanding, not automatically redundant. |
|
|
27
|
+
| Arrowheads | Open and filled heads are valid. Check consistency with the chosen notation, alignment with shafts, and clean joins without spikes, gaps or protruding stems. Inspect at full and review size. |
|
|
28
|
+
|
|
29
|
+
Inspect the render: DOM nesting alone cannot establish whether a boundary helps,
|
|
30
|
+
and an HTML card detector can miss nested SVG shapes.
|
|
31
|
+
Use the shared [review process](../visual-review.md#independent-review).
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Choose a visual by meaning
|
|
2
|
+
|
|
3
|
+
Start with the audience's question, not a favorite layout. These are choices,
|
|
4
|
+
not templates. Choose the primary medium from the source, audience and brief;
|
|
5
|
+
plain text or a large image may be enough. Authoring mode changes visual rules, not
|
|
6
|
+
the truth of the relationships. More detail requires more supported explanation,
|
|
7
|
+
not more nodes or arrows by default.
|
|
8
|
+
|
|
9
|
+
## Pick the relationship
|
|
10
|
+
|
|
11
|
+
| Question | Pattern | Keep clear |
|
|
12
|
+
| --- | --- | --- |
|
|
13
|
+
| What happens next? | Process / sequence | Input, steps, output and blockers. Label branches and return paths; pending is not approved. |
|
|
14
|
+
| Which option fits? | Comparison / decision | Same criteria, units and scope. Explain the recommendation without hiding drawbacks or inventing scores. |
|
|
15
|
+
| What belongs to what? | Hierarchy / containment | Consistent parent–child meaning. Use a map when shared ownership or cross-links matter. |
|
|
16
|
+
| What connects? | System map | Named entities, meaningful boundaries and labeled connections. Use a sequence when event order is the story. |
|
|
17
|
+
| What should I notice? | Annotated detail | Enough context to locate the detail, large evidence and nearby labels. Identify crops and mockups; don't invent specifications. |
|
|
18
|
+
|
|
19
|
+
Choose theme and composition to suit the relationship. Any pattern can be
|
|
20
|
+
restrained or expressive; decorative shapes must not imply data.
|
|
21
|
+
|
|
22
|
+
## Infer the form; preserve the meaning
|
|
23
|
+
|
|
24
|
+
People do not need to name a diagram or chart type. In Auto, infer a suitable form
|
|
25
|
+
from the goal, audience, supplied relationships and data. An explicitly selected form is binding:
|
|
26
|
+
preserve it and ask before switching, including to another component kind. Never
|
|
27
|
+
silently reset explicit selection to Auto. Honor notation requested in the intent
|
|
28
|
+
or brief even in Auto. When ambiguity changes the explanation, ask what should be emphasized rather than
|
|
29
|
+
asking the person to choose from a taxonomy.
|
|
30
|
+
|
|
31
|
+
Keep specialized semantics when they matter: message order in a sequence,
|
|
32
|
+
guarded transitions in a state machine, enclosure for containment, and honest
|
|
33
|
+
scales for quantities. Use editable vectors when a standard draft cannot express
|
|
34
|
+
them. In Auto, update the returned diagram type or chart template to match the chosen form
|
|
35
|
+
without changing its selection mode.
|
|
36
|
+
|
|
37
|
+
Diagram Design and Archify are references, not product specifications. Borrow
|
|
38
|
+
useful techniques with attribution; do not pursue their catalog coverage or
|
|
39
|
+
force domain recipes into first-class types. Evaluate the result against the
|
|
40
|
+
explanation goal, factual fidelity and editability.
|
|
41
|
+
|
|
42
|
+
Render and inspect: is the relationship clear without narration? Are facts,
|
|
43
|
+
arrows and labels correct and readable? No aesthetic score or required layout.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Themes
|
|
2
|
+
|
|
3
|
+
Themes combine font roles and a referenced color palette, not a slide layout.
|
|
4
|
+
|
|
5
|
+
Use [authoring guidance](../../AUTHORING.md#taste-and-creative-freedom) for theme
|
|
6
|
+
selection, font defaults and deck-wide consistency.
|
|
7
|
+
|
|
8
|
+
```ts
|
|
9
|
+
import { getTheme } from './design/themes/index.ts';
|
|
10
|
+
const theme = getTheme('Plex', 'paper');
|
|
11
|
+
// theme.body, theme.headline, theme.typography, theme.palette
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Eight light/dark themes: Plex, Precision, Editorial, Blue–cyan, Orange–coral,
|
|
15
|
+
Yellow, Green and Graphite. Precision uses Noto Sans; Editorial uses Plex Serif
|
|
16
|
+
headlines with Plex Sans body; the others use Plex Sans. Font loading remains
|
|
17
|
+
the author's responsibility; load the required Fontsource Latin weights before
|
|
18
|
+
measuring or rendering text.
|
|
19
|
+
|
|
20
|
+
Mineral and Botanical are light-only palette candidates in
|
|
21
|
+
[palettes/candidates.ts](../palettes/candidates.ts).
|
|
22
|
+
A theme does not impose geometry, density or supporting-text sizes.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { typography } from '../../lib/taste.ts';
|
|
2
|
+
import { paletteNames, resolvePalette, type PaletteName, type PaletteMode } from '../palettes/index.ts';
|
|
3
|
+
|
|
4
|
+
export const themeNames = paletteNames;
|
|
5
|
+
export type ThemeName = PaletteName;
|
|
6
|
+
export type ThemeMode = PaletteMode;
|
|
7
|
+
|
|
8
|
+
// Themes combine typography with a palette; they do not choose a composition.
|
|
9
|
+
export function getTheme(name: ThemeName, mode: ThemeMode) {
|
|
10
|
+
const body = name === 'Precision' ? '"Noto Sans", sans-serif' : typography.family;
|
|
11
|
+
const headline = name === 'Editorial' ? '"IBM Plex Serif", serif' : body;
|
|
12
|
+
return { name, body, headline, typography: { ...typography, family: body }, palette: resolvePalette(name, mode) };
|
|
13
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Technical product
|
|
2
|
+
|
|
3
|
+
Use for product explanations, processes and comparisons where a concrete visual
|
|
4
|
+
can carry the argument. This is art direction, not a palette or a fixed template.
|
|
5
|
+
|
|
6
|
+
- Give the product/interface/output enough space to explain the claim.
|
|
7
|
+
- Apply the selected mode's framing and emphasis rules; do not flatten
|
|
8
|
+
unrelated content into equally prominent boxes.
|
|
9
|
+
- Connect a process to its tangible output. Keep labels near their connectors.
|
|
10
|
+
- Make selection/recommendation distinct without obscuring alternatives.
|
|
11
|
+
- Keep diagrams and annotations readable at the intended viewing size. Shared
|
|
12
|
+
card headers round outer top corners only, not the internal bottom seam.
|
|
13
|
+
- Avoid importing website density, tiny gray labels, ubiquitous registration
|
|
14
|
+
marks, or scroll effects into slides.
|
|
15
|
+
|
|
16
|
+
Works with Blue–cyan light or Graphite dark; these are examples, not limits.
|
|
17
|
+
Reference: [user-supplied website video](https://video.twimg.com/amplify_video/2097350430993072128/vid/avc1/2306x2160/IgjnX7Duukk4W54G.mp4).
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Focused visual review
|
|
2
|
+
|
|
3
|
+
Choose the relevant categories for the work. Each owns its checks; shared
|
|
4
|
+
requirements remain in [AUTHORING](../AUTHORING.md). Apply judgment to the
|
|
5
|
+
content; no automatic bans or aesthetic score.
|
|
6
|
+
|
|
7
|
+
All categories apply the selected [authoring mode](../AUTHORING.md#authoring-mode)
|
|
8
|
+
and explicit brief. Default uses the original visual restrictions; dynamic
|
|
9
|
+
relaxes only the rules named in the mode table. That table takes precedence over
|
|
10
|
+
general suggestions below and in category guides. Do not impose default-only
|
|
11
|
+
restrictions on dynamic work or require dynamic work to add effects. Judge
|
|
12
|
+
explanation structure and depth against the source, audience and brief.
|
|
13
|
+
Correctness, readability and source fidelity remain non-negotiable in both modes.
|
|
14
|
+
Report a mode mismatch separately from a factual/access defect or taste preference.
|
|
15
|
+
|
|
16
|
+
| Category | Scope |
|
|
17
|
+
| --- | --- |
|
|
18
|
+
| [Text](review/text.md) | Meaning, claims, repetition and writing tone |
|
|
19
|
+
| [Typography](review/typography.md) | Font rendering, text hierarchy and reading comfort |
|
|
20
|
+
| [Layout](review/layout.md) | Composition, grouping, spacing and comparisons |
|
|
21
|
+
| [Color / theme](review/color-theme.md) | Deck-wide direction, contrast and semantic color roles |
|
|
22
|
+
| [Visuals](review/visuals.md) | Diagrams, charts, imagery and meaningful boundaries |
|
|
23
|
+
|
|
24
|
+
## Independent review
|
|
25
|
+
|
|
26
|
+
For a small change, review directly. When useful and subagents are available,
|
|
27
|
+
assign independent categories concurrently. Give each reviewer the same brief,
|
|
28
|
+
chosen direction, source and full/half-size renders, plus its category file.
|
|
29
|
+
Reviewers inspect their scope without editing files or reading each other's findings.
|
|
30
|
+
|
|
31
|
+
Return only meaningful findings: **priority · page/element · evidence · reader
|
|
32
|
+
impact · suggested fix**. Distinguish observed defects from design suggestions;
|
|
33
|
+
list checks not performed as **Not verified**, not as defects or passes.
|
|
34
|
+
An empty finding list is valid.
|
|
35
|
+
The coordinator deduplicates cross-category issues, resolves conflicting fixes
|
|
36
|
+
against the brief, and checks narrative flow and deck coherence. Report a shared
|
|
37
|
+
root cause once, naming affected pages. Apply fixes in one editing pass,
|
|
38
|
+
then re-render affected pages and repeat relevant checks.
|
|
39
|
+
|
|
40
|
+
## Repair order
|
|
41
|
+
|
|
42
|
+
1. **Accuracy:** factual errors, misleading scales, missing qualifications and
|
|
43
|
+
incorrect relationships.
|
|
44
|
+
2. **Access to content:** unreadable, missing or clipped essential content,
|
|
45
|
+
color-only meaning and inaccessible interactions when present.
|
|
46
|
+
3. **Understanding:** grouping, reading order, hierarchy and deck coherence.
|
|
47
|
+
4. **Polish:** optical alignment, decorative details and surface consistency.
|
|
48
|
+
|
|
49
|
+
Judge whether the treatment helps the audience, not whether it could be removed.
|
|
50
|
+
A repair may add a diagram, color field or annotation, or remove competing
|
|
51
|
+
material. Reuse existing primitives where useful; never delete required evidence to improve fit.
|
|
52
|
+
Repair upstream causes first: a cramped region may need recomposition rather
|
|
53
|
+
than separate font-size, line-break and padding changes.
|
|
54
|
+
|
|
55
|
+
### Repair examples
|
|
56
|
+
|
|
57
|
+
These are diagnostic examples, not measured findings or mandatory layouts.
|
|
58
|
+
Render the repair with real content to judge whether it helps.
|
|
59
|
+
|
|
60
|
+
| Before | After | Why |
|
|
61
|
+
| --- | --- | --- |
|
|
62
|
+
| A heading sits equally far from the preceding section and its own paragraph. | Move it nearer its paragraph and increase separation from the preceding section. | Proximity makes ownership clear without another box. |
|
|
63
|
+
| A wide diagram leaves its evidence and caveat in tiny side text. | Give the evidence a larger region or split the page while retaining the qualification. | Essential context becomes readable without shrinking the diagram's labels. |
|
|
64
|
+
| A large value dominates a faint unit and denominator. | Keep unit and denominator adjacent and readable; reduce the value's dominance if needed. | The reader can interpret the number rather than just notice it. |
|
|
65
|
+
| Every sentence sits in an equally prominent nested panel. | Reduce competing layers; retain surfaces that support grouping, emphasis or the chosen direction. | The audience can distinguish the main point from supporting material. |
|
|
66
|
+
| A prose list makes readers reconstruct a request journey. | Draw the named participants and labeled connections, retaining useful explanatory copy. | Relationships become easier to follow even though words already describe them. |
|
|
67
|
+
|
|
68
|
+
## Accessibility and delivery
|
|
69
|
+
|
|
70
|
+
Apply checks to the requested format, at its actual viewing size. These are
|
|
71
|
+
delivery checks, not a claim of full accessibility conformance.
|
|
72
|
+
The author (or coordinator when review is delegated) owns this checklist and
|
|
73
|
+
records evidence or **Not verified** for every applicable check.
|
|
74
|
+
|
|
75
|
+
- Check captions, sources, units and caveats as carefully as the headline.
|
|
76
|
+
Keep category and state meanings available through labels, shapes or patterns,
|
|
77
|
+
not color alone. Measure contrast on actual surfaces; see [color review](review/color-theme.md).
|
|
78
|
+
- For browser slides, provide meaningful accessible descriptions or a text
|
|
79
|
+
equivalent for visual content. Check reading order and that chart alternatives
|
|
80
|
+
convey the conclusion and relevant values, not merely “chart.” Confirm the
|
|
81
|
+
content is exposed in the accessibility tree; source markup alone is insufficient.
|
|
82
|
+
- When controls or motion are included, exercise keyboard navigation, visible
|
|
83
|
+
focus and accessible control names. Check the reduced-motion path and ensure
|
|
84
|
+
state changes remain understandable without animation. Keep runtime fixes
|
|
85
|
+
upstream rather than building a second navigation or export system.
|
|
86
|
+
- Inspect each requested export for text, fonts, reading order and alternatives
|
|
87
|
+
as applicable. Browser/PNG success does not establish accessible PDF/PPTX or
|
|
88
|
+
cross-application fidelity. Report unsupported or untested delivery properties.
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# Development
|
|
2
|
+
|
|
3
|
+
Clone `https://github.com/vcfgdev/konpeki.git` with the required repository access.
|
|
4
|
+
Use [mise](https://mise.jdx.dev/getting-started.html) to install the Node.js and
|
|
5
|
+
pnpm versions pinned in `mise.toml`. On macOS, install mise with `brew install mise`.
|
|
6
|
+
From the repository root:
|
|
7
|
+
|
|
8
|
+
```sh
|
|
9
|
+
mise trust
|
|
10
|
+
mise install
|
|
11
|
+
mise exec -- pnpm install --frozen-lockfile
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Mise manages the toolchain; pnpm manages dependencies through `pnpm-lock.yaml`.
|
|
15
|
+
Run the commands below from that repository root with an activated mise shell,
|
|
16
|
+
or prefix them with `mise exec --` (for example, `mise exec -- pnpm test`).
|
|
17
|
+
No global Node.js or pnpm installation is required. npm for packing and publishing
|
|
18
|
+
comes with the pinned Node.js; use `mise exec -- npm pack` to select it explicitly.
|
|
19
|
+
|
|
20
|
+
Development and regression checks require a repository checkout, not an npm
|
|
21
|
+
tarball, which excludes tests and review scripts.
|
|
22
|
+
|
|
23
|
+
## Development server and demo hosting
|
|
24
|
+
|
|
25
|
+
```sh
|
|
26
|
+
pnpm dev
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
For a production preview, run `pnpm build` then `pnpm preview`. The build produces
|
|
30
|
+
a static site in `dist` for a root or subdirectory. Use
|
|
31
|
+
`?example=introducing-konpeki` or `?example=custom-visual` to open a bundled editable
|
|
32
|
+
example. Example links do not autosave; open a composition in a file-backed
|
|
33
|
+
session to preserve edits.
|
|
34
|
+
|
|
35
|
+
Hosting shares bundled examples, not private drafts, arbitrary documents or an
|
|
36
|
+
AI service. No deployment is automatic. In a remote environment, expose the
|
|
37
|
+
server through its authenticated preview mechanism; a local address is not a
|
|
38
|
+
shareable URL.
|
|
39
|
+
|
|
40
|
+
## Implementation reference
|
|
41
|
+
|
|
42
|
+
- `src/` contains the shared canvas application for editing and presentation.
|
|
43
|
+
The [versioned composition contract](../composition/README.md) preserves
|
|
44
|
+
content, relationships and visual intent across human and agent revisions.
|
|
45
|
+
- `bin/` contains the file-session CLI and its revision-checked persistence.
|
|
46
|
+
- [AUTHORING.md](../AUTHORING.md) owns design defaults, factual fidelity and review.
|
|
47
|
+
[Design resources](../design/README.md) provide palettes, themes and semantic
|
|
48
|
+
patterns; these are choices, not mandatory layouts.
|
|
49
|
+
- `lib/text.tsx` supplies measured `Text` and `Paragraphs` with string or rich-text
|
|
50
|
+
runs. Overset content is flagged, not automatically shrunk or hidden. Await
|
|
51
|
+
`fontsReady` from `lib/typeface.ts` before measuring.
|
|
52
|
+
- `lib/slide.tsx` supplies specimen `Panel`, `Relationship` and 1920×1080 `Sheet`
|
|
53
|
+
components. `Panel` shares one heading/body size; `Relationship` is a short
|
|
54
|
+
directional glyph. Convert their SVG output to composition vectors for the canvas.
|
|
55
|
+
- `lib/layouts.ts` supplies fixed-gutter regions, not a content-fitting solver.
|
|
56
|
+
- Retained React chart references use Nivo `Bar`, `Line` and `Sankey` with
|
|
57
|
+
`chartDefaults(palette)` from `lib/charts.ts` spread before chart-specific props.
|
|
58
|
+
Keep data, dimensions, scales and semantic colors in the deck. Use explicit
|
|
59
|
+
label colors and `linkBlendMode="normal"` for Sankey.
|
|
60
|
+
|
|
61
|
+
### React/SVG drawing references
|
|
62
|
+
|
|
63
|
+
The retained `slides/*/index.tsx` files are presentation-runtime-independent
|
|
64
|
+
drawing references. They are checked as source but are not discovered as routes
|
|
65
|
+
or executed by a second presentation runtime. New decks use composition JSON;
|
|
66
|
+
a trusted build may render React to SVG, then convert supported elements into
|
|
67
|
+
the owning component's editable vector payload.
|
|
68
|
+
|
|
69
|
+
To migrate the retained architecture reference into the shared canvas:
|
|
70
|
+
|
|
71
|
+
```sh
|
|
72
|
+
pnpm example:migrate-page slides/architecture/index.tsx all /tmp/architecture-composition.json
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Drag the resulting JSON onto the canvas, edit its vectors, and use **Present**.
|
|
76
|
+
Replace `all` with a zero-based page index for one page. This command executes
|
|
77
|
+
trusted local React source; never use it on untrusted JSX. It rejects unsupported
|
|
78
|
+
SVG elements rather than silently flattening them. Review converted typography
|
|
79
|
+
and geometry in the browser; conversion is not a fidelity guarantee.
|
|
80
|
+
The bundled `?example=react-page-migration` preview uses the same format.
|
|
81
|
+
Example previews do not autosave; use a file-backed session to save edits.
|
|
82
|
+
|
|
83
|
+
## Package contents
|
|
84
|
+
|
|
85
|
+
`package.json` explicitly allowlists the npm payload: the source-based Vite
|
|
86
|
+
runtime and file-session CLI, authoring guidance and design resources, and named
|
|
87
|
+
curated examples with editable source and prompts. New example directories are
|
|
88
|
+
not included automatically. Gallery screenshots, tests, research fixtures,
|
|
89
|
+
browser review scripts, original branding assets, lockfiles and UI build output
|
|
90
|
+
stay in the repository.
|
|
91
|
+
|
|
92
|
+
`npm pack` builds the JavaScript CLI in `runtime/` automatically because Node
|
|
93
|
+
cannot load its TypeScript source from inside `node_modules`. That generated
|
|
94
|
+
CLI is included in the package.
|
|
95
|
+
|
|
96
|
+
Run `pnpm check:package` before preparing a release. It checks npm's file selection,
|
|
97
|
+
required resources, excluded development files and relative imports. For an
|
|
98
|
+
installation smoke test, use `npm pack --pack-destination <temporary-dir>`, install
|
|
99
|
+
the tarball in an empty project, then run its `konpeki validate` and `konpeki preview`
|
|
100
|
+
commands against a composition outside the installed package. Do not publish
|
|
101
|
+
until that isolated preview works. Publish the tested tarball rather than
|
|
102
|
+
rebuilding during publication. Packing locally does not publish anything.
|
|
103
|
+
|
|
104
|
+
## Verification
|
|
105
|
+
|
|
106
|
+
```sh
|
|
107
|
+
pnpm check
|
|
108
|
+
pnpm test
|
|
109
|
+
pnpm build
|
|
110
|
+
pnpm check:package
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
With the dev server running and `agent-browser` installed:
|
|
114
|
+
|
|
115
|
+
```sh
|
|
116
|
+
node scripts/check-canvas.mjs http://localhost:4318 .amp/in/artifacts
|
|
117
|
+
node scripts/check-pages.mjs http://localhost:4318 .amp/in/artifacts/pages
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
These checks exercise all five component kinds, empty slides, JSON round trips,
|
|
121
|
+
vector editing/history and fitted line dragging. They capture editor and
|
|
122
|
+
presentation states at two sizes; inspect the images because assertions alone
|
|
123
|
+
do not establish visual correctness.
|
|
124
|
+
|
|
125
|
+
Documentation changes need link and instruction checks. Deck changes need
|
|
126
|
+
typecheck, build, relevant fixture checks and actual visual inspection. Shared
|
|
127
|
+
component, theme or dependency changes also need the full test suite and
|
|
128
|
+
representative affected decks. A build can report a large-framework-chunk advisory.
|
|
129
|
+
|
|
130
|
+
Render affected pages at presentation and review sizes after fonts load. Inspect
|
|
131
|
+
text, clipping, relationships, contrast and cross-page consistency. Repair issues
|
|
132
|
+
and inspect fresh captures. Keep browser checks scoped to factual and layout
|
|
133
|
+
contracts, not universal taste. Record untested outputs and limitations with
|
|
134
|
+
the example; screenshots do not prove PDF/PPTX or cross-application fidelity.
|
|
135
|
+
|
|
136
|
+
When adding examples, preserve the exact creative requests, editable source,
|
|
137
|
+
source facts and reviewed images as described in [AUTHORING.md](../AUTHORING.md).
|
|
138
|
+
Examples demonstrate capabilities; there is no separate benchmark suite or
|
|
139
|
+
aesthetic score. Check font language subsets and license notices when
|
|
140
|
+
redistributing assets; dependencies retain their own licenses.
|
package/docs/workflow.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Canvas workflow
|
|
2
|
+
|
|
3
|
+
Start with the [quickstart](../README.md#start-in-your-coding-agent) and give your
|
|
4
|
+
coding agent a brief in its prompt field. Keep the skill with the project:
|
|
5
|
+
copying `SKILL.md` alone does not install Konpeki. Skill discovery varies by
|
|
6
|
+
agent; there is no universal `/konpeki` command.
|
|
7
|
+
|
|
8
|
+
## Documents and exports
|
|
9
|
+
|
|
10
|
+
New documents live in `slides/<name>/composition.json`, with `PROMPT.md`, source
|
|
11
|
+
notes and reviewed images alongside. Keep the editable composition under version
|
|
12
|
+
control. The canvas is the source of truth for editing and presentation; download
|
|
13
|
+
its JSON for handoff and drag returned JSON onto the canvas to continue.
|
|
14
|
+
|
|
15
|
+
One page is a complete creation. Presets cover Presentation (1920×1080), Square
|
|
16
|
+
post (1080×1080), Portrait post (1080×1350), Link preview / OG (1200×630), and
|
|
17
|
+
Article header (1600×600). The document contract supports 256–4096 pixels per side.
|
|
18
|
+
Pages in one document may use different sizes. Changing size never stretches
|
|
19
|
+
content and is refused when existing components would fall outside the page.
|
|
20
|
+
Recompose for a new aspect ratio instead of stretching or cropping.
|
|
21
|
+
|
|
22
|
+
**Export PNG** saves the active page at its declared dimensions without editor
|
|
23
|
+
controls. JSON remains the editable source; PNG is an image. Fresh documents and
|
|
24
|
+
added pages are empty. **Present** uses the same renderer for any page sequence.
|
|
25
|
+
|
|
26
|
+
Standard Chart, Diagram and Table illustrations are structural drafts. Finished
|
|
27
|
+
artwork can remain owned by its semantic component as editable vector elements.
|
|
28
|
+
Retained React/SVG examples are drawing references, not another deck runtime.
|
|
29
|
+
|
|
30
|
+
## File-backed editing with an agent
|
|
31
|
+
|
|
32
|
+
The CLI interface is `konpeki <command>`. After local installation, use
|
|
33
|
+
`npm exec --no -- konpeki <command>` from your workspace. In a repository checkout,
|
|
34
|
+
use the development shim `pnpm konpeki <command>` instead:
|
|
35
|
+
|
|
36
|
+
```sh
|
|
37
|
+
npm exec --no -- konpeki validate slides/my-visual/composition.json
|
|
38
|
+
npm exec --no -- konpeki preview slides/my-visual/composition.json
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
`preview` prints a capability-bearing local URL. Open that exact URL. Valid
|
|
42
|
+
browser edits are saved atomically to the composition file; a revision hash
|
|
43
|
+
prevents overwriting concurrent external changes. When an agent updates the same
|
|
44
|
+
file, the canvas loads the valid revision and keeps the previous document in Undo.
|
|
45
|
+
|
|
46
|
+
An agent waiting for a person's revision request runs:
|
|
47
|
+
|
|
48
|
+
```sh
|
|
49
|
+
npm exec --no -- konpeki wait slides/my-visual/composition.json
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
In the file-backed canvas, **Build it** saves the composition and submits the
|
|
53
|
+
exact revision, active page and optional selected component. `wait` prints that
|
|
54
|
+
machine-readable request and exits. It does not launch or wake an agent itself.
|
|
55
|
+
The listening agent must reread the named composition, preserve unrelated human
|
|
56
|
+
edits, validate, render and inspect its revision before returning. Browser-local
|
|
57
|
+
drafts and hosted examples do not expose **Build it** because no local agent owns
|
|
58
|
+
their files.
|
|
59
|
+
|
|
60
|
+
Browser screenshots do not establish PDF/PPTX editability, font embedding or
|
|
61
|
+
cross-application fidelity. Inspect every requested export separately.
|
package/index.html
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<meta name="theme-color" content="#ffffff" />
|
|
7
|
+
<meta
|
|
8
|
+
name="description"
|
|
9
|
+
content="An editable canvas for agent-made visuals. Create a single explanation or a whole presentation, then revise it together."
|
|
10
|
+
/>
|
|
11
|
+
<title>Konpeki</title>
|
|
12
|
+
</head>
|
|
13
|
+
<body>
|
|
14
|
+
<div id="root"></div>
|
|
15
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
16
|
+
</body>
|
|
17
|
+
</html>
|
package/lib/assets.d.ts
ADDED
package/lib/charts.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { typography, type Palette } from './taste.ts';
|
|
2
|
+
|
|
3
|
+
// Shared presentation defaults for Nivo SVG components, not a chart wrapper.
|
|
4
|
+
// Decks still own data, dimensions, scales, labels and semantic color assignments.
|
|
5
|
+
export function chartDefaults(p: Palette) {
|
|
6
|
+
return {
|
|
7
|
+
animate: false,
|
|
8
|
+
isInteractive: false,
|
|
9
|
+
renderWrapper: false,
|
|
10
|
+
colors: [p.accent, p.emphasis],
|
|
11
|
+
theme: {
|
|
12
|
+
text: { fontFamily: typography.family, fontSize: typography.caption, fill: p.fg },
|
|
13
|
+
axis: { ticks: { text: { fill: p.fg, fontSize: typography.caption } }, domain: { line: { stroke: p.line } } },
|
|
14
|
+
grid: { line: { stroke: p.line, strokeWidth: 1 } },
|
|
15
|
+
labels: { text: { fontSize: typography.caption, fill: p.fg } },
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
}
|
package/lib/contrast.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// WCAG relative luminance for opaque, six-digit sRGB hex colors only.
|
|
2
|
+
// Callers must establish the actual rendered pair; this does not inspect a DOM.
|
|
3
|
+
export function contrastRatio(foreground: string, background: string): number {
|
|
4
|
+
const luminance = (color: string) => {
|
|
5
|
+
if (!/^#[0-9a-f]{6}$/i.test(color)) {
|
|
6
|
+
throw new Error('Contrast requires opaque six-digit sRGB hex colors (#RRGGBB).');
|
|
7
|
+
}
|
|
8
|
+
const channels = [1, 3, 5].map(offset => {
|
|
9
|
+
const value = Number.parseInt(color.slice(offset, offset + 2), 16) / 255;
|
|
10
|
+
return value <= 0.04045 ? value / 12.92 : ((value + 0.055) / 1.055) ** 2.4;
|
|
11
|
+
});
|
|
12
|
+
return 0.2126 * channels[0] + 0.7152 * channels[1] + 0.0722 * channels[2];
|
|
13
|
+
};
|
|
14
|
+
const fg = luminance(foreground), bg = luminance(background);
|
|
15
|
+
return (Math.max(fg, bg) + 0.05) / (Math.min(fg, bg) + 0.05);
|
|
16
|
+
}
|
package/lib/layouts.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export type Region = { x: number; y: number; width: number; height: number };
|
|
2
|
+
export type RelationshipSlot = { x: number; y: number; axis: 'horizontal' | 'vertical' };
|
|
3
|
+
export const layoutKinds = ['two-columns', 'main-aside', 'three-columns', 'four-grid', 'one-left', 'one-right', 'one-top', 'one-bottom'] as const;
|
|
4
|
+
export type LayoutKind = typeof layoutKinds[number];
|
|
5
|
+
export const contentRegion: Region = { x: 112, y: 404, width: 1696, height: 520 };
|
|
6
|
+
|
|
7
|
+
function split(area: Region, axis: 'horizontal' | 'vertical', weights: number[], gap: number): Region[] {
|
|
8
|
+
const length = axis === 'horizontal' ? area.width : area.height;
|
|
9
|
+
const available = length - gap * (weights.length - 1);
|
|
10
|
+
const total = weights.reduce((a, b) => a + b, 0);
|
|
11
|
+
let offset = 0;
|
|
12
|
+
return weights.map(weight => {
|
|
13
|
+
const size = available * weight / total;
|
|
14
|
+
const region = axis === 'horizontal'
|
|
15
|
+
? { ...area, x: area.x + offset, width: size }
|
|
16
|
+
: { ...area, y: area.y + offset, height: size };
|
|
17
|
+
offset += size + gap;
|
|
18
|
+
return region;
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function between(a: Region, b: Region, axis: RelationshipSlot['axis']): RelationshipSlot {
|
|
23
|
+
return axis === 'horizontal'
|
|
24
|
+
? { x: (a.x + a.width + b.x) / 2, y: a.y + a.height / 2, axis }
|
|
25
|
+
: { x: a.x + a.width / 2, y: (a.y + a.height + b.y) / 2, axis };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Regions and relationship gutters, not an automatic layout/diagram solver.
|
|
29
|
+
// A slot is available space; the author decides whether an arrow belongs there.
|
|
30
|
+
export function arrange(kind: LayoutKind, area: Region = contentRegion, gap = 80): { panels: Region[]; slots: RelationshipSlot[] } {
|
|
31
|
+
if (kind === 'two-columns' || kind === 'main-aside' || kind === 'three-columns') {
|
|
32
|
+
const weights = kind === 'main-aside' ? [2, 1] : kind === 'three-columns' ? [1, 1, 1] : [1, 1];
|
|
33
|
+
const panels = split(area, 'horizontal', weights, gap);
|
|
34
|
+
return { panels, slots: panels.slice(1).map((panel, i) => between(panels[i], panel, 'horizontal')) };
|
|
35
|
+
}
|
|
36
|
+
if (kind === 'four-grid') {
|
|
37
|
+
const rows = split(area, 'vertical', [1, 1], gap);
|
|
38
|
+
const panels = rows.flatMap(row => split(row, 'horizontal', [1, 1], gap));
|
|
39
|
+
return { panels, slots: [between(panels[0], panels[1], 'horizontal'), between(panels[2], panels[3], 'horizontal'), between(panels[0], panels[2], 'vertical'), between(panels[1], panels[3], 'vertical')] };
|
|
40
|
+
}
|
|
41
|
+
const axis = kind === 'one-top' || kind === 'one-bottom' ? 'vertical' : 'horizontal';
|
|
42
|
+
const halves = split(area, axis, [1, 1], gap);
|
|
43
|
+
const reversed = kind === 'one-right' || kind === 'one-bottom';
|
|
44
|
+
const single = halves[reversed ? 1 : 0], group = halves[reversed ? 0 : 1];
|
|
45
|
+
// Single panel is always index 0; the three siblings follow in reading order.
|
|
46
|
+
return {
|
|
47
|
+
panels: [single, ...split(group, axis === 'horizontal' ? 'vertical' : 'horizontal', [1, 1, 1], 32)],
|
|
48
|
+
slots: [between(halves[0], halves[1], axis)],
|
|
49
|
+
};
|
|
50
|
+
}
|