@litfamily/litopencode 1.0.31 → 1.0.32
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/CHANGELOG.md +24 -0
- package/README-Ko-KR.md +6 -6
- package/README.md +6 -6
- package/dist/activation-probe.js +1 -0
- package/dist/activation-prompt-utils.d.ts +1 -1
- package/dist/activation-reentry.d.ts +20 -0
- package/dist/activation-reentry.js +110 -1
- package/dist/activation-routing.d.ts +2 -1
- package/dist/activation-routing.js +100 -11
- package/dist/activation-workflow-prompts.d.ts +4 -0
- package/dist/activation-workflow-prompts.js +30 -0
- package/dist/activation.d.ts +1 -1
- package/dist/activation.js +44 -5
- package/dist/adhd-next.d.ts +51 -0
- package/dist/adhd-next.js +150 -0
- package/dist/cli/managed-skill-assets.d.ts +1 -1
- package/dist/cli/managed-skill-assets.js +7 -1
- package/dist/cli/native-skill-integrity.js +1 -1
- package/dist/cli.js +7 -1
- package/dist/commands.d.ts +28 -1
- package/dist/commands.js +48 -1
- package/dist/features.d.ts +80 -1
- package/dist/features.js +105 -1
- package/dist/ledger.js +12 -1
- package/dist/secret-shapes.js +5 -5
- package/dist/skills.d.ts +22 -1
- package/dist/skills.js +36 -0
- package/dist/start-work-typed.d.ts +34 -0
- package/dist/start-work-typed.js +156 -0
- package/dist/state.d.ts +2 -0
- package/dist/state.js +2 -0
- package/dist/tools.js +22 -2
- package/dist/tui/mission-band.d.ts +20 -1
- package/dist/tui/mission-band.js +73 -16
- package/dist/tui/mission-looks.d.ts +38 -0
- package/dist/tui/mission-looks.js +73 -0
- package/dist/tui/mission-model.d.ts +2 -0
- package/dist/tui/mission-model.js +3 -1
- package/dist/tui/mission-rainbow.d.ts +33 -0
- package/dist/tui/mission-rainbow.js +90 -0
- package/dist/tui/mission-source.d.ts +48 -0
- package/dist/tui/mission-source.js +184 -2
- package/dist/tui/mission-text.d.ts +2 -0
- package/dist/tui/mission-text.js +9 -1
- package/dist/tui/mission-threads.d.ts +50 -0
- package/dist/tui/mission-threads.js +119 -0
- package/dist/tui.js +84 -6
- package/dist/uiux-visual-catalog.js +8 -1
- package/dist/v2/session-hooks.js +38 -5
- package/dist/workflow-stack.d.ts +53 -0
- package/dist/workflow-stack.js +196 -0
- package/docs/assets/readme/badge-version.svg +1 -1
- package/docs/assets/skills/lit-schematic.webp +0 -0
- package/docs/reference-Ko-KR.md +30 -2
- package/docs/reference.md +34 -2
- package/package.json +1 -1
- package/skills/frontend-ui-ux/SKILL.md +3 -2
- package/skills/frontend-ui-ux/kit/components.css +414 -0
- package/skills/frontend-ui-ux/kit/fonts.json +22 -0
- package/skills/frontend-ui-ux/kit/layouts/landing.html +164 -0
- package/skills/frontend-ui-ux/kit/layouts/settings.html +114 -0
- package/skills/frontend-ui-ux/kit/layouts/workspace.html +115 -0
- package/skills/frontend-ui-ux/kit/styles/computational-brutalism.json +227 -0
- package/skills/frontend-ui-ux/kit/styles/field-notes.json +205 -0
- package/skills/frontend-ui-ux/kit/styles/graphite.json +200 -0
- package/skills/frontend-ui-ux/kit/styles/meadow.json +199 -0
- package/skills/frontend-ui-ux/kit/styles/neo-brutalism.json +222 -0
- package/skills/frontend-ui-ux/kit/ui.js +226 -0
- package/skills/frontend-ui-ux/references/brand-and-imagery.md +2 -2
- package/skills/frontend-ui-ux/references/complete-contract.md +2 -1
- package/skills/frontend-ui-ux/references/craft-floor.md +6 -2
- package/skills/frontend-ui-ux/references/default-editorial-pixel.json +3 -0
- package/skills/frontend-ui-ux/references/house-styles.md +236 -0
- package/skills/frontend-ui-ux/references/motion-guide.md +2 -2
- package/skills/frontend-ui-ux/references/production.md +3 -1
- package/skills/frontend-ui-ux/references/slop-register.md +4 -4
- package/skills/frontend-ui-ux/scripts/design-lock.mjs +400 -0
- package/skills/frontend-ui-ux/scripts/pixel-art.mjs +60 -0
- package/skills/frontend-ui-ux/scripts/probe-lock.mjs +235 -0
- package/skills/frontend-ui-ux/scripts/probe-page.mjs +34 -12
- package/skills/frontend-ui-ux/scripts/probe-static.mjs +16 -3
- package/skills/frontend-ui-ux/scripts/probe-thresholds.json +8 -2
- package/skills/frontend-ui-ux/scripts/probe.mjs +35 -7
- package/skills/lit-adhd/SKILL.md +208 -0
- package/skills/lit-adhd/references/brief-format.md +43 -0
- package/skills/lit-adhd/references/card-examples.md +82 -0
- package/skills/lit-adhd/references/status-taxonomy.md +29 -0
- package/skills/lit-adhd/scripts/rewind.mjs +835 -0
- package/skills/lit-diagram-drawer/SKILL.md +4 -3
- package/skills/lit-diagram-drawer/references/style-guide.md +20 -11
- package/skills/lit-diagram-drawer/references/type-architecture.md +3 -3
- package/skills/lit-diagram-drawer/references/type-dependency.md +1 -1
- package/skills/lit-diagram-drawer/references/type-tree.md +3 -3
- package/skills/lit-diagram-drawer/references/type-wardley.md +1 -1
- package/skills/lit-diagram-drawer/references/verifier-guide.md +1 -0
- package/skills/lit-diagram-drawer/scripts/craft-thresholds.json +1 -2
- package/skills/lit-diagram-drawer/scripts/visual-quality.mjs +1 -2
- package/skills/lit-docx/SKILL.md +2 -1
- package/skills/lit-handoff/SKILL.md +2 -0
- package/skills/lit-hijack/SKILL.md +422 -0
- package/skills/lit-hijack/references/capture-and-provenance.md +87 -0
- package/skills/lit-hijack/references/clean-room-build.md +111 -0
- package/skills/lit-hijack/references/distil-and-licence.md +100 -0
- package/skills/lit-hijack/references/gap-and-port-design.md +126 -0
- package/skills/lit-hijack/references/parity-and-report.md +110 -0
- package/skills/lit-hijack/scripts/hijack.mjs +993 -0
- package/skills/lit-plan/SKILL.md +2 -0
- package/skills/lit-pptx/SKILL.md +27 -11
- package/skills/lit-pptx/fonts/jetbrains-mono/JetBrainsMono-Bold.ttf +0 -0
- package/skills/lit-pptx/fonts/jetbrains-mono/JetBrainsMono-Regular.ttf +0 -0
- package/skills/lit-pptx/fonts/jetbrains-mono/OFL.txt +93 -0
- package/skills/lit-pptx/fonts/jetbrains-mono/SOURCE.md +17 -0
- package/skills/lit-pptx/references/density-and-fill.md +9 -3
- package/skills/lit-pptx/references/direction-step.md +21 -6
- package/skills/lit-pptx/references/examples/04-lecture-chalk-ko.md +3 -6
- package/skills/lit-pptx/references/examples/05-research-talk-paper-en.md +1 -5
- package/skills/lit-pptx/references/examples/08-reliability-keynote-night-en.md +0 -4
- package/skills/lit-pptx/references/examples/09-status-update-ledger-en.md +2 -2
- package/skills/lit-pptx/references/examples/11-forecast-review-night-ko.md +4 -7
- package/skills/lit-pptx/references/examples/13-engineering-review-computational-brutalism-ko.md +173 -0
- package/skills/lit-pptx/references/examples/14-launch-pitch-neo-brutalism-ko.md +154 -0
- package/skills/lit-pptx/references/examples/15-design-lecture-bauhaus-ko.md +139 -0
- package/skills/lit-pptx/references/examples/16-community-programme-riso-ko.md +158 -0
- package/skills/lit-pptx/references/examples/17-public-data-briefing-newsroom-ko.md +179 -0
- package/skills/lit-pptx/references/layout-families.md +65 -47
- package/skills/lit-pptx/references/title-treatments.md +83 -134
- package/skills/lit-pptx/references/tonalities/atlas.md +3 -3
- package/skills/lit-pptx/references/tonalities/bauhaus.md +140 -0
- package/skills/lit-pptx/references/tonalities/chalk.md +7 -6
- package/skills/lit-pptx/references/tonalities/computational-brutalism.md +150 -0
- package/skills/lit-pptx/references/tonalities/gazette.md +1 -1
- package/skills/lit-pptx/references/tonalities/ledger.md +1 -1
- package/skills/lit-pptx/references/tonalities/neo-brutalism.md +161 -0
- package/skills/lit-pptx/references/tonalities/newsroom.md +144 -0
- package/skills/lit-pptx/references/tonalities/night.md +1 -1
- package/skills/lit-pptx/references/tonalities/paper.md +2 -2
- package/skills/lit-pptx/references/tonalities/riso.md +137 -0
- package/skills/lit-pptx/references/tonalities/signal.md +3 -3
- package/skills/lit-pptx/references/tonalities/studio.md +7 -6
- package/skills/lit-pptx/run.mjs +2 -1
- package/skills/lit-pptx/scripts/compile-deck.js +1 -1
- package/skills/lit-pptx/scripts/craft-thresholds.json +4 -8
- package/skills/lit-pptx/scripts/craft_extras.py +56 -3
- package/skills/lit-pptx/scripts/deck_output.py +75 -90
- package/skills/lit-pptx/scripts/embed_fonts.py +13 -1
- package/skills/lit-pptx/scripts/layout_inventory.py +12 -5
- package/skills/lit-pptx/scripts/lib/grid-resolver.js +101 -110
- package/skills/lit-pptx/scripts/lib/layout-resolver.js +9 -15
- package/skills/lit-pptx/scripts/lib/render-pack.js +373 -566
- package/skills/lit-pptx/scripts/lib/slide-grid.js +104 -0
- package/skills/lit-pptx/scripts/lib/template-registry.js +57 -6
- package/skills/lit-pptx/scripts/qa_deck.py +10 -11
- package/skills/lit-pptx/scripts/render_pages.py +118 -0
- package/skills/lit-pptx/templates/tonalities/atlas/pack.yaml +1 -1
- package/skills/lit-pptx/templates/tonalities/bauhaus/pack.yaml +98 -0
- package/skills/lit-pptx/templates/tonalities/chalk/pack.yaml +1 -1
- package/skills/lit-pptx/templates/tonalities/computational-brutalism/pack.yaml +99 -0
- package/skills/lit-pptx/templates/tonalities/gazette/pack.yaml +1 -1
- package/skills/lit-pptx/templates/tonalities/ledger/pack.yaml +1 -1
- package/skills/lit-pptx/templates/tonalities/neo-brutalism/pack.yaml +107 -0
- package/skills/lit-pptx/templates/tonalities/newsroom/pack.yaml +99 -0
- package/skills/lit-pptx/templates/tonalities/night/pack.yaml +1 -1
- package/skills/lit-pptx/templates/tonalities/paper/pack.yaml +1 -1
- package/skills/lit-pptx/templates/tonalities/riso/pack.yaml +99 -0
- package/skills/lit-pptx/templates/tonalities/signal/pack.yaml +2 -2
- package/skills/lit-pptx/templates/tonalities/studio/pack.yaml +1 -1
- package/skills/lit-recap/SKILL.md +4 -0
- package/skills/lit-schematic/SKILL.md +118 -0
- package/skills/lit-schematic/examples/iso-heat-exchanger/build.mjs +38 -0
- package/skills/lit-schematic/examples/iso-heat-exchanger/scene.mjs +133 -0
- package/skills/lit-schematic/examples/journal-adsorption-rig/build.mjs +87 -0
- package/skills/lit-schematic/examples/pid-dosing-skid/build.mjs +85 -0
- package/skills/lit-schematic/references/cutaway-outputs.md +70 -0
- package/skills/lit-schematic/references/isometric-craft.md +101 -0
- package/skills/lit-schematic/references/journal-figures.md +72 -0
- package/skills/lit-schematic/references/kit-api.md +134 -0
- package/skills/lit-schematic/references/pfd-and-layout.md +53 -0
- package/skills/lit-schematic/references/pid-drafting.md +103 -0
- package/skills/lit-schematic/references/pid-symbols.md +163 -0
- package/skills/lit-schematic/references/verification.md +100 -0
- package/skills/lit-schematic/scripts/doctor.mjs +57 -0
- package/skills/lit-schematic/scripts/lib/figure.mjs +81 -0
- package/skills/lit-schematic/scripts/lib/fonts.mjs +25 -0
- package/skills/lit-schematic/scripts/lib/geom.mjs +113 -0
- package/skills/lit-schematic/scripts/lib/interactive.mjs +292 -0
- package/skills/lit-schematic/scripts/lib/isa.mjs +115 -0
- package/skills/lit-schematic/scripts/lib/iso.mjs +719 -0
- package/skills/lit-schematic/scripts/lib/legend-sheet.mjs +162 -0
- package/skills/lit-schematic/scripts/lib/pid.mjs +937 -0
- package/skills/lit-schematic/scripts/lib/png.mjs +132 -0
- package/skills/lit-schematic/scripts/lib/qa-core.mjs +658 -0
- package/skills/lit-schematic/scripts/lib/route.mjs +218 -0
- package/skills/lit-schematic/scripts/lib/sheet.mjs +890 -0
- package/skills/lit-schematic/scripts/lib/svg.mjs +82 -0
- package/skills/lit-schematic/scripts/lib/theme.mjs +115 -0
- package/skills/lit-schematic/scripts/motion.mjs +129 -0
- package/skills/lit-schematic/scripts/qa.mjs +92 -0
- package/skills/lit-schematic/scripts/render.mjs +233 -0
- package/skills/lit-schematic/scripts/scaffold.mjs +60 -0
- package/skills/lit-scientific-visualization/SKILL.md +27 -4
- package/skills/lit-typographic-motion/SKILL.md +19 -17
- package/skills/lit-typographic-motion/THIRD_PARTY_NOTICES +9 -0
- package/skills/lit-typographic-motion/engine/accents.mjs +6 -0
- package/skills/lit-typographic-motion/engine/assets.mjs +282 -0
- package/skills/lit-typographic-motion/engine/blender/runner.py +228 -0
- package/skills/lit-typographic-motion/engine/blender.mjs +126 -0
- package/skills/lit-typographic-motion/engine/board.mjs +138 -0
- package/skills/lit-typographic-motion/engine/cover/assets.mjs +11 -8
- package/skills/lit-typographic-motion/engine/cover/capture.mjs +6 -6
- package/skills/lit-typographic-motion/engine/cover/render.mjs +20 -7
- package/skills/lit-typographic-motion/engine/cover/treatment.mjs +30 -3
- package/skills/lit-typographic-motion/engine/fill.mjs +54 -0
- package/skills/lit-typographic-motion/engine/gallery.mjs +118 -0
- package/skills/lit-typographic-motion/engine/house.mjs +42 -0
- package/skills/lit-typographic-motion/engine/look.mjs +65 -8
- package/skills/lit-typographic-motion/engine/loudness.mjs +101 -0
- package/skills/lit-typographic-motion/engine/scaffold.mjs +219 -0
- package/skills/lit-typographic-motion/engine/score.mjs +594 -0
- package/skills/lit-typographic-motion/engine/sound.mjs +9 -57
- package/skills/lit-typographic-motion/engine/stage/capture.mjs +23 -9
- package/skills/lit-typographic-motion/engine/stage/clock.js +8 -2
- package/skills/lit-typographic-motion/engine/stage/cover-init.js +12 -1
- package/skills/lit-typographic-motion/engine/stage/frame-worker.mjs +15 -7
- package/skills/lit-typographic-motion/engine/stage/gate.mjs +48 -4
- package/skills/lit-typographic-motion/engine/stage/qa-page.js +16 -5
- package/skills/lit-typographic-motion/engine/stage/qa.mjs +148 -7
- package/skills/lit-typographic-motion/engine/stage/render.mjs +69 -7
- package/skills/lit-typographic-motion/engine/stage/scan.mjs +20 -1
- package/skills/lit-typographic-motion/engine/stage/stage-kit.js +85 -4
- package/skills/lit-typographic-motion/engine/stills.mjs +1 -1
- package/skills/lit-typographic-motion/engine/styles.mjs +221 -0
- package/skills/lit-typographic-motion/engine/text.mjs +1 -1
- package/skills/lit-typographic-motion/engine/treatment.mjs +190 -6
- package/skills/lit-typographic-motion/engine/vendor/three/LICENSE +21 -0
- package/skills/lit-typographic-motion/engine/vendor/three/addons/environments/RoomEnvironment.js +144 -0
- package/skills/lit-typographic-motion/engine/vendor/three/addons/geometries/RoundedBoxGeometry.js +155 -0
- package/skills/lit-typographic-motion/engine/vendor/three/three.module.js +54571 -0
- package/skills/lit-typographic-motion/gate.mjs +18 -2
- package/skills/lit-typographic-motion/probe.mjs +13 -1
- package/skills/lit-typographic-motion/recipes/hero-3d/expected.json +64 -0
- package/skills/lit-typographic-motion/recipes/hero-3d/index.html +132 -0
- package/skills/lit-typographic-motion/recipes/orbit-loop/expected.json +2 -0
- package/skills/lit-typographic-motion/recipes/painted-light/expected.json +2 -0
- package/skills/lit-typographic-motion/recipes/weight-tide/expected.json +2 -0
- package/skills/lit-typographic-motion/references/cover.md +56 -13
- package/skills/lit-typographic-motion/references/craft-loop.md +20 -7
- package/skills/lit-typographic-motion/references/depth.md +112 -0
- package/skills/lit-typographic-motion/references/runtime.md +21 -6
- package/skills/lit-typographic-motion/references/sound.md +76 -0
- package/skills/lit-typographic-motion/references/stage.md +50 -7
- package/skills/lit-typographic-motion/references/studio.md +162 -0
- package/skills/lit-typographic-motion/references/style-bibles.md +18 -0
- package/skills/lit-typographic-motion/references/treatment.md +108 -9
- package/skills/lit-typographic-motion/render.mjs +60 -3
- package/skills/lit-typographic-motion/styles/paper.json +185 -0
- package/skills/lit-typographic-motion/styles/swiss-signal.json +188 -0
- package/skills/lit-typographic-motion/styles/terminalcore.json +182 -0
- package/skills/lit-typographic-motion/styles/tidal.json +187 -0
- package/skills/litresearch/SKILL.md +2 -0
- package/skills/managed-skill-manifest.json +517 -88
- package/skills/readme-studio/SKILL.md +1 -1
- package/skills/review-work/SKILL.md +2 -0
- package/skills/start-work/SKILL.md +8 -0
- package/skills/workflow-loop/SKILL.md +4 -0
- package/tools/check-pack-payload.mjs +4 -2
- package/tools/payload-substance-parity.json +4 -3
- package/tools/qa-cover-recipes.mjs +4 -3
|
@@ -10,14 +10,9 @@
|
|
|
10
10
|
* out in points on the 960 x 540 (16:9) or 720 x 540 (4:3) canvas; the renderer converts to inches.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
const
|
|
13
|
+
const SG = require("./slide-grid");
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
// exactly to the canvas width over 12 columns and 11 gutters.
|
|
17
|
-
const GRIDS = {
|
|
18
|
-
"16:9": { airy: { margin: 60, col: 48, gutter: 24 }, standard: { margin: 48, col: 50, gutter: 24 }, dense: { margin: 36, col: 52, gutter: 24 }, compact: { margin: 24, col: 54, gutter: 24 } },
|
|
19
|
-
"4:3": { airy: { margin: 54, col: 40, gutter: 12 }, standard: { margin: 42, col: 42, gutter: 12 }, dense: { margin: 30, col: 44, gutter: 12 }, compact: { margin: 24, col: 45, gutter: 12 } },
|
|
20
|
-
};
|
|
15
|
+
const { CANVAS } = SG;
|
|
21
16
|
|
|
22
17
|
const RAMPS = {
|
|
23
18
|
presented: { source: 12, label: 14, body: 18, lead: 24, title: 32, display: 44, cover: 56, hero: 72 },
|
|
@@ -29,19 +24,22 @@ const RAMPS = {
|
|
|
29
24
|
const RAMP_ORDER = ["source", "label", "body", "lead", "title", "display", "cover", "hero"];
|
|
30
25
|
const SCALE = [6, 12, 18, 24, 36, 48, 72];
|
|
31
26
|
|
|
32
|
-
//
|
|
33
|
-
const ZONE =
|
|
27
|
+
// The content zones of the shared slide grid (slide-grid.js), the same on both canvases.
|
|
28
|
+
const ZONE = (() => {
|
|
29
|
+
const z = SG.ZONES.content;
|
|
30
|
+
return { top: z.title.y, body: z.body.y, floor: z.body.y + z.body.h, footer: z.footer.y, footerH: z.footer.h };
|
|
31
|
+
})();
|
|
34
32
|
|
|
35
|
-
// What the density dial sets:
|
|
36
|
-
//
|
|
37
|
-
// density 10 is the compact step:
|
|
33
|
+
// What the density dial sets: ramp, gaps, padding, table rows and the empty band a content slide may
|
|
34
|
+
// leave under its last line; never where the zones are. From density 5 a deck reads on the reading ramp
|
|
35
|
+
// (body 14 pt); density 10 is the compact step: body 13 pt and the tightest gaps.
|
|
38
36
|
const DENSITY_BANDS = [
|
|
39
|
-
{ upTo: 2,
|
|
40
|
-
{ upTo: 4,
|
|
41
|
-
{ upTo: 6,
|
|
42
|
-
{ upTo: 8,
|
|
43
|
-
{ upTo: 9,
|
|
44
|
-
{ upTo: 10,
|
|
37
|
+
{ upTo: 2, ramp: "presented", item: 18, group: 36, block: 48, pad: 24, rowMin: 36, maxLines: 6, cap: 0.28, stepUp: true },
|
|
38
|
+
{ upTo: 4, ramp: "presented", item: 12, group: 24, block: 36, pad: 24, rowMin: 32, maxLines: 8, cap: 0.24, stepUp: true },
|
|
39
|
+
{ upTo: 6, ramp: "reading", item: 6, group: 18, block: 24, pad: 18, rowMin: 24, maxLines: 12, cap: 0.18, stepUp: true },
|
|
40
|
+
{ upTo: 8, ramp: "reading", item: 6, group: 12, block: 24, pad: 12, rowMin: 22, maxLines: 16, cap: 0.14, stepUp: true },
|
|
41
|
+
{ upTo: 9, ramp: "reading", item: 6, group: 12, block: 24, pad: 12, rowMin: 20, maxLines: 18, cap: 0.12, stepUp: false },
|
|
42
|
+
{ upTo: 10, ramp: "compact", item: 6, group: 12, block: 18, pad: 12, rowMin: 18, maxLines: 22, cap: 0.12, stepUp: false, tight: true },
|
|
45
43
|
];
|
|
46
44
|
|
|
47
45
|
const TREATMENTS = ["top-rule", "top-plain-large", "side-rail", "band", "statement", "overlay", "kicker-numeral", "bottom-anchor"];
|
|
@@ -95,10 +93,15 @@ function clampDial(value, fallback) {
|
|
|
95
93
|
return Number.isFinite(n) ? Math.max(1, Math.min(10, n)) : fallback;
|
|
96
94
|
}
|
|
97
95
|
|
|
96
|
+
/**
|
|
97
|
+
* The density band's tokens. A bold pack (`ramp: presented`, allowed only with `register: bold`)
|
|
98
|
+
* sets its type on the presented ramp at any density, so its titles and figures fill the same zones
|
|
99
|
+
* at presentation size; every other pack takes the band's ramp.
|
|
100
|
+
*/
|
|
98
101
|
function densityTokens(density, packRamp) {
|
|
99
102
|
const d = clampDial(density, 5);
|
|
100
103
|
const band = DENSITY_BANDS.find((b) => d <= b.upTo);
|
|
101
|
-
const ramp =
|
|
104
|
+
const ramp = packRamp === "presented" ? "presented" : band.ramp;
|
|
102
105
|
return { density: d, ...band, ramp, sizes: RAMPS[ramp] };
|
|
103
106
|
}
|
|
104
107
|
|
|
@@ -109,12 +112,13 @@ function varianceMax(variance, treatmentCount) {
|
|
|
109
112
|
return Math.min(max, treatmentCount);
|
|
110
113
|
}
|
|
111
114
|
|
|
112
|
-
|
|
115
|
+
/** The shared slide grid's columns on a canvas (the same for every pack and density). */
|
|
116
|
+
function makeGrid(canvas) {
|
|
113
117
|
const { W, H } = CANVAS[canvas];
|
|
114
|
-
const g =
|
|
118
|
+
const g = SG.COLUMNS[canvas];
|
|
115
119
|
const pitch = g.col + g.gutter;
|
|
116
120
|
return {
|
|
117
|
-
canvas, name, W, H, ...g, pitch,
|
|
121
|
+
canvas, name: "compact", W, H, ...g, pitch,
|
|
118
122
|
/** Columns a…b (1-based, inclusive) as x and width in points. */
|
|
119
123
|
span(a, b) { return { x: g.margin + pitch * (a - 1), w: pitch * (b - a + 1) - g.gutter }; },
|
|
120
124
|
colX(a) { return g.margin + pitch * (a - 1); },
|
|
@@ -279,7 +283,16 @@ function leading(text) {
|
|
|
279
283
|
* How much wider than the estimate a face sets: heavier weights of the bundled faces run wider,
|
|
280
284
|
* so a frame measured at the regular width would lose its last line.
|
|
281
285
|
*/
|
|
282
|
-
function faceWidth(face) {
|
|
286
|
+
function faceWidth(face, text) {
|
|
287
|
+
// A monospaced Latin face sets every Latin character and space at 0.6 em, and its Hangul in the
|
|
288
|
+
// East Asian face; the factor is that advance over the estimate, or the Latin worst case unread.
|
|
289
|
+
if (face && face.ea) {
|
|
290
|
+
const est = textEms(text);
|
|
291
|
+
if (text == null || !est) return 1.26;
|
|
292
|
+
let mono = 0;
|
|
293
|
+
for (const ch of String(text)) mono += /[ᄀ-ᇿ-가-힣一-鿿]/u.test(ch) ? 0.94 * (face.bold ? 1.08 : 1.0) : 0.6;
|
|
294
|
+
return Math.max(1, mono / est);
|
|
295
|
+
}
|
|
283
296
|
const font = (face && face.font) || "";
|
|
284
297
|
return /9 Black/u.test(font) ? 1.14 : /7 Bold/u.test(font) ? 1.08 : /5 Medium/u.test(font) ? 1.05 : face && face.bold ? 1.04 : 1.0;
|
|
285
298
|
}
|
|
@@ -375,86 +388,90 @@ function pickTreatment({ pack, family, role, override, slideNumber, used, max, a
|
|
|
375
388
|
/**
|
|
376
389
|
* Title frame, companion decoration and body zone of one treatment, in points.
|
|
377
390
|
*
|
|
391
|
+
* Every treatment sets its title in the shared title zone (slide-grid.js) and leaves the body zone
|
|
392
|
+
* as it is: a treatment chooses the title's face, size and colour and what is drawn with it, never
|
|
393
|
+
* where the title or the body stands. A statement sets its sentence in the display title zone.
|
|
394
|
+
*
|
|
378
395
|
* ctx: { grid, sizes, title, hero, decoration (Set), numeral, rail ("surface" or "field") }
|
|
379
|
-
* Returns { title, decor[], numeral?, body: {a, b, y, bottom},
|
|
380
|
-
* a…b are on the deck grid. `fits` is false when the title does not fit
|
|
396
|
+
* Returns { title, decor[], numeral?, body: {a, b, y, bottom}, support?, lines } where body
|
|
397
|
+
* columns a…b are on the deck grid. `fits` is false when the title does not fit its zone.
|
|
381
398
|
*/
|
|
382
399
|
function treatmentGeometry(id, ctx) {
|
|
383
400
|
const { grid, sizes } = ctx;
|
|
384
401
|
// Lines of the title at a size, in the face that sets it (ctx.wide: face role → width factor).
|
|
385
|
-
const fit = (t, w, size, face = "title") =>
|
|
402
|
+
const fit = (t, w, size, face = "title") => {
|
|
403
|
+
const k = ctx.wide && ctx.wide[face];
|
|
404
|
+
return lineCount(t, w / ((typeof k === "function" ? k(t) : k) || 1), size);
|
|
405
|
+
};
|
|
386
406
|
const text = ctx.title || "";
|
|
387
407
|
const decor = [];
|
|
388
408
|
const full = grid.span(1, 12);
|
|
389
409
|
const out = { id, decor, fits: true };
|
|
390
|
-
const
|
|
391
|
-
|
|
392
|
-
|
|
410
|
+
const T = SG.zone(grid.canvas, "content", "title");
|
|
411
|
+
const B = SG.zone(grid.canvas, "content", "body");
|
|
412
|
+
const body = { a: B.a, b: B.b, y: B.y, bottom: B.y + B.h };
|
|
413
|
+
// The title frame is the zone itself. Two lines at the title step take 1.15 leading, or 1.1 when
|
|
414
|
+
// that is what keeps them inside the zone (the presented title step); display type sets solid (1.0)
|
|
415
|
+
// when that is what keeps two lines of it in the zone.
|
|
416
|
+
const frame = (size, face, colour) => {
|
|
417
|
+
const lines = fit(text, T.w, size, face);
|
|
418
|
+
const lineSpacing = [1.15, 1.1, ...(face === "display" ? [1.0] : [])].find((k) => lines * size * k <= T.h + 0.5) || 1.1;
|
|
419
|
+
return { x: T.x, y: T.y, w: T.w, h: T.h, size, face, colour, lines, lineSpacing, fits: lines * size * lineSpacing <= T.h + 0.5 };
|
|
393
420
|
};
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
if (id === "top-rule" || id === "band") {
|
|
398
|
-
const
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
out.
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
decor.push({ x: 0, y: 0, w: grid.W, h: 108, role: "field", kind: "band" });
|
|
406
|
-
out.body = { a: 1, b: 12, y: ctx.tight ? 120 : 132, bottom: ZONE.floor };
|
|
407
|
-
} else {
|
|
408
|
-
const ruleY = 36 + h + 6;
|
|
409
|
-
if (ctx.decoration.has("accent-rule")) decor.push({ x: out.title.x, y: ruleY, w: grid.col, h: 4, role: "accent", kind: "rule" });
|
|
421
|
+
// Where the title's last line ends inside the frame (a rule under it follows the text, not the zone).
|
|
422
|
+
const textBottom = (f) => T.y + Math.ceil(Math.max(1, f.lines) * f.size * f.lineSpacing) + 2;
|
|
423
|
+
|
|
424
|
+
if (id === "top-rule" || id === "band" || id === "bottom-anchor" || id === "side-rail" || id === "kicker-numeral") {
|
|
425
|
+
const f = frame(sizes.title, "title", id === "band" ? "on-field" : "ink");
|
|
426
|
+
out.fits = f.fits && f.lines <= 2 && (id !== "kicker-numeral" || ctx.numeral != null);
|
|
427
|
+
out.title = f;
|
|
428
|
+
out.body = body;
|
|
429
|
+
if (id === "top-rule") {
|
|
430
|
+
const ruleY = textBottom(f) + 4;
|
|
431
|
+
if (ctx.decoration.has("accent-rule")) decor.push({ x: T.x, y: ruleY, w: grid.col, h: 4, role: "accent", kind: "rule" });
|
|
410
432
|
else decor.push({ x: full.x, y: ruleY, w: full.w, h: 0.75, role: "line", kind: "rule" });
|
|
411
|
-
|
|
433
|
+
} else if (id === "band") {
|
|
434
|
+
// The field runs from the page's top edge to the foot of the title zone.
|
|
435
|
+
decor.push({ x: 0, y: 0, w: grid.W, h: T.y + T.h, role: "field", kind: "band" });
|
|
436
|
+
} else if (id === "bottom-anchor") {
|
|
437
|
+
// The title zone closes on a heavy rule in the ink across the page's columns.
|
|
438
|
+
decor.push({ x: full.x, y: T.y + T.h + 2, w: full.w, h: 3, role: "ink", kind: "rule" });
|
|
439
|
+
} else if (id === "side-rail") {
|
|
440
|
+
// A bar in the left margin: the full page height in the rail colour where the pack fills its
|
|
441
|
+
// rail, else as tall as the title zone in the accent.
|
|
442
|
+
const filled = ctx.decoration.has("rail-fill");
|
|
443
|
+
const w = Math.round(grid.margin / 2);
|
|
444
|
+
decor.push(filled ? { x: 0, y: 0, w, h: grid.H, role: ctx.rail === "field" ? "field" : "accent", kind: "rail" }
|
|
445
|
+
: { x: 0, y: T.y, w, h: T.h, role: "accent", kind: "rail" });
|
|
446
|
+
} else {
|
|
447
|
+
const A = SG.zone(grid.canvas, "content", "aside");
|
|
448
|
+
out.numeral = { x: A.x, y: A.y, w: A.w, h: A.h, size: sizes.cover, text: String(ctx.numeral || ""), align: "right" };
|
|
412
449
|
}
|
|
413
450
|
return out;
|
|
414
451
|
}
|
|
415
452
|
|
|
416
453
|
if (id === "top-plain-large") {
|
|
417
|
-
const
|
|
418
|
-
|
|
419
|
-
out.
|
|
420
|
-
|
|
421
|
-
const h = lines <= 1 ? 54 : 102;
|
|
422
|
-
out.title = { ...box([1, 10], 36, sizes.display, lines, "display", "ink"), h: h + 8 };
|
|
423
|
-
out.body = { a: 1, b: 12, y: 36 + h + (ctx.tight ? 18 : 24), bottom: ZONE.floor };
|
|
424
|
-
return out;
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
if (id === "side-rail") {
|
|
428
|
-
const s = grid.span(1, 4);
|
|
429
|
-
const lines = fit(text, s.w, sizes.title);
|
|
430
|
-
out.fits = lines <= 4;
|
|
431
|
-
const filled = ctx.decoration.has("rail-fill");
|
|
432
|
-
const rail = filled && ctx.rail === "field" ? "field" : "surface";
|
|
433
|
-
out.title = box([1, 4], 36, sizes.title, lines, "title", rail === "field" ? "on-field" : "ink");
|
|
434
|
-
// In a rail a few words fill a line, so one word moving down can add a line the estimate does
|
|
435
|
-
// not see; the frame keeps a spare line (the text is top-aligned, so nothing moves).
|
|
436
|
-
out.title.h = Math.ceil((lines + 1) * sizes.title * 1.15);
|
|
437
|
-
const railRight = s.x + s.w + grid.gutter / 2;
|
|
438
|
-
if (filled) decor.push({ x: 0, y: 0, w: railRight, h: grid.H, role: rail, kind: "rail" });
|
|
439
|
-
else if (ctx.decoration.has("hairline-rule")) decor.push({ x: railRight, y: 36, w: 0.75, h: 450, role: "line", kind: "rule" });
|
|
440
|
-
out.body = { a: 5, b: 12, y: 36, bottom: ZONE.floor };
|
|
454
|
+
const f = frame(sizes.display, "display", "ink");
|
|
455
|
+
out.fits = f.fits && f.lines <= 2;
|
|
456
|
+
out.title = f;
|
|
457
|
+
out.body = body;
|
|
441
458
|
return out;
|
|
442
459
|
}
|
|
443
460
|
|
|
444
461
|
if (id === "statement") {
|
|
445
|
-
//
|
|
446
|
-
//
|
|
447
|
-
const
|
|
448
|
-
const
|
|
449
|
-
const heroLines = fit(text, w, sizes.hero, "display");
|
|
450
|
-
const useHero = ctx.hero && heroLines <= 3;
|
|
462
|
+
// The sentence is centred in the display title zone, at the hero step in a hero pack while it
|
|
463
|
+
// keeps to three lines there, else at the display step.
|
|
464
|
+
const D = SG.zone(grid.canvas, "display", "title");
|
|
465
|
+
const tall = (size, lines) => lines * size * 1.15 <= D.h + 0.5;
|
|
466
|
+
const heroLines = fit(text, D.w, sizes.hero, "display");
|
|
467
|
+
const useHero = ctx.hero && heroLines <= 3 && tall(sizes.hero, heroLines);
|
|
451
468
|
const size = useHero ? sizes.hero : sizes.display;
|
|
452
|
-
const lines = useHero ? heroLines : fit(text, w, sizes.display, "display");
|
|
453
|
-
out.fits = lines <= 3;
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
out.support = {
|
|
469
|
+
const lines = useHero ? heroLines : fit(text, D.w, sizes.display, "display");
|
|
470
|
+
out.fits = lines <= 3 && tall(size, lines);
|
|
471
|
+
out.title = { x: D.x, y: D.y, w: D.w, h: D.h, size, face: "display", colour: "ink", lines, lineSpacing: 1.15, valign: "middle",
|
|
472
|
+
textH: Math.ceil(lines * size * 1.15) };
|
|
473
|
+
const P = SG.zone(grid.canvas, "display", "support");
|
|
474
|
+
out.support = { x: P.x, y: P.y, w: P.w, bottom: P.y + P.h };
|
|
458
475
|
out.body = null;
|
|
459
476
|
return out;
|
|
460
477
|
}
|
|
@@ -466,37 +483,11 @@ function treatmentGeometry(id, ctx) {
|
|
|
466
483
|
// The panel is as tall as the title and its caption line (ending 24 pt under the caption at 432), so its
|
|
467
484
|
// lower part never stands empty; the sample tag in the footer zone sits on the picture, clear of its edge.
|
|
468
485
|
decor.push({ x: 0, y: 324, w: s.x + s.w + 24, h: 146, role: "field", kind: "panel", alpha: 12 });
|
|
469
|
-
out.title = {
|
|
486
|
+
out.title = { x: s.x, y: 348, w: s.w, h: 72, size: sizes.title, face: "title", colour: "on-field", lines };
|
|
470
487
|
out.image = { x: 0, y: 0, w: grid.W, h: grid.H };
|
|
471
488
|
out.body = null;
|
|
472
489
|
return out;
|
|
473
490
|
}
|
|
474
|
-
|
|
475
|
-
if (id === "kicker-numeral") {
|
|
476
|
-
const w = grid.span(3, 12).w;
|
|
477
|
-
const lines = fit(text, w, sizes.title);
|
|
478
|
-
out.fits = lines <= 1 && ctx.numeral != null;
|
|
479
|
-
const n = grid.span(1, 2);
|
|
480
|
-
out.numeral = { x: n.x, y: 36, w: n.w, h: 72, size: sizes.cover, text: String(ctx.numeral || "") };
|
|
481
|
-
out.title = { ...box([3, 12], 48, sizes.title, lines, "title", "ink"), h: 60 };
|
|
482
|
-
out.body = { a: 1, b: 12, y: ctx.tight ? 120 : 132, bottom: ZONE.floor };
|
|
483
|
-
return out;
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
if (id === "bottom-anchor") {
|
|
487
|
-
// The title's last line ends on the body floor, so a one-line title leaves no band under itself;
|
|
488
|
-
// the hairline sits 12 pt above the title and the visual's zone ends 24 pt above it.
|
|
489
|
-
const s = grid.span(1, 9);
|
|
490
|
-
const lines = fit(text, s.w, sizes.title);
|
|
491
|
-
out.fits = lines <= 2;
|
|
492
|
-
const h = Math.ceil(Math.max(1, lines) * sizes.title * 1.15) + 2;
|
|
493
|
-
const y = ZONE.floor - h;
|
|
494
|
-
out.title = { ...box([1, 9], y, sizes.title, lines, "title", "ink"), h };
|
|
495
|
-
if (ctx.decoration.has("hairline-rule")) decor.push({ x: full.x, y: y - 12, w: full.w, h: 0.75, role: "line", kind: "rule" });
|
|
496
|
-
out.side = { ...grid.span(10, 12), y, bottom: ZONE.floor };
|
|
497
|
-
out.body = { a: 1, b: 12, y: 36, bottom: y - 24 };
|
|
498
|
-
return out;
|
|
499
|
-
}
|
|
500
491
|
throw new Error(`unknown title treatment "${id}"`);
|
|
501
492
|
}
|
|
502
493
|
|
|
@@ -514,7 +505,7 @@ function treatmentApplies(id, facts, ctx) {
|
|
|
514
505
|
}
|
|
515
506
|
|
|
516
507
|
module.exports = {
|
|
517
|
-
CANVAS,
|
|
508
|
+
CANVAS, RAMPS, SCALE, ZONE, TREATMENTS, FAMILIES, VARIANTS, LEGACY_LAYOUTS,
|
|
518
509
|
densityTokens, varianceMax, makeGrid, stepGap, stepRole, clampDial,
|
|
519
510
|
textEms, lineCount, leading, textHeight, isKorean, faceWidth, balanceLines, keepLines,
|
|
520
511
|
familyIds, resolveFamily, familyAllows, pickTreatment, treatmentGeometry, treatmentApplies,
|
|
@@ -831,6 +831,7 @@ function comparisonRole(blocks) {
|
|
|
831
831
|
|
|
832
832
|
/** The ordered content of a pack slide, captions bound to the visual before them. */
|
|
833
833
|
// Families whose geometry is a chart: a table of numbers there is drawn as one.
|
|
834
|
+
const DISPLAY_FAMILIES = new Set(["statement", "quote", "closing-statement"]);
|
|
834
835
|
const CHART_FAMILIES = new Set(["chart-insight", "full-chart", "kpi-over-chart", "dashboard-grid"]);
|
|
835
836
|
const NUMBER_CELL = /^[+\-−±▲▼△▽]?\s*[\d.,]+\s*(?:%p?|배|x|pt|bp|[가-힣]{1,3}|[A-Za-z]{1,3})?$/u;
|
|
836
837
|
|
|
@@ -998,7 +999,7 @@ function resolvePack(ast, templateObj) {
|
|
|
998
999
|
const numbering = { figure: 0, table: 0, FIGURE, TABLE };
|
|
999
1000
|
const facts = deckFacts(ast);
|
|
1000
1001
|
const families = pack["layout-families"] || [];
|
|
1001
|
-
const wide = { title: grid.faceWidth(pack.faces.title), display: grid.faceWidth(pack.faces.display) };
|
|
1002
|
+
const wide = { title: (t) => grid.faceWidth(pack.faces.title, t), display: (t) => grid.faceWidth(pack.faces.display, t) };
|
|
1002
1003
|
let part = 0;
|
|
1003
1004
|
|
|
1004
1005
|
const slides = ast.slides.map((slide) => {
|
|
@@ -1046,23 +1047,13 @@ function resolvePack(ast, templateObj) {
|
|
|
1046
1047
|
} else if (!families.includes(family)) {
|
|
1047
1048
|
notes.push(`slide ${n}: ${family} is not a ${pack.id} layout family (${families.join(", ")}); drawn with its own geometry`);
|
|
1048
1049
|
}
|
|
1049
|
-
let titleOnly = null;
|
|
1050
|
-
if (family === "statement" && !pack.treatments.includes("statement")) {
|
|
1051
|
-
// A pack without a statement title sets the sentence as a top title, the largest it has.
|
|
1052
|
-
titleOnly = ["top-plain-large", "band", "top-rule"].find((t) => pack.treatments.includes(t));
|
|
1053
|
-
if (!titleOnly) throw new Error(`Slide ${n}: ${pack.id} has no statement or top title to set a statement slide with; choose another tonality`);
|
|
1054
|
-
notes.push(`slide ${n}: ${pack.id} has no statement title, so the sentence is drawn as a ${titleOnly} title`);
|
|
1055
|
-
family = "text-column";
|
|
1056
|
-
role = "content";
|
|
1057
|
-
}
|
|
1058
1050
|
const items = packItems(slide.blocks, numbering, CHART_FAMILIES.has(family));
|
|
1059
1051
|
const paras = slide.blocks.filter((b) => b.type === "body").flatMap((b) => b.items || []);
|
|
1060
1052
|
// A closing is not part of a section, so it never carries the part number.
|
|
1061
1053
|
const closing = grid.VARIANTS.closing.includes(family);
|
|
1062
1054
|
// An agenda numbers its own rows: a count beside its title reads as a stray section number.
|
|
1063
1055
|
const numeral = family === "agenda" ? null : part > 0 && !closing ? part : null;
|
|
1064
|
-
const
|
|
1065
|
-
const ctx = { grid: pack.grid, sizes, title: plain(title), hero: pack.hero, decoration, numeral, rail: pack.rail, wide, statementCols, tight: Boolean((pack.tok || {}).tight) };
|
|
1056
|
+
const ctx = { grid: pack.grid, sizes, title: plain(title), hero: pack.hero, decoration, numeral, rail: pack.rail, wide, tight: Boolean((pack.tok || {}).tight) };
|
|
1066
1057
|
const facts1 = slideFacts(slide.blocks);
|
|
1067
1058
|
// A quote under a statement title says the quote; the source line becomes the support line.
|
|
1068
1059
|
let statementText = null;
|
|
@@ -1080,8 +1071,11 @@ function resolvePack(ast, templateObj) {
|
|
|
1080
1071
|
};
|
|
1081
1072
|
let allow = grid.familyAllows(family);
|
|
1082
1073
|
let treatment;
|
|
1083
|
-
|
|
1084
|
-
|
|
1074
|
+
// A statement, a quote and a closing statement sit in the display zone in every pack (the shared
|
|
1075
|
+
// slide grid): the statement title is theirs whether or not the pack lists it among its treatments.
|
|
1076
|
+
const display = DISPLAY_FAMILIES.has(family) && !meta.title && applicable("statement") === true;
|
|
1077
|
+
if (display) {
|
|
1078
|
+
treatment = "statement";
|
|
1085
1079
|
} else if (!families.includes(family) && !meta.title && !pack.treatments.some((t) => allow.includes(t) && applicable(t) === true)) {
|
|
1086
1080
|
// A family from outside the pack that takes none of its titles gets the pack's title for its role.
|
|
1087
1081
|
allow = [pack["role-defaults"][role] || pack.treatments[0], ...grid.familyAllows("text-column")];
|
|
@@ -1093,7 +1087,7 @@ function resolvePack(ast, templateObj) {
|
|
|
1093
1087
|
applicable, onNote: (note) => notes.push(note),
|
|
1094
1088
|
});
|
|
1095
1089
|
}
|
|
1096
|
-
const candidates = meta.title ||
|
|
1090
|
+
const candidates = meta.title || display ? [treatment] : [treatment, ...pack.treatments.filter((t) =>
|
|
1097
1091
|
t !== treatment && allow.includes(t) && !["statement", "overlay"].includes(t) && applicable(t) === true)];
|
|
1098
1092
|
return {
|
|
1099
1093
|
...base,
|