@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.
Files changed (114) hide show
  1. package/.grok/hooks/auto-handoff-gate.mjs +15 -2
  2. package/.grok/rules/00-litgrok.md +1 -1
  3. package/.grok/skills/frontend-ui-ux/THIRD-PARTY-NOTICE.txt +0 -5
  4. package/.grok/skills/frontend-ui-ux/references/slop-register.md +4 -4
  5. package/.grok/skills/frontend-ui-ux/scripts/import-design-intelligence.mjs +1 -1
  6. package/.grok/skills/lit-docx/SKILL.md +59 -11
  7. package/.grok/skills/lit-docx/examples/01-report-ko.md +137 -0
  8. package/.grok/skills/lit-docx/examples/02-brief-ko.md +82 -0
  9. package/.grok/skills/lit-docx/examples/03-manual-ko.md +118 -0
  10. package/.grok/skills/lit-docx/examples/04-proposal-ko.md +92 -0
  11. package/.grok/skills/lit-docx/examples/05-memo-en.md +42 -0
  12. package/.grok/skills/lit-docx/examples/06-journal-en.md +90 -0
  13. package/.grok/skills/lit-docx/examples/07-report-en.md +103 -0
  14. package/.grok/skills/lit-docx/examples/08-proposal-en.md +90 -0
  15. package/.grok/skills/lit-docx/examples/09-memo-ko.md +41 -0
  16. package/.grok/skills/lit-docx/references/components.md +151 -0
  17. package/.grok/skills/lit-docx/references/direction-step.md +129 -0
  18. package/.grok/skills/lit-docx/references/page-composition.md +129 -0
  19. package/.grok/skills/lit-docx/references/tonalities/brief.md +98 -0
  20. package/.grok/skills/lit-docx/references/tonalities/journal.md +100 -0
  21. package/.grok/skills/lit-docx/references/tonalities/manual.md +107 -0
  22. package/.grok/skills/lit-docx/references/tonalities/memo.md +95 -0
  23. package/.grok/skills/lit-docx/references/tonalities/proposal.md +105 -0
  24. package/.grok/skills/lit-docx/references/tonalities/report.md +114 -0
  25. package/.grok/skills/lit-docx/scripts/convert_md_to_docx.py +394 -51
  26. package/.grok/skills/lit-docx/scripts/docx_design.py +2446 -0
  27. package/.grok/skills/lit-docx/scripts/docx_gate.py +203 -0
  28. package/.grok/skills/lit-docx/scripts/docx_layout.py +959 -0
  29. package/.grok/skills/lit-docx/scripts/run.mjs +3 -2
  30. package/.grok/skills/lit-docx/scripts/slop_lint.py +63 -17
  31. package/.grok/skills/lit-docx/templates/tonalities/brief.yaml +29 -0
  32. package/.grok/skills/lit-docx/templates/tonalities/journal.yaml +26 -0
  33. package/.grok/skills/lit-docx/templates/tonalities/manual.yaml +27 -0
  34. package/.grok/skills/lit-docx/templates/tonalities/memo.yaml +27 -0
  35. package/.grok/skills/lit-docx/templates/tonalities/proposal.yaml +27 -0
  36. package/.grok/skills/lit-docx/templates/tonalities/report.yaml +27 -0
  37. package/.grok/skills/lit-pptx/NOTICE.md +1 -1
  38. package/.grok/skills/lit-pptx/SKILL.md +70 -14
  39. package/.grok/skills/lit-pptx/agents/analyst.md +1 -1
  40. package/.grok/skills/lit-pptx/agents/thesis.md +2 -2
  41. package/.grok/skills/lit-pptx/examples/01-pitch-signal-ko.md +175 -0
  42. package/.grok/skills/lit-pptx/examples/02-business-review-ledger-ko.md +199 -0
  43. package/.grok/skills/lit-pptx/examples/03-research-talk-paper-en.md +177 -0
  44. package/.grok/skills/lit-pptx/examples/04-lecture-chalk-ko.md +176 -0
  45. package/.grok/skills/lit-pptx/examples/05-data-review-night-en.md +221 -0
  46. package/.grok/skills/lit-pptx/examples/06-image-led-atlas-en.md +143 -0
  47. package/.grok/skills/lit-pptx/examples/07-briefing-gazette-ko.md +192 -0
  48. package/.grok/skills/lit-pptx/examples/08-status-update-ledger-en.md +168 -0
  49. package/.grok/skills/lit-pptx/examples/09-pitch-studio-en.md +157 -0
  50. package/.grok/skills/lit-pptx/examples/10-image-led-studio-ko.md +175 -0
  51. package/.grok/skills/lit-pptx/examples/11-business-review-night-en.md +181 -0
  52. package/.grok/skills/lit-pptx/examples/12-status-update-gazette-ko.md +199 -0
  53. package/.grok/skills/lit-pptx/pretendard-font/public/static/Pretendard-Bold.otf +0 -0
  54. package/.grok/skills/lit-pptx/pretendard-font/public/static/Pretendard-Regular.otf +0 -0
  55. package/.grok/skills/lit-pptx/references/density-and-fill.md +155 -0
  56. package/.grok/skills/lit-pptx/references/direction-step.md +211 -0
  57. package/.grok/skills/lit-pptx/references/layout-families.md +193 -0
  58. package/.grok/skills/lit-pptx/references/title-treatments.md +134 -0
  59. package/.grok/skills/lit-pptx/references/tonalities/atlas.md +124 -0
  60. package/.grok/skills/lit-pptx/references/tonalities/chalk.md +135 -0
  61. package/.grok/skills/lit-pptx/references/tonalities/gazette.md +127 -0
  62. package/.grok/skills/lit-pptx/references/tonalities/ledger.md +134 -0
  63. package/.grok/skills/lit-pptx/references/tonalities/night.md +132 -0
  64. package/.grok/skills/lit-pptx/references/tonalities/paper.md +127 -0
  65. package/.grok/skills/lit-pptx/references/tonalities/signal.md +118 -0
  66. package/.grok/skills/lit-pptx/references/tonalities/studio.md +123 -0
  67. package/.grok/skills/lit-pptx/scripts/compile-deck.js +65 -17
  68. package/.grok/skills/lit-pptx/scripts/craft_extras.py +82 -18
  69. package/.grok/skills/lit-pptx/scripts/deck_output.py +598 -0
  70. package/.grok/skills/lit-pptx/scripts/embed_fonts.py +1 -1
  71. package/.grok/skills/lit-pptx/scripts/inventory.py +6 -2
  72. package/.grok/skills/lit-pptx/scripts/lib/directive-parser.js +2 -2
  73. package/.grok/skills/lit-pptx/scripts/lib/grid-resolver.js +521 -0
  74. package/.grok/skills/lit-pptx/scripts/lib/layout-resolver.js +401 -16
  75. package/.grok/skills/lit-pptx/scripts/lib/markdown-loader.js +6 -4
  76. package/.grok/skills/lit-pptx/scripts/lib/render-adapter-html.js +2 -2
  77. package/.grok/skills/lit-pptx/scripts/lib/render-adapter-pptx.js +500 -126
  78. package/.grok/skills/lit-pptx/scripts/lib/render-pack.js +3558 -0
  79. package/.grok/skills/lit-pptx/scripts/lib/slide-ast.js +54 -6
  80. package/.grok/skills/lit-pptx/scripts/lib/template-registry.js +335 -11
  81. package/.grok/skills/lit-pptx/scripts/qa_deck.py +43 -10
  82. package/.grok/skills/lit-pptx/scripts/run.mjs +3 -2
  83. package/.grok/skills/lit-pptx/scripts/validate_pptx.py +17 -5
  84. package/.grok/skills/lit-pptx/templates/boilerplate_professional.css +6 -6
  85. package/.grok/skills/lit-pptx/templates/enrolled/AZURE-A2Z/layout-mapping.yaml +1 -1
  86. package/.grok/skills/lit-pptx/templates/enrolled/AZURE-A2Z/template.yaml +4 -1
  87. package/.grok/skills/lit-pptx/templates/enrolled/AZURE-PRO/layout-mapping.yaml +1 -1
  88. package/.grok/skills/lit-pptx/templates/enrolled/AZURE-PRO/template.yaml +4 -1
  89. package/.grok/skills/lit-pptx/templates/tonalities/atlas/pack.yaml +99 -0
  90. package/.grok/skills/lit-pptx/templates/tonalities/chalk/pack.yaml +104 -0
  91. package/.grok/skills/lit-pptx/templates/tonalities/gazette/pack.yaml +99 -0
  92. package/.grok/skills/lit-pptx/templates/tonalities/ledger/pack.yaml +100 -0
  93. package/.grok/skills/lit-pptx/templates/tonalities/night/pack.yaml +100 -0
  94. package/.grok/skills/lit-pptx/templates/tonalities/paper/pack.yaml +105 -0
  95. package/.grok/skills/lit-pptx/templates/tonalities/signal/pack.yaml +101 -0
  96. package/.grok/skills/lit-pptx/templates/tonalities/studio/pack.yaml +99 -0
  97. package/.grok/skills/lit-typographic-motion/THIRD_PARTY_NOTICES +1 -1
  98. package/.grok/skills/lit-typographic-motion/fonts/pins.json +6 -6
  99. package/.grok/skills/lit-typographic-motion/references/runtime.md +1 -1
  100. package/.grok/skills/lit-typographic-motion/references/style-bible.md +2 -2
  101. package/.grok/skills/lit-typographic-motion/references/type-craft.md +2 -2
  102. package/.grok/skills/lit-typographic-motion/scripts/lib/gate.mjs +1 -1
  103. package/.grok/skills/litgrok/SKILL.md +1 -1
  104. package/.grok-plugin/plugin.json +1 -1
  105. package/CHANGELOG.md +11 -0
  106. package/README.md +9 -9
  107. package/README_ko-KR.md +9 -9
  108. package/docs/assets/readme/badge-version.svg +1 -1
  109. package/docs/reference.md +1 -1
  110. package/docs/reference_ko-KR.md +1 -1
  111. package/package.json +1 -1
  112. package/plugin.json +1 -1
  113. package/.grok/skills/lit-pptx/pretendard-font/public/static/PretendardGOV-Bold.otf +0 -0
  114. 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
- if not 10.5 < pt < 30:
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
- capacity = max(1, shape.width / EMU * 72 / (pt * .55))
99
- lines = max(content.count("\n") + 1, math.ceil(len(content) / capacity))
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 = len(content) / lines
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
- region = sorted((_box(s)[1], _box(s)[1] + _box(s)[3]) for s in shapes if s is not title and (getattr(s, "has_table", False) or getattr(s, "has_text_frame", False) and s.text.strip()) and _box(s)[1] >= top and _box(s)[1] < bottom)
168
- if region and bottom > top:
169
- rows = []
170
- for start, end in region:
171
- if rows and abs(start - rows[-1][0]) <= .08:
172
- rows[-1][1] = min(rows[-1][1], end)
173
- else:
174
- rows.append([start, end])
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 rows:
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))