@litfamily/litgrok 1.0.13 → 1.0.15
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/.grok/hooks/auto-handoff-gate.mjs +15 -2
- package/.grok/rules/00-litgrok.md +1 -1
- package/.grok/skills/frontend-ui-ux/THIRD-PARTY-NOTICE.txt +0 -5
- package/.grok/skills/frontend-ui-ux/references/slop-register.md +4 -4
- package/.grok/skills/frontend-ui-ux/scripts/import-design-intelligence.mjs +1 -1
- package/.grok/skills/lit-docx/SKILL.md +59 -11
- package/.grok/skills/lit-docx/examples/01-report-ko.md +137 -0
- package/.grok/skills/lit-docx/examples/02-brief-ko.md +82 -0
- package/.grok/skills/lit-docx/examples/03-manual-ko.md +118 -0
- package/.grok/skills/lit-docx/examples/04-proposal-ko.md +92 -0
- package/.grok/skills/lit-docx/examples/05-memo-en.md +42 -0
- package/.grok/skills/lit-docx/examples/06-journal-en.md +90 -0
- package/.grok/skills/lit-docx/examples/07-report-en.md +103 -0
- package/.grok/skills/lit-docx/examples/08-proposal-en.md +90 -0
- package/.grok/skills/lit-docx/examples/09-memo-ko.md +41 -0
- package/.grok/skills/lit-docx/references/components.md +151 -0
- package/.grok/skills/lit-docx/references/direction-step.md +129 -0
- package/.grok/skills/lit-docx/references/page-composition.md +129 -0
- package/.grok/skills/lit-docx/references/tonalities/brief.md +98 -0
- package/.grok/skills/lit-docx/references/tonalities/journal.md +100 -0
- package/.grok/skills/lit-docx/references/tonalities/manual.md +107 -0
- package/.grok/skills/lit-docx/references/tonalities/memo.md +95 -0
- package/.grok/skills/lit-docx/references/tonalities/proposal.md +105 -0
- package/.grok/skills/lit-docx/references/tonalities/report.md +114 -0
- package/.grok/skills/lit-docx/scripts/convert_md_to_docx.py +394 -51
- package/.grok/skills/lit-docx/scripts/docx_design.py +2446 -0
- package/.grok/skills/lit-docx/scripts/docx_gate.py +203 -0
- package/.grok/skills/lit-docx/scripts/docx_layout.py +959 -0
- package/.grok/skills/lit-docx/scripts/run.mjs +3 -2
- package/.grok/skills/lit-docx/scripts/slop_lint.py +63 -17
- package/.grok/skills/lit-docx/templates/tonalities/brief.yaml +29 -0
- package/.grok/skills/lit-docx/templates/tonalities/journal.yaml +26 -0
- package/.grok/skills/lit-docx/templates/tonalities/manual.yaml +27 -0
- package/.grok/skills/lit-docx/templates/tonalities/memo.yaml +27 -0
- package/.grok/skills/lit-docx/templates/tonalities/proposal.yaml +27 -0
- package/.grok/skills/lit-docx/templates/tonalities/report.yaml +27 -0
- package/.grok/skills/lit-pptx/NOTICE.md +1 -1
- package/.grok/skills/lit-pptx/SKILL.md +70 -14
- package/.grok/skills/lit-pptx/agents/analyst.md +1 -1
- package/.grok/skills/lit-pptx/agents/thesis.md +2 -2
- package/.grok/skills/lit-pptx/examples/01-pitch-signal-ko.md +175 -0
- package/.grok/skills/lit-pptx/examples/02-business-review-ledger-ko.md +199 -0
- package/.grok/skills/lit-pptx/examples/03-research-talk-paper-en.md +177 -0
- package/.grok/skills/lit-pptx/examples/04-lecture-chalk-ko.md +176 -0
- package/.grok/skills/lit-pptx/examples/05-data-review-night-en.md +221 -0
- package/.grok/skills/lit-pptx/examples/06-image-led-atlas-en.md +143 -0
- package/.grok/skills/lit-pptx/examples/07-briefing-gazette-ko.md +192 -0
- package/.grok/skills/lit-pptx/examples/08-status-update-ledger-en.md +168 -0
- package/.grok/skills/lit-pptx/examples/09-pitch-studio-en.md +157 -0
- package/.grok/skills/lit-pptx/examples/10-image-led-studio-ko.md +175 -0
- package/.grok/skills/lit-pptx/examples/11-business-review-night-en.md +181 -0
- package/.grok/skills/lit-pptx/examples/12-status-update-gazette-ko.md +199 -0
- package/.grok/skills/lit-pptx/pretendard-font/public/static/Pretendard-Bold.otf +0 -0
- package/.grok/skills/lit-pptx/pretendard-font/public/static/Pretendard-Regular.otf +0 -0
- package/.grok/skills/lit-pptx/references/density-and-fill.md +155 -0
- package/.grok/skills/lit-pptx/references/direction-step.md +211 -0
- package/.grok/skills/lit-pptx/references/layout-families.md +193 -0
- package/.grok/skills/lit-pptx/references/title-treatments.md +134 -0
- package/.grok/skills/lit-pptx/references/tonalities/atlas.md +124 -0
- package/.grok/skills/lit-pptx/references/tonalities/chalk.md +135 -0
- package/.grok/skills/lit-pptx/references/tonalities/gazette.md +127 -0
- package/.grok/skills/lit-pptx/references/tonalities/ledger.md +134 -0
- package/.grok/skills/lit-pptx/references/tonalities/night.md +132 -0
- package/.grok/skills/lit-pptx/references/tonalities/paper.md +127 -0
- package/.grok/skills/lit-pptx/references/tonalities/signal.md +118 -0
- package/.grok/skills/lit-pptx/references/tonalities/studio.md +123 -0
- package/.grok/skills/lit-pptx/scripts/compile-deck.js +65 -17
- package/.grok/skills/lit-pptx/scripts/craft_extras.py +82 -18
- package/.grok/skills/lit-pptx/scripts/deck_output.py +598 -0
- package/.grok/skills/lit-pptx/scripts/embed_fonts.py +1 -1
- package/.grok/skills/lit-pptx/scripts/inventory.py +6 -2
- package/.grok/skills/lit-pptx/scripts/lib/directive-parser.js +2 -2
- package/.grok/skills/lit-pptx/scripts/lib/grid-resolver.js +521 -0
- package/.grok/skills/lit-pptx/scripts/lib/layout-resolver.js +401 -16
- package/.grok/skills/lit-pptx/scripts/lib/markdown-loader.js +6 -4
- package/.grok/skills/lit-pptx/scripts/lib/render-adapter-html.js +2 -2
- package/.grok/skills/lit-pptx/scripts/lib/render-adapter-pptx.js +500 -126
- package/.grok/skills/lit-pptx/scripts/lib/render-pack.js +3558 -0
- package/.grok/skills/lit-pptx/scripts/lib/slide-ast.js +54 -6
- package/.grok/skills/lit-pptx/scripts/lib/template-registry.js +335 -11
- package/.grok/skills/lit-pptx/scripts/qa_deck.py +43 -10
- package/.grok/skills/lit-pptx/scripts/run.mjs +3 -2
- package/.grok/skills/lit-pptx/scripts/validate_pptx.py +17 -5
- package/.grok/skills/lit-pptx/templates/boilerplate_professional.css +6 -6
- package/.grok/skills/lit-pptx/templates/enrolled/AZURE-A2Z/layout-mapping.yaml +1 -1
- package/.grok/skills/lit-pptx/templates/enrolled/AZURE-A2Z/template.yaml +4 -1
- package/.grok/skills/lit-pptx/templates/enrolled/AZURE-PRO/layout-mapping.yaml +1 -1
- package/.grok/skills/lit-pptx/templates/enrolled/AZURE-PRO/template.yaml +4 -1
- package/.grok/skills/lit-pptx/templates/tonalities/atlas/pack.yaml +99 -0
- package/.grok/skills/lit-pptx/templates/tonalities/chalk/pack.yaml +104 -0
- package/.grok/skills/lit-pptx/templates/tonalities/gazette/pack.yaml +99 -0
- package/.grok/skills/lit-pptx/templates/tonalities/ledger/pack.yaml +100 -0
- package/.grok/skills/lit-pptx/templates/tonalities/night/pack.yaml +100 -0
- package/.grok/skills/lit-pptx/templates/tonalities/paper/pack.yaml +105 -0
- package/.grok/skills/lit-pptx/templates/tonalities/signal/pack.yaml +101 -0
- package/.grok/skills/lit-pptx/templates/tonalities/studio/pack.yaml +99 -0
- package/.grok/skills/lit-typographic-motion/THIRD_PARTY_NOTICES +1 -1
- package/.grok/skills/lit-typographic-motion/fonts/pins.json +6 -6
- package/.grok/skills/lit-typographic-motion/references/runtime.md +1 -1
- package/.grok/skills/lit-typographic-motion/references/style-bible.md +2 -2
- package/.grok/skills/lit-typographic-motion/references/type-craft.md +2 -2
- package/.grok/skills/lit-typographic-motion/scripts/lib/gate.mjs +1 -1
- package/.grok/skills/litgrok/SKILL.md +1 -1
- package/.grok-plugin/plugin.json +1 -1
- package/CHANGELOG.md +11 -0
- package/README.md +9 -9
- package/README_ko-KR.md +9 -9
- package/docs/assets/readme/badge-version.svg +1 -1
- package/docs/reference.md +1 -1
- package/docs/reference_ko-KR.md +1 -1
- package/package.json +1 -1
- package/plugin.json +1 -1
- package/.grok/skills/lit-pptx/pretendard-font/public/static/PretendardGOV-Bold.otf +0 -0
- package/.grok/skills/lit-pptx/pretendard-font/public/static/PretendardGOV-Regular.otf +0 -0
|
@@ -14,10 +14,47 @@ LIMITS = {
|
|
|
14
14
|
"accent_light_max": .93, "hue_band": 20, "latin_chars": 90,
|
|
15
15
|
"cjk_chars": 38, "narrow_chars": 10, "group_ratio": 2,
|
|
16
16
|
"symmetric_inset": .06, "radius_tolerance": .02,
|
|
17
|
-
"empty_high": .35, "empty_medium": .25,
|
|
17
|
+
"empty_high": .35, "empty_medium": .25, "rule": .03,
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
|
|
21
|
+
# Advance widths of the bundled Pretendard faces in em (the wider of Regular and Bold per class),
|
|
22
|
+
# so a measure or a wrap estimate follows the face the deck is set in.
|
|
23
|
+
EM = {"hangul": .87, "upper": .67, "lower": .54, "digit": .62, "space": .25, "punct": .41}
|
|
24
|
+
# Slides that hold a statement rather than a body: their space is part of the design.
|
|
25
|
+
DISPLAY_FAMILIES = re.compile(r"family@(?:cover|section|statement|quote|closing-statement)")
|
|
26
|
+
DISPLAY_TITLES = {"title@statement", "title@cover", "title@section"}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def text_em(text):
|
|
30
|
+
"""Width of a run of text in em of the bundled face."""
|
|
31
|
+
total = 0.0
|
|
32
|
+
for c in text:
|
|
33
|
+
if "\uac00" <= c <= "\ud7af" or "\u3130" <= c <= "\u318f" or "\u4e00" <= c <= "\u9fff":
|
|
34
|
+
total += EM["hangul"]
|
|
35
|
+
elif c.isspace():
|
|
36
|
+
total += EM["space"]
|
|
37
|
+
elif c.isdigit():
|
|
38
|
+
total += EM["digit"]
|
|
39
|
+
elif c.isupper():
|
|
40
|
+
total += EM["upper"]
|
|
41
|
+
elif c.isalpha():
|
|
42
|
+
total += EM["lower"]
|
|
43
|
+
else:
|
|
44
|
+
total += EM["punct"]
|
|
45
|
+
return total
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def named_title(slide):
|
|
49
|
+
"""The frame the deck engine names as the slide title (`title@<treatment>`), if any."""
|
|
50
|
+
return next((s for s in slide.shapes if s.name.startswith("title@") and getattr(s, "has_text_frame", False)), None)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def display_slide(slide):
|
|
54
|
+
"""A cover, section, statement or quote slide drawn by the deck engine."""
|
|
55
|
+
return any(DISPLAY_FAMILIES.match(s.name) or s.name in DISPLAY_TITLES for s in slide.shapes)
|
|
56
|
+
|
|
57
|
+
|
|
21
58
|
def _box(shape):
|
|
22
59
|
return tuple(float(getattr(shape, key)) / EMU for key in ("left", "top", "width", "height"))
|
|
23
60
|
|
|
@@ -76,6 +113,8 @@ def assess(prs):
|
|
|
76
113
|
box = _box(shape)
|
|
77
114
|
if box[2] * box[3] >= LIMITS["full_bleed"] * W * H:
|
|
78
115
|
continue
|
|
116
|
+
if shape.name.startswith("lit-notice") or min(box[2], box[3]) < LIMITS["rule"]:
|
|
117
|
+
continue
|
|
79
118
|
hue = _hue(shape)
|
|
80
119
|
if hue is not None and not any(min(abs(hue - old), 360 - abs(hue - old)) <= LIMITS["hue_band"] for old in hue_families):
|
|
81
120
|
hue_families.append(hue)
|
|
@@ -86,21 +125,29 @@ def assess(prs):
|
|
|
86
125
|
add("OF-101", "HIGH" if count >= high else "MEDIUM", number, count, {"medium": medium, "high": high})
|
|
87
126
|
|
|
88
127
|
text_shapes = [s for s in shapes if getattr(s, "has_text_frame", False) and s.text.strip()]
|
|
89
|
-
title = min(text_shapes, key=lambda s: _box(s)[1]) if text_shapes else None
|
|
128
|
+
title = named_title(slide) or (min(text_shapes, key=lambda s: _box(s)[1]) if text_shapes else None)
|
|
129
|
+
# A cover or section page the engine names is a display page: its preview lines keep their own measure
|
|
130
|
+
# (two lines an opened slide, within 70 % of the page), so the body measure does not apply there.
|
|
131
|
+
family = next((s.name.split("@", 1)[1] for s in shapes if s.name.startswith("family@")), "")
|
|
90
132
|
for shape in text_shapes:
|
|
91
|
-
if shape is title:
|
|
133
|
+
if shape is title or re.match(r"(cover|section)(-|$)", family):
|
|
92
134
|
continue
|
|
93
135
|
sizes = [r.font.size.pt for p in shape.text_frame.paragraphs for r in p.runs if r.font.size]
|
|
94
136
|
pt = max(sizes) if sizes else 18
|
|
95
|
-
|
|
137
|
+
# Body text only: captions and table notes at 11 pt run as wide as the visual they label.
|
|
138
|
+
if not 11 < pt < 30:
|
|
96
139
|
continue
|
|
97
140
|
content = shape.text.strip()
|
|
98
|
-
|
|
99
|
-
|
|
141
|
+
frame = max(1, shape.width / EMU * 72)
|
|
142
|
+
# Each paragraph or explicit break is a line of its own that may wrap again in the frame.
|
|
143
|
+
segments = [seg.strip() for seg in re.split(r"[\n\v]", content) if seg.strip()]
|
|
144
|
+
wrapped = [(seg, max(1, math.ceil(text_em(seg) * pt / frame))) for seg in segments]
|
|
145
|
+
lines = sum(n for _, n in wrapped)
|
|
100
146
|
if lines < 2:
|
|
101
147
|
continue
|
|
102
|
-
cjk = sum("\uac00" <= c <= "\ud7af" for c in content) >= .5 * len(content)
|
|
103
|
-
measure
|
|
148
|
+
cjk = sum("\uac00" <= c <= "\ud7af" for c in content) >= .5 * len(content.replace(" ", ""))
|
|
149
|
+
# A Korean measure counts glyphs, so the spaces between 어절 are not counted.
|
|
150
|
+
measure = max(len(seg.replace(" ", "") if cjk else seg) / n for seg, n in wrapped)
|
|
104
151
|
ceiling = LIMITS["cjk_chars"] if cjk else LIMITS["latin_chars"]
|
|
105
152
|
if measure > ceiling:
|
|
106
153
|
add("OF-102", "HIGH", number, round(measure, 1), ceiling, "derived", shape.name)
|
|
@@ -161,20 +208,37 @@ def assess(prs):
|
|
|
161
208
|
if any(0x1F000 <= ord(c) <= 0x1FAFF or 0x2600 <= ord(c) <= 0x27BF for c in char):
|
|
162
209
|
add("OF-108", "HIGH", number, char, "no emoji bullet")
|
|
163
210
|
|
|
164
|
-
if not display and number > 1 and text_shapes:
|
|
211
|
+
if not display and not display_slide(slide) and number > 1 and text_shapes:
|
|
165
212
|
title_bottom = _box(title)[1] + _box(title)[3] if title else H * .18
|
|
166
213
|
top, bottom = title_bottom + .1, H - .55
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
214
|
+
|
|
215
|
+
def content(s):
|
|
216
|
+
return (getattr(s, "has_table", False) or getattr(s, "has_chart", False) or s.shape_type == MSO_SHAPE_TYPE.PICTURE
|
|
217
|
+
or getattr(s, "has_text_frame", False) and s.text.strip())
|
|
218
|
+
|
|
219
|
+
# A title on the body floor closes the page, so the body is the zone above it. A side title's body
|
|
220
|
+
# is the zone beside its rail from the title's top; what stands in the rail under it is the rail's.
|
|
221
|
+
rail = set()
|
|
222
|
+
named = title is not None and title.name.startswith("title@")
|
|
223
|
+
if named and _box(title)[1] > H * .5:
|
|
224
|
+
top, bottom = .5, _box(title)[1] - .1
|
|
225
|
+
elif named and _box(title)[0] <= W * .1 and _box(title)[2] <= W * .35:
|
|
226
|
+
edge = _box(title)[0] + _box(title)[2]
|
|
227
|
+
others = [s for s in shapes if s is not title and not s.name.startswith("lit-notice") and content(s) and _box(s)[1] < bottom]
|
|
228
|
+
under = [s for s in others if _box(s)[0] + _box(s)[2] <= edge + .05 and _box(s)[1] >= title_bottom - .05]
|
|
229
|
+
if any(_box(s)[0] >= edge - .05 for s in others) and all(s in under or _box(s)[0] >= edge - .05 for s in others):
|
|
230
|
+
top, rail = _box(title)[1], {id(s) for s in under}
|
|
231
|
+
|
|
232
|
+
# The empty band is a height at which nothing on the slide holds content: blocks are clipped to
|
|
233
|
+
# the body and joined, so a short label beside a tall chart, a column that starts beside a side
|
|
234
|
+
# title, or a picture behind the body all count for the height they cover.
|
|
235
|
+
spans = sorted((max(top, _box(s)[1]), min(bottom, _box(s)[1] + _box(s)[3])) for s in shapes
|
|
236
|
+
if s is not title and id(s) not in rail and not s.name.startswith("lit-notice") and content(s)
|
|
237
|
+
and _box(s)[1] < bottom and _box(s)[1] + _box(s)[3] > top)
|
|
238
|
+
if spans and bottom > top:
|
|
175
239
|
cursor = top
|
|
176
240
|
gaps = []
|
|
177
|
-
for start, end in
|
|
241
|
+
for start, end in spans:
|
|
178
242
|
gaps.append(max(0, start - cursor))
|
|
179
243
|
cursor = max(cursor, end)
|
|
180
244
|
gaps.append(max(0, bottom - cursor))
|